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}