From 1b340d0118da1d7c60c664f17d7c8fce2bb1cd9d Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Fri, 25 Nov 2011 17:13:04 +0300 Subject: NFS: DNS resolver cache per network namespace context introduced This patch implements DNS resolver cache creation and registration for each alive network namespace context. This was done by registering NFS per-net operations, responsible for DNS cache allocation/register and unregister/destructioning instead of initialization and destruction of static "nfs_dns_resolve" cache detail (this one was removed). Pointer to network dns resolver cache is stored in new per-net "nfs_net" structure. This patch also changes nfs_dns_resolve_name() function prototype (and it's calls) by adding network pointer parameter, which is used to get proper DNS resolver cache pointer for do_cache_lookup_wait() call. Note: empty nfs_dns_resolver_init() and nfs_dns_resolver_destroy() functions will be used in next patch in the series. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/netns.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 fs/nfs/netns.h (limited to 'fs/nfs/netns.h') diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h new file mode 100644 index 00000000000..8c1f130d6ca --- /dev/null +++ b/fs/nfs/netns.h @@ -0,0 +1,13 @@ +#ifndef __NFS_NETNS_H__ +#define __NFS_NETNS_H__ + +#include +#include + +struct nfs_net { + struct cache_detail *nfs_dns_resolve; +}; + +extern int nfs_net_id; + +#endif -- cgit v1.2.3-70-g09d2 From 9e2e74dba6ddce94da187369b50a27536147d5df Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Tue, 10 Jan 2012 17:04:24 +0400 Subject: NFS: blocklayout pipe creation per network namespace context introduced This patch implements blocklayout pipe creation and registration per each existent network namespace. This was achived by registering NFS per-net operations, responsible for blocklayout pipe allocation/register and unregister/destruction instead of initialization and destruction of static "bl_device_pipe" pipe (this one was removed). Note, than pointer to network blocklayout pipe is stored in per-net "nfs_net" structure, because allocating of one more per-net structure for blocklayout module looks redundant. This patch also changes dev_remove() function prototype (and all it's callers, where it' requied) by adding network namespace pointer parameter, which is used to discover proper blocklayout pipe for rpc_queue_upcall() call. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/blocklayout/blocklayout.c | 54 ++++++++++++++++++++++++------------- fs/nfs/blocklayout/blocklayout.h | 3 ++- fs/nfs/blocklayout/blocklayoutdev.c | 5 +++- fs/nfs/blocklayout/blocklayoutdm.c | 7 ++--- fs/nfs/inode.c | 1 + fs/nfs/netns.h | 1 + 6 files changed, 47 insertions(+), 24 deletions(-) (limited to 'fs/nfs/netns.h') diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 80b0c4a4048..9da72b8a554 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -46,7 +46,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Andy Adamson "); MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver"); -struct rpc_pipe *bl_device_pipe; wait_queue_head_t bl_wq; static void print_page(struct page *page) @@ -1071,6 +1070,37 @@ static void nfs4blocklayout_unregister_net(struct net *net, } } +static int nfs4blocklayout_net_init(struct net *net) +{ + struct nfs_net *nn = net_generic(net, nfs_net_id); + struct dentry *dentry; + + nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); + if (IS_ERR(nn->bl_device_pipe)) + return PTR_ERR(nn->bl_device_pipe); + dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe); + if (IS_ERR(dentry)) { + rpc_destroy_pipe_data(nn->bl_device_pipe); + return PTR_ERR(dentry); + } + nn->bl_device_pipe->dentry = dentry; + return 0; +} + +static void nfs4blocklayout_net_exit(struct net *net) +{ + struct nfs_net *nn = net_generic(net, nfs_net_id); + + nfs4blocklayout_unregister_net(net, nn->bl_device_pipe); + rpc_destroy_pipe_data(nn->bl_device_pipe); + nn->bl_device_pipe = NULL; +} + +static struct pernet_operations nfs4blocklayout_net_ops = { + .init = nfs4blocklayout_net_init, + .exit = nfs4blocklayout_net_exit, +}; + static int __init nfs4blocklayout_init(void) { struct vfsmount *mnt; @@ -1089,24 +1119,12 @@ static int __init nfs4blocklayout_init(void) ret = PTR_ERR(mnt); goto out_remove; } - bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); - if (IS_ERR(bl_device_pipe)) { - ret = PTR_ERR(bl_device_pipe); - goto out_putrpc; - } - bl_device_pipe->dentry = nfs4blocklayout_register_net(&init_net, - bl_device_pipe); - if (IS_ERR(bl_device_pipe->dentry)) { - ret = PTR_ERR(bl_device_pipe->dentry); - goto out_destroy_pipe; - } + ret = register_pernet_subsys(&nfs4blocklayout_net_ops); + if (ret) + goto out_remove; out: return ret; -out_destroy_pipe: - rpc_destroy_pipe_data(bl_device_pipe); -out_putrpc: - rpc_put_mount(); out_remove: pnfs_unregister_layoutdriver(&blocklayout_type); return ret; @@ -1117,10 +1135,8 @@ static void __exit nfs4blocklayout_exit(void) dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n", __func__); + unregister_pernet_subsys(&nfs4blocklayout_net_ops); pnfs_unregister_layoutdriver(&blocklayout_type); - nfs4blocklayout_unregister_net(&init_net, bl_device_pipe); - rpc_destroy_pipe_data(bl_device_pipe); - rpc_put_mount(); } MODULE_ALIAS("nfs-layouttype4-3"); diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h index 49c670b18a9..0966b39bbcf 100644 --- a/fs/nfs/blocklayout/blocklayout.h +++ b/fs/nfs/blocklayout/blocklayout.h @@ -37,6 +37,7 @@ #include #include "../pnfs.h" +#include "../netns.h" #define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT) #define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT) @@ -50,6 +51,7 @@ struct pnfs_block_dev { struct list_head bm_node; struct nfs4_deviceid bm_mdevid; /* associated devid */ struct block_device *bm_mdev; /* meta device itself */ + struct net *net; }; enum exstate4 { @@ -161,7 +163,6 @@ struct bl_msg_hdr { u16 totallen; /* length of entire message, including hdr itself */ }; -extern struct rpc_pipe *bl_device_pipe; extern wait_queue_head_t bl_wq; #define BL_DEVICE_UMOUNT 0x0 /* Umount--delete devices */ diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c index 949b6247879..94ed978860c 100644 --- a/fs/nfs/blocklayout/blocklayoutdev.c +++ b/fs/nfs/blocklayout/blocklayoutdev.c @@ -120,6 +120,8 @@ nfs4_blk_decode_device(struct nfs_server *server, DECLARE_WAITQUEUE(wq, current); struct bl_dev_msg *reply = &bl_mount_reply; int offset, len, i, rc; + struct net *net = server->nfs_client->net; + struct nfs_net *nn = net_generic(net, nfs_net_id); dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data, @@ -146,7 +148,7 @@ nfs4_blk_decode_device(struct nfs_server *server, dprintk("%s CALLING USERSPACE DAEMON\n", __func__); add_wait_queue(&bl_wq, &wq); - rc = rpc_queue_upcall(bl_device_pipe, &msg); + rc = rpc_queue_upcall(nn->bl_device_pipe, &msg); if (rc < 0) { remove_wait_queue(&bl_wq, &wq); rv = ERR_PTR(rc); @@ -181,6 +183,7 @@ nfs4_blk_decode_device(struct nfs_server *server, rv->bm_mdev = bd; memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid)); + rv->net = net; dprintk("%s Created device %s with bd_block_size %u\n", __func__, bd->bd_disk->disk_name, diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c index 631f254d12a..970490f556d 100644 --- a/fs/nfs/blocklayout/blocklayoutdm.c +++ b/fs/nfs/blocklayout/blocklayoutdm.c @@ -38,7 +38,7 @@ #define NFSDBG_FACILITY NFSDBG_PNFS_LD -static void dev_remove(dev_t dev) +static void dev_remove(struct net *net, dev_t dev) { struct rpc_pipe_msg msg; struct bl_dev_msg bl_umount_request; @@ -48,6 +48,7 @@ static void dev_remove(dev_t dev) }; uint8_t *dataptr; DECLARE_WAITQUEUE(wq, current); + struct nfs_net *nn = net_generic(net, nfs_net_id); dprintk("Entering %s\n", __func__); @@ -66,7 +67,7 @@ static void dev_remove(dev_t dev) msg.len = sizeof(bl_msg) + bl_msg.totallen; add_wait_queue(&bl_wq, &wq); - if (rpc_queue_upcall(bl_device_pipe, &msg) < 0) { + if (rpc_queue_upcall(nn->bl_device_pipe, &msg) < 0) { remove_wait_queue(&bl_wq, &wq); goto out; } @@ -93,7 +94,7 @@ static void nfs4_blk_metadev_release(struct pnfs_block_dev *bdev) printk(KERN_ERR "%s nfs4_blkdev_put returns %d\n", __func__, rv); - dev_remove(bdev->bm_mdev->bd_dev); + dev_remove(bdev->net, bdev->bm_mdev->bd_dev); } void bl_free_block_dev(struct pnfs_block_dev *bdev) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 0335f6e4ff7..577ad5a72a2 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1554,6 +1554,7 @@ static void nfsiod_stop(void) } int nfs_net_id; +EXPORT_SYMBOL_GPL(nfs_net_id); static int nfs_net_init(struct net *net) { diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h index 8c1f130d6ca..39ae4cad5b4 100644 --- a/fs/nfs/netns.h +++ b/fs/nfs/netns.h @@ -6,6 +6,7 @@ struct nfs_net { struct cache_detail *nfs_dns_resolve; + struct rpc_pipe *bl_device_pipe; }; extern int nfs_net_id; -- cgit v1.2.3-70-g09d2 From 6b13168b36b6a7f603d962c232f1f2f325705832 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 23 Jan 2012 17:26:05 +0000 Subject: NFS: make nfs_client_list per net ns This patch splits global list of NFS clients into per-net-ns array of lists. This looks more strict and clearer. BTW, this patch also makes "/proc/fs/nfsfs/servers" entry content depends on /proc mount owner pid namespace. See below for details. NOTE: few words about how was /proc/fs/nfsfs/ entries content show per network namespace done. This is a little bit tricky and not the best is could be. But it's cheap (proper fix for /proc conteinerization is a hard nut to crack). The idea is simple: take proper network namespace from pid namespace child reaper nsproxy of /proc/ mount creator. This actually means, that if there are 2 containers with different net namespace sharing pid namespace, then read of /proc/fs/nfsfs/ entries will always return content, taken from net namespace of pid namespace creator task (and thus second namespace set wil be unvisible). Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 38 +++++++++++++++++++++++++++----------- fs/nfs/idmap.c | 5 ++--- fs/nfs/inode.c | 1 + fs/nfs/internal.h | 2 +- fs/nfs/netns.h | 1 + 5 files changed, 32 insertions(+), 15 deletions(-) (limited to 'fs/nfs/netns.h') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 98af1cb28ee..058eb9bcfa9 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include @@ -49,11 +51,11 @@ #include "internal.h" #include "fscache.h" #include "pnfs.h" +#include "netns.h" #define NFSDBG_FACILITY NFSDBG_CLIENT DEFINE_SPINLOCK(nfs_client_lock); -LIST_HEAD(nfs_client_list); static LIST_HEAD(nfs_volume_list); static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); #ifdef CONFIG_NFS_V4 @@ -464,8 +466,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat { struct nfs_client *clp; const struct sockaddr *sap = data->addr; + struct nfs_net *nn = net_generic(data->net, nfs_net_id); - list_for_each_entry(clp, &nfs_client_list, cl_share_link) { + list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; /* Don't match clients that failed to initialise properly */ if (clp->cl_cons_state < 0) @@ -483,9 +486,6 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat /* Match the full socket address */ if (!nfs_sockaddr_cmp(sap, clap)) continue; - /* Match network namespace */ - if (clp->net != data->net) - continue; atomic_inc(&clp->cl_count); return clp; @@ -506,6 +506,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, { struct nfs_client *clp, *new = NULL; int error; + struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id); dprintk("--> nfs_get_client(%s,v%u)\n", cl_init->hostname ?: "", cl_init->rpc_ops->version); @@ -531,7 +532,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, /* install a new client and return with it unready */ install_client: clp = new; - list_add(&clp->cl_share_link, &nfs_client_list); + list_add(&clp->cl_share_link, &nn->nfs_client_list); spin_unlock(&nfs_client_lock); error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr, @@ -1227,9 +1228,10 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, struct nfs4_sessionid *sid) { struct nfs_client *clp; + struct nfs_net *nn = net_generic(&init_net, nfs_net_id); spin_lock(&nfs_client_lock); - list_for_each_entry(clp, &nfs_client_list, cl_share_link) { + list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { if (nfs4_cb_match_client(addr, clp, 1) == false) continue; @@ -1757,6 +1759,13 @@ out_free_server: return ERR_PTR(error); } +void nfs_clients_init(struct net *net) +{ + struct nfs_net *nn = net_generic(net, nfs_net_id); + + INIT_LIST_HEAD(&nn->nfs_client_list); +} + #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_fs_nfs; @@ -1810,13 +1819,15 @@ static int nfs_server_list_open(struct inode *inode, struct file *file) { struct seq_file *m; int ret; + struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info; + struct net *net = pid_ns->child_reaper->nsproxy->net_ns; ret = seq_open(file, &nfs_server_list_ops); if (ret < 0) return ret; m = file->private_data; - m->private = PDE(inode)->data; + m->private = net; return 0; } @@ -1826,9 +1837,11 @@ static int nfs_server_list_open(struct inode *inode, struct file *file) */ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) { + struct nfs_net *nn = net_generic(m->private, nfs_net_id); + /* lock the list against modification */ spin_lock(&nfs_client_lock); - return seq_list_start_head(&nfs_client_list, *_pos); + return seq_list_start_head(&nn->nfs_client_list, *_pos); } /* @@ -1836,7 +1849,9 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) */ static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) { - return seq_list_next(v, &nfs_client_list, pos); + struct nfs_net *nn = net_generic(p->private, nfs_net_id); + + return seq_list_next(v, &nn->nfs_client_list, pos); } /* @@ -1853,9 +1868,10 @@ static void nfs_server_list_stop(struct seq_file *p, void *v) static int nfs_server_list_show(struct seq_file *m, void *v) { struct nfs_client *clp; + struct nfs_net *nn = net_generic(m->private, nfs_net_id); /* display header on line 1 */ - if (v == &nfs_client_list) { + if (v == &nn->nfs_client_list) { seq_puts(m, "NV SERVER PORT USE HOSTNAME\n"); return 0; } diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 83f7d42d5c7..2f78f0ce266 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -532,13 +532,12 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr) { struct super_block *sb = ptr; + struct nfs_net *nn = net_generic(sb->s_fs_info, nfs_net_id); struct nfs_client *clp; int error = 0; spin_lock(&nfs_client_lock); - list_for_each_entry(clp, &nfs_client_list, cl_share_link) { - if (clp->net != sb->s_fs_info) - continue; + list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { if (clp->rpc_ops != &nfs_v4_clientops) continue; error = __rpc_pipefs_event(clp, event, sb); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 028464bcbe0..0365b84cc2c 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1558,6 +1558,7 @@ EXPORT_SYMBOL_GPL(nfs_net_id); static int nfs_net_init(struct net *net) { + nfs_clients_init(net); return nfs_dns_resolver_cache_init(net); } diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index cdb121d3c6f..a9ae8069fff 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -146,6 +146,7 @@ extern void nfs_umount(const struct nfs_mount_request *info); /* client.c */ extern const struct rpc_program nfs_program; +extern void nfs_clients_init(struct net *net); extern void nfs_cleanup_cb_ident_idr(void); extern void nfs_put_client(struct nfs_client *); @@ -183,7 +184,6 @@ static inline void nfs_fs_proc_exit(void) #endif #ifdef CONFIG_NFS_V4 extern spinlock_t nfs_client_lock; -extern struct list_head nfs_client_list; #endif /* nfs4namespace.c */ diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h index 39ae4cad5b4..feb33c3f9a5 100644 --- a/fs/nfs/netns.h +++ b/fs/nfs/netns.h @@ -7,6 +7,7 @@ struct nfs_net { struct cache_detail *nfs_dns_resolve; struct rpc_pipe *bl_device_pipe; + struct list_head nfs_client_list; }; extern int nfs_net_id; -- cgit v1.2.3-70-g09d2 From c25d32b26361ce0814fef2281f164866c18c8692 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 23 Jan 2012 17:26:14 +0000 Subject: NFS: make nfs_volume_list per net ns This patch splits global list of NFS servers into per-net-ns array of lists. This looks more strict and clearer. BTW, this patch also makes "/proc/fs/nfsfs/volumes" content depends on /proc mount owner pid namespace. See below for details. NOTE: few words about how was /proc/fs/nfsfs/ entries content show per network namespace done. This is a little bit tricky and not the best is could be. But it's cheap (proper fix for /proc conteinerization is a hard nut to crack). The idea is simple: take proper network namespace from pid namespace child reaper nsproxy of /proc/ mount creator. This actually means, that if there are 2 containers with different net namespace sharing pid namespace, then read of /proc/fs/nfsfs/ entries will always return content, taken from net namespace of pid namespace creator task (and thus second namespace set wil be unvisible). Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 20 ++++++++++++++------ fs/nfs/netns.h | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) (limited to 'fs/nfs/netns.h') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 058eb9bcfa9..d58e8386e6b 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -56,7 +56,6 @@ #define NFSDBG_FACILITY NFSDBG_CLIENT DEFINE_SPINLOCK(nfs_client_lock); -static LIST_HEAD(nfs_volume_list); static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); #ifdef CONFIG_NFS_V4 static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */ @@ -1036,10 +1035,11 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve static void nfs_server_insert_lists(struct nfs_server *server) { struct nfs_client *clp = server->nfs_client; + struct nfs_net *nn = net_generic(clp->net, nfs_net_id); spin_lock(&nfs_client_lock); list_add_tail_rcu(&server->client_link, &clp->cl_superblocks); - list_add_tail(&server->master_link, &nfs_volume_list); + list_add_tail(&server->master_link, &nn->nfs_volume_list); clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); spin_unlock(&nfs_client_lock); @@ -1764,6 +1764,7 @@ void nfs_clients_init(struct net *net) struct nfs_net *nn = net_generic(net, nfs_net_id); INIT_LIST_HEAD(&nn->nfs_client_list); + INIT_LIST_HEAD(&nn->nfs_volume_list); } #ifdef CONFIG_PROC_FS @@ -1900,13 +1901,15 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file) { struct seq_file *m; int ret; + struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info; + struct net *net = pid_ns->child_reaper->nsproxy->net_ns; ret = seq_open(file, &nfs_volume_list_ops); if (ret < 0) return ret; m = file->private_data; - m->private = PDE(inode)->data; + m->private = net; return 0; } @@ -1916,9 +1919,11 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file) */ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) { + struct nfs_net *nn = net_generic(m->private, nfs_net_id); + /* lock the list against modification */ spin_lock(&nfs_client_lock); - return seq_list_start_head(&nfs_volume_list, *_pos); + return seq_list_start_head(&nn->nfs_volume_list, *_pos); } /* @@ -1926,7 +1931,9 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) */ static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) { - return seq_list_next(v, &nfs_volume_list, pos); + struct nfs_net *nn = net_generic(p->private, nfs_net_id); + + return seq_list_next(v, &nn->nfs_volume_list, pos); } /* @@ -1945,9 +1952,10 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) struct nfs_server *server; struct nfs_client *clp; char dev[8], fsid[17]; + struct nfs_net *nn = net_generic(m->private, nfs_net_id); /* display header on line 1 */ - if (v == &nfs_volume_list) { + if (v == &nn->nfs_volume_list) { seq_puts(m, "NV SERVER PORT DEV FSID FSC\n"); return 0; } diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h index feb33c3f9a5..0fbd4e017d2 100644 --- a/fs/nfs/netns.h +++ b/fs/nfs/netns.h @@ -8,6 +8,7 @@ struct nfs_net { struct cache_detail *nfs_dns_resolve; struct rpc_pipe *bl_device_pipe; struct list_head nfs_client_list; + struct list_head nfs_volume_list; }; extern int nfs_net_id; -- cgit v1.2.3-70-g09d2 From 28cd1b3f262dba56b5e335ba668e342d530f6129 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 23 Jan 2012 17:26:22 +0000 Subject: NFS: make cb_ident_idr per net ns This patch makes ID's infrastructure network namespace aware. This was done mainly because of nfs_client_lock, which is desired to be per network namespace, but protects NFS clients ID's. NOTE: NFS client's net pointer have to be set prior to ID initialization, proper assignment was moved. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/callback_xdr.c | 2 +- fs/nfs/client.c | 28 ++++++++++++++++++---------- fs/nfs/inode.c | 2 +- fs/nfs/internal.h | 4 ++-- fs/nfs/netns.h | 3 +++ 5 files changed, 25 insertions(+), 14 deletions(-) (limited to 'fs/nfs/netns.h') diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 2f45aa71742..e14af46bd2c 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -876,7 +876,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r return rpc_garbage_args; if (hdr_arg.minorversion == 0) { - cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident); + cps.clp = nfs4_find_client_ident(rqstp->rq_xprt->xpt_net, hdr_arg.cb_ident); if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) return rpc_drop_reply; } diff --git a/fs/nfs/client.c b/fs/nfs/client.c index d58e8386e6b..f51b2795ce0 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -58,7 +58,6 @@ DEFINE_SPINLOCK(nfs_client_lock); static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); #ifdef CONFIG_NFS_V4 -static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */ /* * Get a unique NFSv4.0 callback identifier which will be used @@ -67,14 +66,15 @@ static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) { int ret = 0; + struct nfs_net *nn = net_generic(clp->net, nfs_net_id); if (clp->rpc_ops->version != 4 || minorversion != 0) return ret; retry: - if (!idr_pre_get(&cb_ident_idr, GFP_KERNEL)) + if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL)) return -ENOMEM; spin_lock(&nfs_client_lock); - ret = idr_get_new(&cb_ident_idr, clp, &clp->cl_cb_ident); + ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident); spin_unlock(&nfs_client_lock); if (ret == -EAGAIN) goto retry; @@ -173,6 +173,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ clp->cl_rpcclient = ERR_PTR(-EINVAL); clp->cl_proto = cl_init->proto; + clp->net = cl_init->net; #ifdef CONFIG_NFS_V4 err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); @@ -191,7 +192,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ if (!IS_ERR(cred)) clp->cl_machine_cred = cred; nfs_fscache_get_client_cookie(clp); - clp->net = cl_init->net; return clp; @@ -236,16 +236,20 @@ static void nfs4_shutdown_client(struct nfs_client *clp) } /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ -void nfs_cleanup_cb_ident_idr(void) +void nfs_cleanup_cb_ident_idr(struct net *net) { - idr_destroy(&cb_ident_idr); + struct nfs_net *nn = net_generic(net, nfs_net_id); + + idr_destroy(&nn->cb_ident_idr); } /* nfs_client_lock held */ static void nfs_cb_idr_remove_locked(struct nfs_client *clp) { + struct nfs_net *nn = net_generic(clp->net, nfs_net_id); + if (clp->cl_cb_ident) - idr_remove(&cb_ident_idr, clp->cl_cb_ident); + idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident); } static void pnfs_init_server(struct nfs_server *server) @@ -263,7 +267,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp) { } -void nfs_cleanup_cb_ident_idr(void) +void nfs_cleanup_cb_ident_idr(struct net *net) { } @@ -1203,12 +1207,13 @@ error: * Find a client by callback identifier */ struct nfs_client * -nfs4_find_client_ident(int cb_ident) +nfs4_find_client_ident(struct net *net, int cb_ident) { struct nfs_client *clp; + struct nfs_net *nn = net_generic(net, nfs_net_id); spin_lock(&nfs_client_lock); - clp = idr_find(&cb_ident_idr, cb_ident); + clp = idr_find(&nn->cb_ident_idr, cb_ident); if (clp) atomic_inc(&clp->cl_count); spin_unlock(&nfs_client_lock); @@ -1765,6 +1770,9 @@ void nfs_clients_init(struct net *net) INIT_LIST_HEAD(&nn->nfs_client_list); INIT_LIST_HEAD(&nn->nfs_volume_list); +#ifdef CONFIG_NFS_V4 + idr_init(&nn->cb_ident_idr); +#endif } #ifdef CONFIG_PROC_FS diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 0365b84cc2c..6c662598f88 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1565,6 +1565,7 @@ static int nfs_net_init(struct net *net) static void nfs_net_exit(struct net *net) { nfs_dns_resolver_cache_destroy(net); + nfs_cleanup_cb_ident_idr(net); } static struct pernet_operations nfs_net_ops = { @@ -1674,7 +1675,6 @@ static void __exit exit_nfs_fs(void) #ifdef CONFIG_PROC_FS rpc_proc_unregister(&init_net, "nfs"); #endif - nfs_cleanup_cb_ident_idr(); unregister_nfs_fs(); nfs_fs_proc_exit(); nfsiod_stop(); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index a9ae8069fff..958fff2927c 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -148,9 +148,9 @@ extern void nfs_umount(const struct nfs_mount_request *info); extern const struct rpc_program nfs_program; extern void nfs_clients_init(struct net *net); -extern void nfs_cleanup_cb_ident_idr(void); +extern void nfs_cleanup_cb_ident_idr(struct net *); extern void nfs_put_client(struct nfs_client *); -extern struct nfs_client *nfs4_find_client_ident(int); +extern struct nfs_client *nfs4_find_client_ident(struct net *, int); extern struct nfs_client * nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *); extern struct nfs_server *nfs_create_server( diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h index 0fbd4e017d2..547cc9525ba 100644 --- a/fs/nfs/netns.h +++ b/fs/nfs/netns.h @@ -9,6 +9,9 @@ struct nfs_net { struct rpc_pipe *bl_device_pipe; struct list_head nfs_client_list; struct list_head nfs_volume_list; +#ifdef CONFIG_NFS_V4 + struct idr cb_ident_idr; /* Protected by nfs_client_lock */ +#endif }; extern int nfs_net_id; -- cgit v1.2.3-70-g09d2 From dc03085834a4530b2514708a643cd3fe38f35b21 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Mon, 23 Jan 2012 17:26:31 +0000 Subject: NFS: make nfs_client_lock per net ns This patch makes nfs_clients_lock allocated per network namespace. All items it protects are already network namespace aware. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/client.c | 51 +++++++++++++++++++++++++++++---------------------- fs/nfs/idmap.c | 4 ++-- fs/nfs/internal.h | 3 --- fs/nfs/netns.h | 1 + 4 files changed, 32 insertions(+), 27 deletions(-) (limited to 'fs/nfs/netns.h') diff --git a/fs/nfs/client.c b/fs/nfs/client.c index f51b2795ce0..9e11d298883 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -55,7 +55,6 @@ #define NFSDBG_FACILITY NFSDBG_CLIENT -DEFINE_SPINLOCK(nfs_client_lock); static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); #ifdef CONFIG_NFS_V4 @@ -73,9 +72,9 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) retry: if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL)) return -ENOMEM; - spin_lock(&nfs_client_lock); + spin_lock(&nn->nfs_client_lock); ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident); - spin_unlock(&nfs_client_lock); + spin_unlock(&nn->nfs_client_lock); if (ret == -EAGAIN) goto retry; return ret; @@ -313,15 +312,18 @@ static void nfs_free_client(struct nfs_client *clp) */ void nfs_put_client(struct nfs_client *clp) { + struct nfs_net *nn; + if (!clp) return; dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count)); + nn = net_generic(clp->net, nfs_net_id); - if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) { + if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) { list_del(&clp->cl_share_link); nfs_cb_idr_remove_locked(clp); - spin_unlock(&nfs_client_lock); + spin_unlock(&nn->nfs_client_lock); BUG_ON(!list_empty(&clp->cl_superblocks)); @@ -516,7 +518,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, /* see if the client already exists */ do { - spin_lock(&nfs_client_lock); + spin_lock(&nn->nfs_client_lock); clp = nfs_match_client(cl_init); if (clp) @@ -524,7 +526,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, if (new) goto install_client; - spin_unlock(&nfs_client_lock); + spin_unlock(&nn->nfs_client_lock); new = nfs_alloc_client(cl_init); } while (!IS_ERR(new)); @@ -536,7 +538,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, install_client: clp = new; list_add(&clp->cl_share_link, &nn->nfs_client_list); - spin_unlock(&nfs_client_lock); + spin_unlock(&nn->nfs_client_lock); error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr, authflavour, noresvport); @@ -551,7 +553,7 @@ install_client: * - make sure it's ready before returning */ found_client: - spin_unlock(&nfs_client_lock); + spin_unlock(&nn->nfs_client_lock); if (new) nfs_free_client(new); @@ -1041,24 +1043,25 @@ static void nfs_server_insert_lists(struct nfs_server *server) struct nfs_client *clp = server->nfs_client; struct nfs_net *nn = net_generic(clp->net, nfs_net_id); - spin_lock(&nfs_client_lock); + spin_lock(&nn->nfs_client_lock); list_add_tail_rcu(&server->client_link, &clp->cl_superblocks); list_add_tail(&server->master_link, &nn->nfs_volume_list); clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); - spin_unlock(&nfs_client_lock); + spin_unlock(&nn->nfs_client_lock); } static void nfs_server_remove_lists(struct nfs_server *server) { struct nfs_client *clp = server->nfs_client; + struct nfs_net *nn = net_generic(clp->net, nfs_net_id); - spin_lock(&nfs_client_lock); + spin_lock(&nn->nfs_client_lock); list_del_rcu(&server->client_link); if (clp && list_empty(&clp->cl_superblocks)) set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); list_del(&server->master_link); - spin_unlock(&nfs_client_lock); + spin_unlock(&nn->nfs_client_lock); synchronize_rcu(); } @@ -1212,11 +1215,11 @@ nfs4_find_client_ident(struct net *net, int cb_ident) struct nfs_client *clp; struct nfs_net *nn = net_generic(net, nfs_net_id); - spin_lock(&nfs_client_lock); + spin_lock(&nn->nfs_client_lock); clp = idr_find(&nn->cb_ident_idr, cb_ident); if (clp) atomic_inc(&clp->cl_count); - spin_unlock(&nfs_client_lock); + spin_unlock(&nn->nfs_client_lock); return clp; } @@ -1235,7 +1238,7 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, struct nfs_client *clp; struct nfs_net *nn = net_generic(&init_net, nfs_net_id); - spin_lock(&nfs_client_lock); + spin_lock(&nn->nfs_client_lock); list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { if (nfs4_cb_match_client(addr, clp, 1) == false) continue; @@ -1249,10 +1252,10 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, continue; atomic_inc(&clp->cl_count); - spin_unlock(&nfs_client_lock); + spin_unlock(&nn->nfs_client_lock); return clp; } - spin_unlock(&nfs_client_lock); + spin_unlock(&nn->nfs_client_lock); return NULL; } @@ -1849,7 +1852,7 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) struct nfs_net *nn = net_generic(m->private, nfs_net_id); /* lock the list against modification */ - spin_lock(&nfs_client_lock); + spin_lock(&nn->nfs_client_lock); return seq_list_start_head(&nn->nfs_client_list, *_pos); } @@ -1868,7 +1871,9 @@ static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) */ static void nfs_server_list_stop(struct seq_file *p, void *v) { - spin_unlock(&nfs_client_lock); + struct nfs_net *nn = net_generic(p->private, nfs_net_id); + + spin_unlock(&nn->nfs_client_lock); } /* @@ -1930,7 +1935,7 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos) struct nfs_net *nn = net_generic(m->private, nfs_net_id); /* lock the list against modification */ - spin_lock(&nfs_client_lock); + spin_lock(&nn->nfs_client_lock); return seq_list_start_head(&nn->nfs_volume_list, *_pos); } @@ -1949,7 +1954,9 @@ static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos) */ static void nfs_volume_list_stop(struct seq_file *p, void *v) { - spin_unlock(&nfs_client_lock); + struct nfs_net *nn = net_generic(p->private, nfs_net_id); + + spin_unlock(&nn->nfs_client_lock); } /* diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 2f78f0ce266..d2afcd8354e 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -536,7 +536,7 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, struct nfs_client *clp; int error = 0; - spin_lock(&nfs_client_lock); + spin_lock(&nn->nfs_client_lock); list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { if (clp->rpc_ops != &nfs_v4_clientops) continue; @@ -544,7 +544,7 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, if (error) break; } - spin_unlock(&nfs_client_lock); + spin_unlock(&nn->nfs_client_lock); return error; } diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 958fff2927c..b38b73347af 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -182,9 +182,6 @@ static inline void nfs_fs_proc_exit(void) { } #endif -#ifdef CONFIG_NFS_V4 -extern spinlock_t nfs_client_lock; -#endif /* nfs4namespace.c */ #ifdef CONFIG_NFS_V4 diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h index 547cc9525ba..7baad89ae60 100644 --- a/fs/nfs/netns.h +++ b/fs/nfs/netns.h @@ -12,6 +12,7 @@ struct nfs_net { #ifdef CONFIG_NFS_V4 struct idr cb_ident_idr; /* Protected by nfs_client_lock */ #endif + spinlock_t nfs_client_lock; }; extern int nfs_net_id; -- cgit v1.2.3-70-g09d2 From cb9c1c4a880bc734c2848f8647be2cfa336ee346 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Sun, 11 Mar 2012 18:20:23 +0400 Subject: NFS: replace global bl_mount_reply with per-net one This global variable is used for blocklayout downcall and thus can be corrupted if case of existence of multiple networks namespaces. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/blocklayout/blocklayout.h | 5 ----- fs/nfs/blocklayout/blocklayoutdev.c | 9 +++++---- fs/nfs/netns.h | 6 ++++++ 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'fs/nfs/netns.h') diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h index 0966b39bbcf..58ac8614c4c 100644 --- a/fs/nfs/blocklayout/blocklayout.h +++ b/fs/nfs/blocklayout/blocklayout.h @@ -153,11 +153,6 @@ BLK_LSEG2EXT(struct pnfs_layout_segment *lseg) return BLK_LO2EXT(lseg->pls_layout); } -struct bl_dev_msg { - int32_t status; - uint32_t major, minor; -}; - struct bl_msg_hdr { u8 type; u16 totallen; /* length of entire message, including hdr itself */ diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c index b48f782a94a..1d58642b153 100644 --- a/fs/nfs/blocklayout/blocklayoutdev.c +++ b/fs/nfs/blocklayout/blocklayoutdev.c @@ -79,15 +79,16 @@ int nfs4_blkdev_put(struct block_device *bdev) return blkdev_put(bdev, FMODE_READ); } -static struct bl_dev_msg bl_mount_reply; - ssize_t bl_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) { + struct nfs_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info, + nfs_net_id); + if (mlen != sizeof (struct bl_dev_msg)) return -EINVAL; - if (copy_from_user(&bl_mount_reply, src, mlen) != 0) + if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0) return -EFAULT; wake_up(&bl_wq); @@ -118,10 +119,10 @@ nfs4_blk_decode_device(struct nfs_server *server, }; uint8_t *dataptr; DECLARE_WAITQUEUE(wq, current); - struct bl_dev_msg *reply = &bl_mount_reply; int offset, len, i, rc; struct net *net = server->nfs_client->net; struct nfs_net *nn = net_generic(net, nfs_net_id); + struct bl_dev_msg *reply = &nn->bl_mount_reply; dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data, diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h index 7baad89ae60..73425f555cd 100644 --- a/fs/nfs/netns.h +++ b/fs/nfs/netns.h @@ -4,9 +4,15 @@ #include #include +struct bl_dev_msg { + int32_t status; + uint32_t major, minor; +}; + struct nfs_net { struct cache_detail *nfs_dns_resolve; struct rpc_pipe *bl_device_pipe; + struct bl_dev_msg bl_mount_reply; struct list_head nfs_client_list; struct list_head nfs_volume_list; #ifdef CONFIG_NFS_V4 -- cgit v1.2.3-70-g09d2 From 5ffaf8554163d9f3873988ce2f9977f6c6f408d2 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsbursky Date: Sun, 11 Mar 2012 18:20:31 +0400 Subject: NFS: replace global bl_wq with per-net one This queue is used for sleeping in kernel and it have to be per-net since we don't want to wake any other waiters except in out network nemespace. BTW, move wq to per-net data is easy. But some way to handle upcall timeouts have to be provided. On message destroy in case of timeout, tasks, waiting for message to be delivered, should be awakened. Thus, some data required to located the right wait queue. Chosen solution replaces rpc_pipe_msg object with new introduced bl_pipe_msg object, containing rpc_pipe_msg and proper wq. Signed-off-by: Stanislav Kinsbursky Signed-off-by: Trond Myklebust --- fs/nfs/blocklayout/blocklayout.c | 4 +--- fs/nfs/blocklayout/blocklayout.h | 7 +++++-- fs/nfs/blocklayout/blocklayoutdev.c | 32 ++++++++++++++++++-------------- fs/nfs/blocklayout/blocklayoutdm.c | 26 ++++++++++++++------------ fs/nfs/netns.h | 1 + 5 files changed, 39 insertions(+), 31 deletions(-) (limited to 'fs/nfs/netns.h') diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 783ebd51bd5..61501346324 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -46,8 +46,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Andy Adamson "); MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver"); -wait_queue_head_t bl_wq; - static void print_page(struct page *page) { dprintk("PRINTPAGE page %p\n", page); @@ -1117,6 +1115,7 @@ static int nfs4blocklayout_net_init(struct net *net) struct nfs_net *nn = net_generic(net, nfs_net_id); struct dentry *dentry; + init_waitqueue_head(&nn->bl_wq); nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); if (IS_ERR(nn->bl_device_pipe)) return PTR_ERR(nn->bl_device_pipe); @@ -1153,7 +1152,6 @@ static int __init nfs4blocklayout_init(void) if (ret) goto out; - init_waitqueue_head(&bl_wq); ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block); if (ret) goto out_remove; diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h index 58ac8614c4c..03350690118 100644 --- a/fs/nfs/blocklayout/blocklayout.h +++ b/fs/nfs/blocklayout/blocklayout.h @@ -153,13 +153,16 @@ BLK_LSEG2EXT(struct pnfs_layout_segment *lseg) return BLK_LO2EXT(lseg->pls_layout); } +struct bl_pipe_msg { + struct rpc_pipe_msg msg; + wait_queue_head_t *bl_wq; +}; + struct bl_msg_hdr { u8 type; u16 totallen; /* length of entire message, including hdr itself */ }; -extern wait_queue_head_t bl_wq; - #define BL_DEVICE_UMOUNT 0x0 /* Umount--delete devices */ #define BL_DEVICE_MOUNT 0x1 /* Mount--create devices*/ #define BL_DEVICE_REQUEST_INIT 0x0 /* Start request */ diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c index 1d58642b153..a5c88a554d9 100644 --- a/fs/nfs/blocklayout/blocklayoutdev.c +++ b/fs/nfs/blocklayout/blocklayoutdev.c @@ -91,16 +91,18 @@ ssize_t bl_pipe_downcall(struct file *filp, const char __user *src, if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0) return -EFAULT; - wake_up(&bl_wq); + wake_up(&nn->bl_wq); return mlen; } void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg) { + struct bl_pipe_msg *bl_pipe_msg = container_of(msg, struct bl_pipe_msg, msg); + if (msg->errno >= 0) return; - wake_up(&bl_wq); + wake_up(bl_pipe_msg->bl_wq); } /* @@ -112,7 +114,8 @@ nfs4_blk_decode_device(struct nfs_server *server, { struct pnfs_block_dev *rv; struct block_device *bd = NULL; - struct rpc_pipe_msg msg; + struct bl_pipe_msg bl_pipe_msg; + struct rpc_pipe_msg *msg = &bl_pipe_msg.msg; struct bl_msg_hdr bl_msg = { .type = BL_DEVICE_MOUNT, .totallen = dev->mincount, @@ -128,15 +131,16 @@ nfs4_blk_decode_device(struct nfs_server *server, dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data, dev->mincount); - memset(&msg, 0, sizeof(msg)); - msg.data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS); - if (!msg.data) { + bl_pipe_msg.bl_wq = &nn->bl_wq; + memset(msg, 0, sizeof(*msg)); + msg->data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS); + if (!msg->data) { rv = ERR_PTR(-ENOMEM); goto out; } - memcpy(msg.data, &bl_msg, sizeof(bl_msg)); - dataptr = (uint8_t *) msg.data; + memcpy(msg->data, &bl_msg, sizeof(bl_msg)); + dataptr = (uint8_t *) msg->data; len = dev->mincount; offset = sizeof(bl_msg); for (i = 0; len > 0; i++) { @@ -145,13 +149,13 @@ nfs4_blk_decode_device(struct nfs_server *server, len -= PAGE_CACHE_SIZE; offset += PAGE_CACHE_SIZE; } - msg.len = sizeof(bl_msg) + dev->mincount; + msg->len = sizeof(bl_msg) + dev->mincount; dprintk("%s CALLING USERSPACE DAEMON\n", __func__); - add_wait_queue(&bl_wq, &wq); - rc = rpc_queue_upcall(nn->bl_device_pipe, &msg); + add_wait_queue(&nn->bl_wq, &wq); + rc = rpc_queue_upcall(nn->bl_device_pipe, msg); if (rc < 0) { - remove_wait_queue(&bl_wq, &wq); + remove_wait_queue(&nn->bl_wq, &wq); rv = ERR_PTR(rc); goto out; } @@ -159,7 +163,7 @@ nfs4_blk_decode_device(struct nfs_server *server, set_current_state(TASK_UNINTERRUPTIBLE); schedule(); __set_current_state(TASK_RUNNING); - remove_wait_queue(&bl_wq, &wq); + remove_wait_queue(&nn->bl_wq, &wq); if (reply->status != BL_DEVICE_REQUEST_PROC) { dprintk("%s failed to open device: %d\n", @@ -191,7 +195,7 @@ nfs4_blk_decode_device(struct nfs_server *server, bd->bd_block_size); out: - kfree(msg.data); + kfree(msg->data); return rv; } diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c index a0f588fa49c..30fc22af7bb 100644 --- a/fs/nfs/blocklayout/blocklayoutdm.c +++ b/fs/nfs/blocklayout/blocklayoutdm.c @@ -40,7 +40,8 @@ static void dev_remove(struct net *net, dev_t dev) { - struct rpc_pipe_msg msg; + struct bl_pipe_msg bl_pipe_msg; + struct rpc_pipe_msg *msg = &bl_pipe_msg.msg; struct bl_dev_msg bl_umount_request; struct bl_msg_hdr bl_msg = { .type = BL_DEVICE_UMOUNT, @@ -52,33 +53,34 @@ static void dev_remove(struct net *net, dev_t dev) dprintk("Entering %s\n", __func__); - memset(&msg, 0, sizeof(msg)); - msg.data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS); - if (!msg.data) + bl_pipe_msg.bl_wq = &nn->bl_wq; + memset(&msg, 0, sizeof(*msg)); + msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS); + if (!msg->data) goto out; memset(&bl_umount_request, 0, sizeof(bl_umount_request)); bl_umount_request.major = MAJOR(dev); bl_umount_request.minor = MINOR(dev); - memcpy(msg.data, &bl_msg, sizeof(bl_msg)); - dataptr = (uint8_t *) msg.data; + memcpy(msg->data, &bl_msg, sizeof(bl_msg)); + dataptr = (uint8_t *) msg->data; memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request)); - msg.len = sizeof(bl_msg) + bl_msg.totallen; + msg->len = sizeof(bl_msg) + bl_msg.totallen; - add_wait_queue(&bl_wq, &wq); - if (rpc_queue_upcall(nn->bl_device_pipe, &msg) < 0) { - remove_wait_queue(&bl_wq, &wq); + add_wait_queue(&nn->bl_wq, &wq); + if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) { + remove_wait_queue(&nn->bl_wq, &wq); goto out; } set_current_state(TASK_UNINTERRUPTIBLE); schedule(); __set_current_state(TASK_RUNNING); - remove_wait_queue(&bl_wq, &wq); + remove_wait_queue(&nn->bl_wq, &wq); out: - kfree(msg.data); + kfree(msg->data); } /* diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h index 73425f555cd..aa14ec303e9 100644 --- a/fs/nfs/netns.h +++ b/fs/nfs/netns.h @@ -13,6 +13,7 @@ struct nfs_net { struct cache_detail *nfs_dns_resolve; struct rpc_pipe *bl_device_pipe; struct bl_dev_msg bl_mount_reply; + wait_queue_head_t bl_wq; struct list_head nfs_client_list; struct list_head nfs_volume_list; #ifdef CONFIG_NFS_V4 -- cgit v1.2.3-70-g09d2