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>
This commit is contained in:
Christoph Hellwig 2014-09-26 16:02:50 +02:00 committed by Trond Myklebust
parent 8c393f9a72
commit e0d4ed71ca
2 changed files with 10 additions and 5 deletions

View File

@ -65,17 +65,18 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
mutex_lock(&nn->bl_mutex);
bl_pipe_msg.bl_wq = &nn->bl_wq; bl_pipe_msg.bl_wq = &nn->bl_wq;
b->simple.len += 4; /* single volume */ b->simple.len += 4; /* single volume */
if (b->simple.len > PAGE_SIZE) if (b->simple.len > PAGE_SIZE)
return -EIO; goto out_unlock;
memset(msg, 0, sizeof(*msg)); memset(msg, 0, sizeof(*msg));
msg->len = sizeof(*bl_msg) + b->simple.len; msg->len = sizeof(*bl_msg) + b->simple.len;
msg->data = kzalloc(msg->len, gfp_mask); msg->data = kzalloc(msg->len, gfp_mask);
if (!msg->data) if (!msg->data)
goto out; goto out_free_data;
bl_msg = msg->data; bl_msg = msg->data;
bl_msg->type = BL_DEVICE_MOUNT, bl_msg->type = BL_DEVICE_MOUNT,
@ -87,7 +88,7 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
rc = rpc_queue_upcall(nn->bl_device_pipe, msg); rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
if (rc < 0) { if (rc < 0) {
remove_wait_queue(&nn->bl_wq, &wq); remove_wait_queue(&nn->bl_wq, &wq);
goto out; goto out_free_data;
} }
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
@ -97,12 +98,14 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
if (reply->status != BL_DEVICE_REQUEST_PROC) { if (reply->status != BL_DEVICE_REQUEST_PROC) {
printk(KERN_WARNING "%s failed to decode device: %d\n", printk(KERN_WARNING "%s failed to decode device: %d\n",
__func__, reply->status); __func__, reply->status);
goto out; goto out_free_data;
} }
dev = MKDEV(reply->major, reply->minor); dev = MKDEV(reply->major, reply->minor);
out: out_free_data:
kfree(msg->data); kfree(msg->data);
out_unlock:
mutex_unlock(&nn->bl_mutex);
return dev; return dev;
} }
@ -232,6 +235,7 @@ static int nfs4blocklayout_net_init(struct net *net)
struct nfs_net *nn = net_generic(net, nfs_net_id); struct nfs_net *nn = net_generic(net, nfs_net_id);
struct dentry *dentry; struct dentry *dentry;
mutex_init(&nn->bl_mutex);
init_waitqueue_head(&nn->bl_wq); init_waitqueue_head(&nn->bl_wq);
nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
if (IS_ERR(nn->bl_device_pipe)) if (IS_ERR(nn->bl_device_pipe))

View File

@ -19,6 +19,7 @@ struct nfs_net {
struct rpc_pipe *bl_device_pipe; struct rpc_pipe *bl_device_pipe;
struct bl_dev_msg bl_mount_reply; struct bl_dev_msg bl_mount_reply;
wait_queue_head_t bl_wq; wait_queue_head_t bl_wq;
struct mutex bl_mutex;
struct list_head nfs_client_list; struct list_head nfs_client_list;
struct list_head nfs_volume_list; struct list_head nfs_volume_list;
#if IS_ENABLED(CONFIG_NFS_V4) #if IS_ENABLED(CONFIG_NFS_V4)