aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2014-09-26 10:02:50 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-11-12 14:22:52 -0500
commite0d4ed71ca0344494722a041780f004d2bcf0f11 (patch)
treece776cb83bd3cefa8ace5bb529d1ec0480079022
parent8c393f9a721c30a030049a680e1bf896669bb279 (diff)
pnfs/blocklayout: serialize GETDEVICEINFO calls
The rpc_pipefs code isn't thread safe, leading to occasional use after frees when running xfstests generic/241 (dbench). Signed-off-by: Christoph Hellwig <hch@lst.de> Link: http://lkml.kernel.org/r/1411740170-18611-2-git-send-email-hch@lst.de Cc: stable@vger.kernel.org # 3.17.x Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r--fs/nfs/blocklayout/rpc_pipefs.c14
-rw-r--r--fs/nfs/netns.h1
2 files changed, 10 insertions, 5 deletions
diff --git a/fs/nfs/blocklayout/rpc_pipefs.c b/fs/nfs/blocklayout/rpc_pipefs.c
index e966c023b1b7..acbf9ca4018c 100644
--- a/fs/nfs/blocklayout/rpc_pipefs.c
+++ b/fs/nfs/blocklayout/rpc_pipefs.c
@@ -65,17 +65,18 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
65 65
66 dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); 66 dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
67 67
68 mutex_lock(&nn->bl_mutex);
68 bl_pipe_msg.bl_wq = &nn->bl_wq; 69 bl_pipe_msg.bl_wq = &nn->bl_wq;
69 70
70 b->simple.len += 4; /* single volume */ 71 b->simple.len += 4; /* single volume */
71 if (b->simple.len > PAGE_SIZE) 72 if (b->simple.len > PAGE_SIZE)
72 return -EIO; 73 goto out_unlock;
73 74
74 memset(msg, 0, sizeof(*msg)); 75 memset(msg, 0, sizeof(*msg));
75 msg->len = sizeof(*bl_msg) + b->simple.len; 76 msg->len = sizeof(*bl_msg) + b->simple.len;
76 msg->data = kzalloc(msg->len, gfp_mask); 77 msg->data = kzalloc(msg->len, gfp_mask);
77 if (!msg->data) 78 if (!msg->data)
78 goto out; 79 goto out_free_data;
79 80
80 bl_msg = msg->data; 81 bl_msg = msg->data;
81 bl_msg->type = BL_DEVICE_MOUNT, 82 bl_msg->type = BL_DEVICE_MOUNT,
@@ -87,7 +88,7 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
87 rc = rpc_queue_upcall(nn->bl_device_pipe, msg); 88 rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
88 if (rc < 0) { 89 if (rc < 0) {
89 remove_wait_queue(&nn->bl_wq, &wq); 90 remove_wait_queue(&nn->bl_wq, &wq);
90 goto out; 91 goto out_free_data;
91 } 92 }
92 93
93 set_current_state(TASK_UNINTERRUPTIBLE); 94 set_current_state(TASK_UNINTERRUPTIBLE);
@@ -97,12 +98,14 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
97 if (reply->status != BL_DEVICE_REQUEST_PROC) { 98 if (reply->status != BL_DEVICE_REQUEST_PROC) {
98 printk(KERN_WARNING "%s failed to decode device: %d\n", 99 printk(KERN_WARNING "%s failed to decode device: %d\n",
99 __func__, reply->status); 100 __func__, reply->status);
100 goto out; 101 goto out_free_data;
101 } 102 }
102 103
103 dev = MKDEV(reply->major, reply->minor); 104 dev = MKDEV(reply->major, reply->minor);
104out: 105out_free_data:
105 kfree(msg->data); 106 kfree(msg->data);
107out_unlock:
108 mutex_unlock(&nn->bl_mutex);
106 return dev; 109 return dev;
107} 110}
108 111
@@ -232,6 +235,7 @@ static int nfs4blocklayout_net_init(struct net *net)
232 struct nfs_net *nn = net_generic(net, nfs_net_id); 235 struct nfs_net *nn = net_generic(net, nfs_net_id);
233 struct dentry *dentry; 236 struct dentry *dentry;
234 237
238 mutex_init(&nn->bl_mutex);
235 init_waitqueue_head(&nn->bl_wq); 239 init_waitqueue_head(&nn->bl_wq);
236 nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); 240 nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
237 if (IS_ERR(nn->bl_device_pipe)) 241 if (IS_ERR(nn->bl_device_pipe))
diff --git a/fs/nfs/netns.h b/fs/nfs/netns.h
index ef221fb8a183..f0e06e4acbef 100644
--- a/fs/nfs/netns.h
+++ b/fs/nfs/netns.h
@@ -19,6 +19,7 @@ struct nfs_net {
19 struct rpc_pipe *bl_device_pipe; 19 struct rpc_pipe *bl_device_pipe;
20 struct bl_dev_msg bl_mount_reply; 20 struct bl_dev_msg bl_mount_reply;
21 wait_queue_head_t bl_wq; 21 wait_queue_head_t bl_wq;
22 struct mutex bl_mutex;
22 struct list_head nfs_client_list; 23 struct list_head nfs_client_list;
23 struct list_head nfs_volume_list; 24 struct list_head nfs_volume_list;
24#if IS_ENABLED(CONFIG_NFS_V4) 25#if IS_ENABLED(CONFIG_NFS_V4)