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/genhd.h> 31#include <linux/blkdev.h> 32 33#include "blocklayout.h" 34 35#define NFSDBG_FACILITY NFSDBG_PNFS_LD 36 37static void 38nfs4_encode_simple(__be32 *p, struct pnfs_block_volume *b) 39{ 40 int i; 41 42 *p++ = cpu_to_be32(1); 43 *p++ = cpu_to_be32(b->type); 44 *p++ = cpu_to_be32(b->simple.nr_sigs); 45 for (i = 0; i < b->simple.nr_sigs; i++) { 46 p = xdr_encode_hyper(p, b->simple.sigs[i].offset); 47 p = xdr_encode_opaque(p, b->simple.sigs[i].sig, 48 b->simple.sigs[i].sig_len); 49 } 50} 51 52dev_t 53bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, 54 gfp_t gfp_mask) 55{ 56 struct net *net = server->nfs_client->cl_net; 57 struct nfs_net *nn = net_generic(net, nfs_net_id); 58 struct bl_dev_msg *reply = &nn->bl_mount_reply; 59 struct bl_pipe_msg bl_pipe_msg; 60 struct rpc_pipe_msg *msg = &bl_pipe_msg.msg; 61 struct bl_msg_hdr *bl_msg; 62 DECLARE_WAITQUEUE(wq, current); 63 dev_t dev = 0; 64 int rc; 65 66 dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); 67 68 mutex_lock(&nn->bl_mutex); 69 bl_pipe_msg.bl_wq = &nn->bl_wq; 70 71 b->simple.len += 4; /* single volume */ 72 if (b->simple.len > PAGE_SIZE) 73 goto out_unlock; 74 75 memset(msg, 0, sizeof(*msg)); 76 msg->len = sizeof(*bl_msg) + b->simple.len; 77 msg->data = kzalloc(msg->len, gfp_mask); 78 if (!msg->data) 79 goto out_free_data; 80 81 bl_msg = msg->data; 82 bl_msg->type = BL_DEVICE_MOUNT, 83 bl_msg->totallen = b->simple.len; 84 nfs4_encode_simple(msg->data + sizeof(*bl_msg), b); 85 86 dprintk("%s CALLING USERSPACE DAEMON\n", __func__); 87 add_wait_queue(&nn->bl_wq, &wq); 88 rc = rpc_queue_upcall(nn->bl_device_pipe, msg); 89 if (rc < 0) { 90 remove_wait_queue(&nn->bl_wq, &wq); 91 goto out_free_data; 92 } 93 94 set_current_state(TASK_UNINTERRUPTIBLE); 95 schedule(); 96 remove_wait_queue(&nn->bl_wq, &wq); 97 98 if (reply->status != BL_DEVICE_REQUEST_PROC) { 99 printk(KERN_WARNING "%s failed to decode device: %d\n", 100 __func__, reply->status); 101 goto out_free_data; 102 } 103 104 dev = MKDEV(reply->major, reply->minor); 105out_free_data: 106 kfree(msg->data); 107out_unlock: 108 mutex_unlock(&nn->bl_mutex); 109 return dev; 110} 111 112static ssize_t bl_pipe_downcall(struct file *filp, const char __user *src, 113 size_t mlen) 114{ 115 struct nfs_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info, 116 nfs_net_id); 117 118 if (mlen != sizeof (struct bl_dev_msg)) 119 return -EINVAL; 120 121 if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0) 122 return -EFAULT; 123 124 wake_up(&nn->bl_wq); 125 126 return mlen; 127} 128 129static void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg) 130{ 131 struct bl_pipe_msg *bl_pipe_msg = 132 container_of(msg, struct bl_pipe_msg, msg); 133 134 if (msg->errno >= 0) 135 return; 136 wake_up(bl_pipe_msg->bl_wq); 137} 138 139static const struct rpc_pipe_ops bl_upcall_ops = { 140 .upcall = rpc_pipe_generic_upcall, 141 .downcall = bl_pipe_downcall, 142 .destroy_msg = bl_pipe_destroy_msg, 143}; 144 145static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb, 146 struct rpc_pipe *pipe) 147{ 148 struct dentry *dir, *dentry; 149 150 dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME); 151 if (dir == NULL) 152 return ERR_PTR(-ENOENT); 153 dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe); 154 dput(dir); 155 return dentry; 156} 157 158static void nfs4blocklayout_unregister_sb(struct super_block *sb, 159 struct rpc_pipe *pipe) 160{ 161 if (pipe->dentry) 162 rpc_unlink(pipe->dentry); 163} 164 165static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, 166 void *ptr) 167{ 168 struct super_block *sb = ptr; 169 struct net *net = sb->s_fs_info; 170 struct nfs_net *nn = net_generic(net, nfs_net_id); 171 struct dentry *dentry; 172 int ret = 0; 173 174 if (!try_module_get(THIS_MODULE)) 175 return 0; 176 177 if (nn->bl_device_pipe == NULL) { 178 module_put(THIS_MODULE); 179 return 0; 180 } 181 182 switch (event) { 183 case RPC_PIPEFS_MOUNT: 184 dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe); 185 if (IS_ERR(dentry)) { 186 ret = PTR_ERR(dentry); 187 break; 188 } 189 nn->bl_device_pipe->dentry = dentry; 190 break; 191 case RPC_PIPEFS_UMOUNT: 192 if (nn->bl_device_pipe->dentry) 193 nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe); 194 break; 195 default: 196 ret = -ENOTSUPP; 197 break; 198 } 199 module_put(THIS_MODULE); 200 return ret; 201} 202 203static struct notifier_block nfs4blocklayout_block = { 204 .notifier_call = rpc_pipefs_event, 205}; 206 207static struct dentry *nfs4blocklayout_register_net(struct net *net, 208 struct rpc_pipe *pipe) 209{ 210 struct super_block *pipefs_sb; 211 struct dentry *dentry; 212 213 pipefs_sb = rpc_get_sb_net(net); 214 if (!pipefs_sb) 215 return NULL; 216 dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe); 217 rpc_put_sb_net(net); 218 return dentry; 219} 220 221static void nfs4blocklayout_unregister_net(struct net *net, 222 struct rpc_pipe *pipe) 223{ 224 struct super_block *pipefs_sb; 225 226 pipefs_sb = rpc_get_sb_net(net); 227 if (pipefs_sb) { 228 nfs4blocklayout_unregister_sb(pipefs_sb, pipe); 229 rpc_put_sb_net(net); 230 } 231} 232 233static int nfs4blocklayout_net_init(struct net *net) 234{ 235 struct nfs_net *nn = net_generic(net, nfs_net_id); 236 struct dentry *dentry; 237 238 mutex_init(&nn->bl_mutex); 239 init_waitqueue_head(&nn->bl_wq); 240 nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); 241 if (IS_ERR(nn->bl_device_pipe)) 242 return PTR_ERR(nn->bl_device_pipe); 243 dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe); 244 if (IS_ERR(dentry)) { 245 rpc_destroy_pipe_data(nn->bl_device_pipe); 246 return PTR_ERR(dentry); 247 } 248 nn->bl_device_pipe->dentry = dentry; 249 return 0; 250} 251 252static void nfs4blocklayout_net_exit(struct net *net) 253{ 254 struct nfs_net *nn = net_generic(net, nfs_net_id); 255 256 nfs4blocklayout_unregister_net(net, nn->bl_device_pipe); 257 rpc_destroy_pipe_data(nn->bl_device_pipe); 258 nn->bl_device_pipe = NULL; 259} 260 261static struct pernet_operations nfs4blocklayout_net_ops = { 262 .init = nfs4blocklayout_net_init, 263 .exit = nfs4blocklayout_net_exit, 264}; 265 266int __init bl_init_pipefs(void) 267{ 268 int ret; 269 270 ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block); 271 if (ret) 272 goto out; 273 ret = register_pernet_subsys(&nfs4blocklayout_net_ops); 274 if (ret) 275 goto out_unregister_notifier; 276 return 0; 277 278out_unregister_notifier: 279 rpc_pipefs_notifier_unregister(&nfs4blocklayout_block); 280out: 281 return ret; 282} 283 284void __exit bl_cleanup_pipefs(void) 285{ 286 rpc_pipefs_notifier_unregister(&nfs4blocklayout_block); 287 unregister_pernet_subsys(&nfs4blocklayout_net_ops); 288} 289