18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2006,2007 The Regents of the University of Michigan. 38c2ecf20Sopenharmony_ci * All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Andy Adamson <andros@citi.umich.edu> 68c2ecf20Sopenharmony_ci * Fred Isaman <iisaman@umich.edu> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * permission is granted to use, copy, create derivative works and 98c2ecf20Sopenharmony_ci * redistribute this software and such derivative works for any purpose, 108c2ecf20Sopenharmony_ci * so long as the name of the university of michigan is not used in 118c2ecf20Sopenharmony_ci * any advertising or publicity pertaining to the use or distribution 128c2ecf20Sopenharmony_ci * of this software without specific, written prior authorization. if 138c2ecf20Sopenharmony_ci * the above copyright notice or any other identification of the 148c2ecf20Sopenharmony_ci * university of michigan is included in any copy of any portion of 158c2ecf20Sopenharmony_ci * this software, then the disclaimer below must also be included. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * this software is provided as is, without representation from the 188c2ecf20Sopenharmony_ci * university of michigan as to its fitness for any purpose, and without 198c2ecf20Sopenharmony_ci * warranty by the university of michigan of any kind, either express 208c2ecf20Sopenharmony_ci * or implied, including without limitation the implied warranties of 218c2ecf20Sopenharmony_ci * merchantability and fitness for a particular purpose. the regents 228c2ecf20Sopenharmony_ci * of the university of michigan shall not be liable for any damages, 238c2ecf20Sopenharmony_ci * including special, indirect, incidental, or consequential damages, 248c2ecf20Sopenharmony_ci * with respect to any claim arising out or in connection with the use 258c2ecf20Sopenharmony_ci * of the software, even if it has been or is hereafter advised of the 268c2ecf20Sopenharmony_ci * possibility of such damages. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/module.h> 308c2ecf20Sopenharmony_ci#include <linux/genhd.h> 318c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "blocklayout.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define NFSDBG_FACILITY NFSDBG_PNFS_LD 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic void 388c2ecf20Sopenharmony_cinfs4_encode_simple(__be32 *p, struct pnfs_block_volume *b) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci int i; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci *p++ = cpu_to_be32(1); 438c2ecf20Sopenharmony_ci *p++ = cpu_to_be32(b->type); 448c2ecf20Sopenharmony_ci *p++ = cpu_to_be32(b->simple.nr_sigs); 458c2ecf20Sopenharmony_ci for (i = 0; i < b->simple.nr_sigs; i++) { 468c2ecf20Sopenharmony_ci p = xdr_encode_hyper(p, b->simple.sigs[i].offset); 478c2ecf20Sopenharmony_ci p = xdr_encode_opaque(p, b->simple.sigs[i].sig, 488c2ecf20Sopenharmony_ci b->simple.sigs[i].sig_len); 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cidev_t 538c2ecf20Sopenharmony_cibl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b, 548c2ecf20Sopenharmony_ci gfp_t gfp_mask) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct net *net = server->nfs_client->cl_net; 578c2ecf20Sopenharmony_ci struct nfs_net *nn = net_generic(net, nfs_net_id); 588c2ecf20Sopenharmony_ci struct bl_dev_msg *reply = &nn->bl_mount_reply; 598c2ecf20Sopenharmony_ci struct bl_pipe_msg bl_pipe_msg; 608c2ecf20Sopenharmony_ci struct rpc_pipe_msg *msg = &bl_pipe_msg.msg; 618c2ecf20Sopenharmony_ci struct bl_msg_hdr *bl_msg; 628c2ecf20Sopenharmony_ci DECLARE_WAITQUEUE(wq, current); 638c2ecf20Sopenharmony_ci dev_t dev = 0; 648c2ecf20Sopenharmony_ci int rc; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci mutex_lock(&nn->bl_mutex); 698c2ecf20Sopenharmony_ci bl_pipe_msg.bl_wq = &nn->bl_wq; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci b->simple.len += 4; /* single volume */ 728c2ecf20Sopenharmony_ci if (b->simple.len > PAGE_SIZE) 738c2ecf20Sopenharmony_ci goto out_unlock; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci memset(msg, 0, sizeof(*msg)); 768c2ecf20Sopenharmony_ci msg->len = sizeof(*bl_msg) + b->simple.len; 778c2ecf20Sopenharmony_ci msg->data = kzalloc(msg->len, gfp_mask); 788c2ecf20Sopenharmony_ci if (!msg->data) 798c2ecf20Sopenharmony_ci goto out_free_data; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci bl_msg = msg->data; 828c2ecf20Sopenharmony_ci bl_msg->type = BL_DEVICE_MOUNT; 838c2ecf20Sopenharmony_ci bl_msg->totallen = b->simple.len; 848c2ecf20Sopenharmony_ci nfs4_encode_simple(msg->data + sizeof(*bl_msg), b); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci dprintk("%s CALLING USERSPACE DAEMON\n", __func__); 878c2ecf20Sopenharmony_ci add_wait_queue(&nn->bl_wq, &wq); 888c2ecf20Sopenharmony_ci rc = rpc_queue_upcall(nn->bl_device_pipe, msg); 898c2ecf20Sopenharmony_ci if (rc < 0) { 908c2ecf20Sopenharmony_ci remove_wait_queue(&nn->bl_wq, &wq); 918c2ecf20Sopenharmony_ci goto out_free_data; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 958c2ecf20Sopenharmony_ci schedule(); 968c2ecf20Sopenharmony_ci remove_wait_queue(&nn->bl_wq, &wq); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (reply->status != BL_DEVICE_REQUEST_PROC) { 998c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s failed to decode device: %d\n", 1008c2ecf20Sopenharmony_ci __func__, reply->status); 1018c2ecf20Sopenharmony_ci goto out_free_data; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci dev = MKDEV(reply->major, reply->minor); 1058c2ecf20Sopenharmony_ciout_free_data: 1068c2ecf20Sopenharmony_ci kfree(msg->data); 1078c2ecf20Sopenharmony_ciout_unlock: 1088c2ecf20Sopenharmony_ci mutex_unlock(&nn->bl_mutex); 1098c2ecf20Sopenharmony_ci return dev; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic ssize_t bl_pipe_downcall(struct file *filp, const char __user *src, 1138c2ecf20Sopenharmony_ci size_t mlen) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct nfs_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info, 1168c2ecf20Sopenharmony_ci nfs_net_id); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (mlen != sizeof (struct bl_dev_msg)) 1198c2ecf20Sopenharmony_ci return -EINVAL; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0) 1228c2ecf20Sopenharmony_ci return -EFAULT; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci wake_up(&nn->bl_wq); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return mlen; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct bl_pipe_msg *bl_pipe_msg = 1328c2ecf20Sopenharmony_ci container_of(msg, struct bl_pipe_msg, msg); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (msg->errno >= 0) 1358c2ecf20Sopenharmony_ci return; 1368c2ecf20Sopenharmony_ci wake_up(bl_pipe_msg->bl_wq); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic const struct rpc_pipe_ops bl_upcall_ops = { 1408c2ecf20Sopenharmony_ci .upcall = rpc_pipe_generic_upcall, 1418c2ecf20Sopenharmony_ci .downcall = bl_pipe_downcall, 1428c2ecf20Sopenharmony_ci .destroy_msg = bl_pipe_destroy_msg, 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic struct dentry *nfs4blocklayout_register_sb(struct super_block *sb, 1468c2ecf20Sopenharmony_ci struct rpc_pipe *pipe) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci struct dentry *dir, *dentry; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME); 1518c2ecf20Sopenharmony_ci if (dir == NULL) 1528c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 1538c2ecf20Sopenharmony_ci dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe); 1548c2ecf20Sopenharmony_ci dput(dir); 1558c2ecf20Sopenharmony_ci return dentry; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void nfs4blocklayout_unregister_sb(struct super_block *sb, 1598c2ecf20Sopenharmony_ci struct rpc_pipe *pipe) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci if (pipe->dentry) 1628c2ecf20Sopenharmony_ci rpc_unlink(pipe->dentry); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, 1668c2ecf20Sopenharmony_ci void *ptr) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct super_block *sb = ptr; 1698c2ecf20Sopenharmony_ci struct net *net = sb->s_fs_info; 1708c2ecf20Sopenharmony_ci struct nfs_net *nn = net_generic(net, nfs_net_id); 1718c2ecf20Sopenharmony_ci struct dentry *dentry; 1728c2ecf20Sopenharmony_ci int ret = 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (nn->bl_device_pipe == NULL) { 1788c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci switch (event) { 1838c2ecf20Sopenharmony_ci case RPC_PIPEFS_MOUNT: 1848c2ecf20Sopenharmony_ci dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe); 1858c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) { 1868c2ecf20Sopenharmony_ci ret = PTR_ERR(dentry); 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci nn->bl_device_pipe->dentry = dentry; 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci case RPC_PIPEFS_UMOUNT: 1928c2ecf20Sopenharmony_ci if (nn->bl_device_pipe->dentry) 1938c2ecf20Sopenharmony_ci nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe); 1948c2ecf20Sopenharmony_ci break; 1958c2ecf20Sopenharmony_ci default: 1968c2ecf20Sopenharmony_ci ret = -ENOTSUPP; 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic struct notifier_block nfs4blocklayout_block = { 2048c2ecf20Sopenharmony_ci .notifier_call = rpc_pipefs_event, 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic struct dentry *nfs4blocklayout_register_net(struct net *net, 2088c2ecf20Sopenharmony_ci struct rpc_pipe *pipe) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct super_block *pipefs_sb; 2118c2ecf20Sopenharmony_ci struct dentry *dentry; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci pipefs_sb = rpc_get_sb_net(net); 2148c2ecf20Sopenharmony_ci if (!pipefs_sb) 2158c2ecf20Sopenharmony_ci return NULL; 2168c2ecf20Sopenharmony_ci dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe); 2178c2ecf20Sopenharmony_ci rpc_put_sb_net(net); 2188c2ecf20Sopenharmony_ci return dentry; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void nfs4blocklayout_unregister_net(struct net *net, 2228c2ecf20Sopenharmony_ci struct rpc_pipe *pipe) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct super_block *pipefs_sb; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci pipefs_sb = rpc_get_sb_net(net); 2278c2ecf20Sopenharmony_ci if (pipefs_sb) { 2288c2ecf20Sopenharmony_ci nfs4blocklayout_unregister_sb(pipefs_sb, pipe); 2298c2ecf20Sopenharmony_ci rpc_put_sb_net(net); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int nfs4blocklayout_net_init(struct net *net) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct nfs_net *nn = net_generic(net, nfs_net_id); 2368c2ecf20Sopenharmony_ci struct dentry *dentry; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci mutex_init(&nn->bl_mutex); 2398c2ecf20Sopenharmony_ci init_waitqueue_head(&nn->bl_wq); 2408c2ecf20Sopenharmony_ci nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0); 2418c2ecf20Sopenharmony_ci if (IS_ERR(nn->bl_device_pipe)) 2428c2ecf20Sopenharmony_ci return PTR_ERR(nn->bl_device_pipe); 2438c2ecf20Sopenharmony_ci dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe); 2448c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) { 2458c2ecf20Sopenharmony_ci rpc_destroy_pipe_data(nn->bl_device_pipe); 2468c2ecf20Sopenharmony_ci return PTR_ERR(dentry); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci nn->bl_device_pipe->dentry = dentry; 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic void nfs4blocklayout_net_exit(struct net *net) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci struct nfs_net *nn = net_generic(net, nfs_net_id); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci nfs4blocklayout_unregister_net(net, nn->bl_device_pipe); 2578c2ecf20Sopenharmony_ci rpc_destroy_pipe_data(nn->bl_device_pipe); 2588c2ecf20Sopenharmony_ci nn->bl_device_pipe = NULL; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic struct pernet_operations nfs4blocklayout_net_ops = { 2628c2ecf20Sopenharmony_ci .init = nfs4blocklayout_net_init, 2638c2ecf20Sopenharmony_ci .exit = nfs4blocklayout_net_exit, 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ciint __init bl_init_pipefs(void) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci int ret; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block); 2718c2ecf20Sopenharmony_ci if (ret) 2728c2ecf20Sopenharmony_ci goto out; 2738c2ecf20Sopenharmony_ci ret = register_pernet_subsys(&nfs4blocklayout_net_ops); 2748c2ecf20Sopenharmony_ci if (ret) 2758c2ecf20Sopenharmony_ci goto out_unregister_notifier; 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ciout_unregister_notifier: 2798c2ecf20Sopenharmony_ci rpc_pipefs_notifier_unregister(&nfs4blocklayout_block); 2808c2ecf20Sopenharmony_ciout: 2818c2ecf20Sopenharmony_ci return ret; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_civoid bl_cleanup_pipefs(void) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci rpc_pipefs_notifier_unregister(&nfs4blocklayout_block); 2878c2ecf20Sopenharmony_ci unregister_pernet_subsys(&nfs4blocklayout_net_ops); 2888c2ecf20Sopenharmony_ci} 289