Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  Copyright (c) 2006,2007 The Regents of the University of Michigan.
0003  *  All rights reserved.
0004  *
0005  *  Andy Adamson <andros@citi.umich.edu>
0006  *  Fred Isaman <iisaman@umich.edu>
0007  *
0008  * permission is granted to use, copy, create derivative works and
0009  * redistribute this software and such derivative works for any purpose,
0010  * so long as the name of the university of michigan is not used in
0011  * any advertising or publicity pertaining to the use or distribution
0012  * of this software without specific, written prior authorization.  if
0013  * the above copyright notice or any other identification of the
0014  * university of michigan is included in any copy of any portion of
0015  * this software, then the disclaimer below must also be included.
0016  *
0017  * this software is provided as is, without representation from the
0018  * university of michigan as to its fitness for any purpose, and without
0019  * warranty by the university of michigan of any kind, either express
0020  * or implied, including without limitation the implied warranties of
0021  * merchantability and fitness for a particular purpose.  the regents
0022  * of the university of michigan shall not be liable for any damages,
0023  * including special, indirect, incidental, or consequential damages,
0024  * with respect to any claim arising out or in connection with the use
0025  * of the software, even if it has been or is hereafter advised of the
0026  * possibility of such damages.
0027  */
0028 
0029 #include <linux/module.h>
0030 #include <linux/blkdev.h>
0031 
0032 #include "blocklayout.h"
0033 
0034 #define NFSDBG_FACILITY         NFSDBG_PNFS_LD
0035 
0036 static void
0037 nfs4_encode_simple(__be32 *p, struct pnfs_block_volume *b)
0038 {
0039     int i;
0040 
0041     *p++ = cpu_to_be32(1);
0042     *p++ = cpu_to_be32(b->type);
0043     *p++ = cpu_to_be32(b->simple.nr_sigs);
0044     for (i = 0; i < b->simple.nr_sigs; i++) {
0045         p = xdr_encode_hyper(p, b->simple.sigs[i].offset);
0046         p = xdr_encode_opaque(p, b->simple.sigs[i].sig,
0047                      b->simple.sigs[i].sig_len);
0048     }
0049 }
0050 
0051 dev_t
0052 bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
0053         gfp_t gfp_mask)
0054 {
0055     struct net *net = server->nfs_client->cl_net;
0056     struct nfs_net *nn = net_generic(net, nfs_net_id);
0057     struct bl_dev_msg *reply = &nn->bl_mount_reply;
0058     struct bl_pipe_msg bl_pipe_msg;
0059     struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
0060     struct bl_msg_hdr *bl_msg;
0061     DECLARE_WAITQUEUE(wq, current);
0062     dev_t dev = 0;
0063     int rc;
0064 
0065     dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
0066 
0067     mutex_lock(&nn->bl_mutex);
0068     bl_pipe_msg.bl_wq = &nn->bl_wq;
0069 
0070     b->simple.len += 4; /* single volume */
0071     if (b->simple.len > PAGE_SIZE)
0072         goto out_unlock;
0073 
0074     memset(msg, 0, sizeof(*msg));
0075     msg->len = sizeof(*bl_msg) + b->simple.len;
0076     msg->data = kzalloc(msg->len, gfp_mask);
0077     if (!msg->data)
0078         goto out_free_data;
0079 
0080     bl_msg = msg->data;
0081     bl_msg->type = BL_DEVICE_MOUNT;
0082     bl_msg->totallen = b->simple.len;
0083     nfs4_encode_simple(msg->data + sizeof(*bl_msg), b);
0084 
0085     dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
0086     add_wait_queue(&nn->bl_wq, &wq);
0087     rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
0088     if (rc < 0) {
0089         remove_wait_queue(&nn->bl_wq, &wq);
0090         goto out_free_data;
0091     }
0092 
0093     set_current_state(TASK_UNINTERRUPTIBLE);
0094     schedule();
0095     remove_wait_queue(&nn->bl_wq, &wq);
0096 
0097     if (reply->status != BL_DEVICE_REQUEST_PROC) {
0098         printk(KERN_WARNING "%s failed to decode device: %d\n",
0099             __func__, reply->status);
0100         goto out_free_data;
0101     }
0102 
0103     dev = MKDEV(reply->major, reply->minor);
0104 out_free_data:
0105     kfree(msg->data);
0106 out_unlock:
0107     mutex_unlock(&nn->bl_mutex);
0108     return dev;
0109 }
0110 
0111 static ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
0112              size_t mlen)
0113 {
0114     struct nfs_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info,
0115                      nfs_net_id);
0116 
0117     if (mlen != sizeof (struct bl_dev_msg))
0118         return -EINVAL;
0119 
0120     if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0)
0121         return -EFAULT;
0122 
0123     wake_up(&nn->bl_wq);
0124 
0125     return mlen;
0126 }
0127 
0128 static void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
0129 {
0130     struct bl_pipe_msg *bl_pipe_msg =
0131         container_of(msg, struct bl_pipe_msg, msg);
0132 
0133     if (msg->errno >= 0)
0134         return;
0135     wake_up(bl_pipe_msg->bl_wq);
0136 }
0137 
0138 static const struct rpc_pipe_ops bl_upcall_ops = {
0139     .upcall     = rpc_pipe_generic_upcall,
0140     .downcall   = bl_pipe_downcall,
0141     .destroy_msg    = bl_pipe_destroy_msg,
0142 };
0143 
0144 static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb,
0145                         struct rpc_pipe *pipe)
0146 {
0147     struct dentry *dir, *dentry;
0148 
0149     dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME);
0150     if (dir == NULL)
0151         return ERR_PTR(-ENOENT);
0152     dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe);
0153     dput(dir);
0154     return dentry;
0155 }
0156 
0157 static void nfs4blocklayout_unregister_sb(struct super_block *sb,
0158                       struct rpc_pipe *pipe)
0159 {
0160     if (pipe->dentry)
0161         rpc_unlink(pipe->dentry);
0162 }
0163 
0164 static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
0165                void *ptr)
0166 {
0167     struct super_block *sb = ptr;
0168     struct net *net = sb->s_fs_info;
0169     struct nfs_net *nn = net_generic(net, nfs_net_id);
0170     struct dentry *dentry;
0171     int ret = 0;
0172 
0173     if (!try_module_get(THIS_MODULE))
0174         return 0;
0175 
0176     if (nn->bl_device_pipe == NULL) {
0177         module_put(THIS_MODULE);
0178         return 0;
0179     }
0180 
0181     switch (event) {
0182     case RPC_PIPEFS_MOUNT:
0183         dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe);
0184         if (IS_ERR(dentry)) {
0185             ret = PTR_ERR(dentry);
0186             break;
0187         }
0188         nn->bl_device_pipe->dentry = dentry;
0189         break;
0190     case RPC_PIPEFS_UMOUNT:
0191         if (nn->bl_device_pipe->dentry)
0192             nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe);
0193         break;
0194     default:
0195         ret = -ENOTSUPP;
0196         break;
0197     }
0198     module_put(THIS_MODULE);
0199     return ret;
0200 }
0201 
0202 static struct notifier_block nfs4blocklayout_block = {
0203     .notifier_call = rpc_pipefs_event,
0204 };
0205 
0206 static struct dentry *nfs4blocklayout_register_net(struct net *net,
0207                            struct rpc_pipe *pipe)
0208 {
0209     struct super_block *pipefs_sb;
0210     struct dentry *dentry;
0211 
0212     pipefs_sb = rpc_get_sb_net(net);
0213     if (!pipefs_sb)
0214         return NULL;
0215     dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe);
0216     rpc_put_sb_net(net);
0217     return dentry;
0218 }
0219 
0220 static void nfs4blocklayout_unregister_net(struct net *net,
0221                        struct rpc_pipe *pipe)
0222 {
0223     struct super_block *pipefs_sb;
0224 
0225     pipefs_sb = rpc_get_sb_net(net);
0226     if (pipefs_sb) {
0227         nfs4blocklayout_unregister_sb(pipefs_sb, pipe);
0228         rpc_put_sb_net(net);
0229     }
0230 }
0231 
0232 static int nfs4blocklayout_net_init(struct net *net)
0233 {
0234     struct nfs_net *nn = net_generic(net, nfs_net_id);
0235     struct dentry *dentry;
0236 
0237     mutex_init(&nn->bl_mutex);
0238     init_waitqueue_head(&nn->bl_wq);
0239     nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
0240     if (IS_ERR(nn->bl_device_pipe))
0241         return PTR_ERR(nn->bl_device_pipe);
0242     dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe);
0243     if (IS_ERR(dentry)) {
0244         rpc_destroy_pipe_data(nn->bl_device_pipe);
0245         return PTR_ERR(dentry);
0246     }
0247     nn->bl_device_pipe->dentry = dentry;
0248     return 0;
0249 }
0250 
0251 static void nfs4blocklayout_net_exit(struct net *net)
0252 {
0253     struct nfs_net *nn = net_generic(net, nfs_net_id);
0254 
0255     nfs4blocklayout_unregister_net(net, nn->bl_device_pipe);
0256     rpc_destroy_pipe_data(nn->bl_device_pipe);
0257     nn->bl_device_pipe = NULL;
0258 }
0259 
0260 static struct pernet_operations nfs4blocklayout_net_ops = {
0261     .init = nfs4blocklayout_net_init,
0262     .exit = nfs4blocklayout_net_exit,
0263 };
0264 
0265 int __init bl_init_pipefs(void)
0266 {
0267     int ret;
0268 
0269     ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block);
0270     if (ret)
0271         goto out;
0272     ret = register_pernet_subsys(&nfs4blocklayout_net_ops);
0273     if (ret)
0274         goto out_unregister_notifier;
0275     return 0;
0276 
0277 out_unregister_notifier:
0278     rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
0279 out:
0280     return ret;
0281 }
0282 
0283 void bl_cleanup_pipefs(void)
0284 {
0285     rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
0286     unregister_pernet_subsys(&nfs4blocklayout_net_ops);
0287 }