cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rpc_pipefs.c (7494B)


      1/*
      2 *  Copyright (c) 2006,2007 The Regents of the University of Michigan.
      3 *  All rights reserved.
      4 *
      5 *  Andy Adamson <andros@citi.umich.edu>
      6 *  Fred Isaman <iisaman@umich.edu>
      7 *
      8 * permission is granted to use, copy, create derivative works and
      9 * redistribute this software and such derivative works for any purpose,
     10 * so long as the name of the university of michigan is not used in
     11 * any advertising or publicity pertaining to the use or distribution
     12 * of this software without specific, written prior authorization.  if
     13 * the above copyright notice or any other identification of the
     14 * university of michigan is included in any copy of any portion of
     15 * this software, then the disclaimer below must also be included.
     16 *
     17 * this software is provided as is, without representation from the
     18 * university of michigan as to its fitness for any purpose, and without
     19 * warranty by the university of michigan of any kind, either express
     20 * or implied, including without limitation the implied warranties of
     21 * merchantability and fitness for a particular purpose.  the regents
     22 * of the university of michigan shall not be liable for any damages,
     23 * including special, indirect, incidental, or consequential damages,
     24 * with respect to any claim arising out or in connection with the use
     25 * of the software, even if it has been or is hereafter advised of the
     26 * possibility of such damages.
     27 */
     28
     29#include <linux/module.h>
     30#include <linux/blkdev.h>
     31
     32#include "blocklayout.h"
     33
     34#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
     35
     36static void
     37nfs4_encode_simple(__be32 *p, struct pnfs_block_volume *b)
     38{
     39	int i;
     40
     41	*p++ = cpu_to_be32(1);
     42	*p++ = cpu_to_be32(b->type);
     43	*p++ = cpu_to_be32(b->simple.nr_sigs);
     44	for (i = 0; i < b->simple.nr_sigs; i++) {
     45		p = xdr_encode_hyper(p, b->simple.sigs[i].offset);
     46		p = xdr_encode_opaque(p, b->simple.sigs[i].sig,
     47					 b->simple.sigs[i].sig_len);
     48	}
     49}
     50
     51dev_t
     52bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
     53		gfp_t gfp_mask)
     54{
     55	struct net *net = server->nfs_client->cl_net;
     56	struct nfs_net *nn = net_generic(net, nfs_net_id);
     57	struct bl_dev_msg *reply = &nn->bl_mount_reply;
     58	struct bl_pipe_msg bl_pipe_msg;
     59	struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
     60	struct bl_msg_hdr *bl_msg;
     61	DECLARE_WAITQUEUE(wq, current);
     62	dev_t dev = 0;
     63	int rc;
     64
     65	dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
     66
     67	mutex_lock(&nn->bl_mutex);
     68	bl_pipe_msg.bl_wq = &nn->bl_wq;
     69
     70	b->simple.len += 4;	/* single volume */
     71	if (b->simple.len > PAGE_SIZE)
     72		goto out_unlock;
     73
     74	memset(msg, 0, sizeof(*msg));
     75	msg->len = sizeof(*bl_msg) + b->simple.len;
     76	msg->data = kzalloc(msg->len, gfp_mask);
     77	if (!msg->data)
     78		goto out_free_data;
     79
     80	bl_msg = msg->data;
     81	bl_msg->type = BL_DEVICE_MOUNT;
     82	bl_msg->totallen = b->simple.len;
     83	nfs4_encode_simple(msg->data + sizeof(*bl_msg), b);
     84
     85	dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
     86	add_wait_queue(&nn->bl_wq, &wq);
     87	rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
     88	if (rc < 0) {
     89		remove_wait_queue(&nn->bl_wq, &wq);
     90		goto out_free_data;
     91	}
     92
     93	set_current_state(TASK_UNINTERRUPTIBLE);
     94	schedule();
     95	remove_wait_queue(&nn->bl_wq, &wq);
     96
     97	if (reply->status != BL_DEVICE_REQUEST_PROC) {
     98		printk(KERN_WARNING "%s failed to decode device: %d\n",
     99			__func__, reply->status);
    100		goto out_free_data;
    101	}
    102
    103	dev = MKDEV(reply->major, reply->minor);
    104out_free_data:
    105	kfree(msg->data);
    106out_unlock:
    107	mutex_unlock(&nn->bl_mutex);
    108	return dev;
    109}
    110
    111static ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
    112			 size_t mlen)
    113{
    114	struct nfs_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info,
    115					 nfs_net_id);
    116
    117	if (mlen != sizeof (struct bl_dev_msg))
    118		return -EINVAL;
    119
    120	if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0)
    121		return -EFAULT;
    122
    123	wake_up(&nn->bl_wq);
    124
    125	return mlen;
    126}
    127
    128static void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
    129{
    130	struct bl_pipe_msg *bl_pipe_msg =
    131		container_of(msg, struct bl_pipe_msg, msg);
    132
    133	if (msg->errno >= 0)
    134		return;
    135	wake_up(bl_pipe_msg->bl_wq);
    136}
    137
    138static const struct rpc_pipe_ops bl_upcall_ops = {
    139	.upcall		= rpc_pipe_generic_upcall,
    140	.downcall	= bl_pipe_downcall,
    141	.destroy_msg	= bl_pipe_destroy_msg,
    142};
    143
    144static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb,
    145					    struct rpc_pipe *pipe)
    146{
    147	struct dentry *dir, *dentry;
    148
    149	dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME);
    150	if (dir == NULL)
    151		return ERR_PTR(-ENOENT);
    152	dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe);
    153	dput(dir);
    154	return dentry;
    155}
    156
    157static void nfs4blocklayout_unregister_sb(struct super_block *sb,
    158					  struct rpc_pipe *pipe)
    159{
    160	if (pipe->dentry)
    161		rpc_unlink(pipe->dentry);
    162}
    163
    164static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
    165			   void *ptr)
    166{
    167	struct super_block *sb = ptr;
    168	struct net *net = sb->s_fs_info;
    169	struct nfs_net *nn = net_generic(net, nfs_net_id);
    170	struct dentry *dentry;
    171	int ret = 0;
    172
    173	if (!try_module_get(THIS_MODULE))
    174		return 0;
    175
    176	if (nn->bl_device_pipe == NULL) {
    177		module_put(THIS_MODULE);
    178		return 0;
    179	}
    180
    181	switch (event) {
    182	case RPC_PIPEFS_MOUNT:
    183		dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe);
    184		if (IS_ERR(dentry)) {
    185			ret = PTR_ERR(dentry);
    186			break;
    187		}
    188		nn->bl_device_pipe->dentry = dentry;
    189		break;
    190	case RPC_PIPEFS_UMOUNT:
    191		if (nn->bl_device_pipe->dentry)
    192			nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe);
    193		break;
    194	default:
    195		ret = -ENOTSUPP;
    196		break;
    197	}
    198	module_put(THIS_MODULE);
    199	return ret;
    200}
    201
    202static struct notifier_block nfs4blocklayout_block = {
    203	.notifier_call = rpc_pipefs_event,
    204};
    205
    206static struct dentry *nfs4blocklayout_register_net(struct net *net,
    207						   struct rpc_pipe *pipe)
    208{
    209	struct super_block *pipefs_sb;
    210	struct dentry *dentry;
    211
    212	pipefs_sb = rpc_get_sb_net(net);
    213	if (!pipefs_sb)
    214		return NULL;
    215	dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe);
    216	rpc_put_sb_net(net);
    217	return dentry;
    218}
    219
    220static void nfs4blocklayout_unregister_net(struct net *net,
    221					   struct rpc_pipe *pipe)
    222{
    223	struct super_block *pipefs_sb;
    224
    225	pipefs_sb = rpc_get_sb_net(net);
    226	if (pipefs_sb) {
    227		nfs4blocklayout_unregister_sb(pipefs_sb, pipe);
    228		rpc_put_sb_net(net);
    229	}
    230}
    231
    232static int nfs4blocklayout_net_init(struct net *net)
    233{
    234	struct nfs_net *nn = net_generic(net, nfs_net_id);
    235	struct dentry *dentry;
    236
    237	mutex_init(&nn->bl_mutex);
    238	init_waitqueue_head(&nn->bl_wq);
    239	nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
    240	if (IS_ERR(nn->bl_device_pipe))
    241		return PTR_ERR(nn->bl_device_pipe);
    242	dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe);
    243	if (IS_ERR(dentry)) {
    244		rpc_destroy_pipe_data(nn->bl_device_pipe);
    245		return PTR_ERR(dentry);
    246	}
    247	nn->bl_device_pipe->dentry = dentry;
    248	return 0;
    249}
    250
    251static void nfs4blocklayout_net_exit(struct net *net)
    252{
    253	struct nfs_net *nn = net_generic(net, nfs_net_id);
    254
    255	nfs4blocklayout_unregister_net(net, nn->bl_device_pipe);
    256	rpc_destroy_pipe_data(nn->bl_device_pipe);
    257	nn->bl_device_pipe = NULL;
    258}
    259
    260static struct pernet_operations nfs4blocklayout_net_ops = {
    261	.init = nfs4blocklayout_net_init,
    262	.exit = nfs4blocklayout_net_exit,
    263};
    264
    265int __init bl_init_pipefs(void)
    266{
    267	int ret;
    268
    269	ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block);
    270	if (ret)
    271		goto out;
    272	ret = register_pernet_subsys(&nfs4blocklayout_net_ops);
    273	if (ret)
    274		goto out_unregister_notifier;
    275	return 0;
    276
    277out_unregister_notifier:
    278	rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
    279out:
    280	return ret;
    281}
    282
    283void bl_cleanup_pipefs(void)
    284{
    285	rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
    286	unregister_pernet_subsys(&nfs4blocklayout_net_ops);
    287}