aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2014-09-10 20:37:26 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-09-12 13:33:50 -0400
commit871760ce97a9a544cfb1ae4589598b25b8570a25 (patch)
treef2c1b9348487b91f6a82b55ff8cdc85104234fd5 /fs/nfs
parentca0fe1dfa5acac6ec4ef5820d2eb5460b02648d5 (diff)
pnfs/blocklayout: move all rpc_pipefs related code into a single file
Create a file to house all the rpc_pipefs boilerplate code instead of sprinkling it over a few files. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/blocklayout/Makefile4
-rw-r--r--fs/nfs/blocklayout/blocklayout.c145
-rw-r--r--fs/nfs/blocklayout/blocklayout.h19
-rw-r--r--fs/nfs/blocklayout/blocklayoutdev.c172
-rw-r--r--fs/nfs/blocklayout/blocklayoutdm.c84
-rw-r--r--fs/nfs/blocklayout/rpc_pipefs.c362
6 files changed, 378 insertions, 408 deletions
diff --git a/fs/nfs/blocklayout/Makefile b/fs/nfs/blocklayout/Makefile
index 3fa5ec780a8e..e177026e0119 100644
--- a/fs/nfs/blocklayout/Makefile
+++ b/fs/nfs/blocklayout/Makefile
@@ -2,5 +2,5 @@
2# Makefile for the pNFS block layout driver kernel module 2# Makefile for the pNFS block layout driver kernel module
3# 3#
4obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o 4obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o
5blocklayoutdriver-objs := blocklayout.o blocklayoutdev.o blocklayoutdm.o \ 5
6 extent_tree.o 6blocklayoutdriver-y += blocklayout.o extent_tree.o rpc_pipefs.o
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index 76ec017a6f0a..65a6b19b17a2 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -863,132 +863,6 @@ static struct pnfs_layoutdriver_type blocklayout_type = {
863 .pg_write_ops = &bl_pg_write_ops, 863 .pg_write_ops = &bl_pg_write_ops,
864}; 864};
865 865
866static const struct rpc_pipe_ops bl_upcall_ops = {
867 .upcall = rpc_pipe_generic_upcall,
868 .downcall = bl_pipe_downcall,
869 .destroy_msg = bl_pipe_destroy_msg,
870};
871
872static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb,
873 struct rpc_pipe *pipe)
874{
875 struct dentry *dir, *dentry;
876
877 dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME);
878 if (dir == NULL)
879 return ERR_PTR(-ENOENT);
880 dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe);
881 dput(dir);
882 return dentry;
883}
884
885static void nfs4blocklayout_unregister_sb(struct super_block *sb,
886 struct rpc_pipe *pipe)
887{
888 if (pipe->dentry)
889 rpc_unlink(pipe->dentry);
890}
891
892static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
893 void *ptr)
894{
895 struct super_block *sb = ptr;
896 struct net *net = sb->s_fs_info;
897 struct nfs_net *nn = net_generic(net, nfs_net_id);
898 struct dentry *dentry;
899 int ret = 0;
900
901 if (!try_module_get(THIS_MODULE))
902 return 0;
903
904 if (nn->bl_device_pipe == NULL) {
905 module_put(THIS_MODULE);
906 return 0;
907 }
908
909 switch (event) {
910 case RPC_PIPEFS_MOUNT:
911 dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe);
912 if (IS_ERR(dentry)) {
913 ret = PTR_ERR(dentry);
914 break;
915 }
916 nn->bl_device_pipe->dentry = dentry;
917 break;
918 case RPC_PIPEFS_UMOUNT:
919 if (nn->bl_device_pipe->dentry)
920 nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe);
921 break;
922 default:
923 ret = -ENOTSUPP;
924 break;
925 }
926 module_put(THIS_MODULE);
927 return ret;
928}
929
930static struct notifier_block nfs4blocklayout_block = {
931 .notifier_call = rpc_pipefs_event,
932};
933
934static struct dentry *nfs4blocklayout_register_net(struct net *net,
935 struct rpc_pipe *pipe)
936{
937 struct super_block *pipefs_sb;
938 struct dentry *dentry;
939
940 pipefs_sb = rpc_get_sb_net(net);
941 if (!pipefs_sb)
942 return NULL;
943 dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe);
944 rpc_put_sb_net(net);
945 return dentry;
946}
947
948static void nfs4blocklayout_unregister_net(struct net *net,
949 struct rpc_pipe *pipe)
950{
951 struct super_block *pipefs_sb;
952
953 pipefs_sb = rpc_get_sb_net(net);
954 if (pipefs_sb) {
955 nfs4blocklayout_unregister_sb(pipefs_sb, pipe);
956 rpc_put_sb_net(net);
957 }
958}
959
960static int nfs4blocklayout_net_init(struct net *net)
961{
962 struct nfs_net *nn = net_generic(net, nfs_net_id);
963 struct dentry *dentry;
964
965 init_waitqueue_head(&nn->bl_wq);
966 nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
967 if (IS_ERR(nn->bl_device_pipe))
968 return PTR_ERR(nn->bl_device_pipe);
969 dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe);
970 if (IS_ERR(dentry)) {
971 rpc_destroy_pipe_data(nn->bl_device_pipe);
972 return PTR_ERR(dentry);
973 }
974 nn->bl_device_pipe->dentry = dentry;
975 return 0;
976}
977
978static void nfs4blocklayout_net_exit(struct net *net)
979{
980 struct nfs_net *nn = net_generic(net, nfs_net_id);
981
982 nfs4blocklayout_unregister_net(net, nn->bl_device_pipe);
983 rpc_destroy_pipe_data(nn->bl_device_pipe);
984 nn->bl_device_pipe = NULL;
985}
986
987static struct pernet_operations nfs4blocklayout_net_ops = {
988 .init = nfs4blocklayout_net_init,
989 .exit = nfs4blocklayout_net_exit,
990};
991
992static int __init nfs4blocklayout_init(void) 866static int __init nfs4blocklayout_init(void)
993{ 867{
994 int ret; 868 int ret;
@@ -998,20 +872,14 @@ static int __init nfs4blocklayout_init(void)
998 ret = pnfs_register_layoutdriver(&blocklayout_type); 872 ret = pnfs_register_layoutdriver(&blocklayout_type);
999 if (ret) 873 if (ret)
1000 goto out; 874 goto out;
1001 875 ret = bl_init_pipefs();
1002 ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block);
1003 if (ret)
1004 goto out_remove;
1005 ret = register_pernet_subsys(&nfs4blocklayout_net_ops);
1006 if (ret) 876 if (ret)
1007 goto out_notifier; 877 goto out_unregister;
1008out: 878 return 0;
1009 return ret;
1010 879
1011out_notifier: 880out_unregister:
1012 rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
1013out_remove:
1014 pnfs_unregister_layoutdriver(&blocklayout_type); 881 pnfs_unregister_layoutdriver(&blocklayout_type);
882out:
1015 return ret; 883 return ret;
1016} 884}
1017 885
@@ -1020,8 +888,7 @@ static void __exit nfs4blocklayout_exit(void)
1020 dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n", 888 dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n",
1021 __func__); 889 __func__);
1022 890
1023 rpc_pipefs_notifier_unregister(&nfs4blocklayout_block); 891 bl_cleanup_pipefs();
1024 unregister_pernet_subsys(&nfs4blocklayout_net_ops);
1025 pnfs_unregister_layoutdriver(&blocklayout_type); 892 pnfs_unregister_layoutdriver(&blocklayout_type);
1026} 893}
1027 894
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h
index 00c11eb9d765..c98d98a62664 100644
--- a/fs/nfs/blocklayout/blocklayout.h
+++ b/fs/nfs/blocklayout/blocklayout.h
@@ -110,17 +110,6 @@ struct bl_msg_hdr {
110#define BL_DEVICE_REQUEST_PROC 0x1 /* User level process succeeds */ 110#define BL_DEVICE_REQUEST_PROC 0x1 /* User level process succeeds */
111#define BL_DEVICE_REQUEST_ERR 0x2 /* User level process fails */ 111#define BL_DEVICE_REQUEST_ERR 0x2 /* User level process fails */
112 112
113/* blocklayoutdev.c */
114ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t);
115void bl_pipe_destroy_msg(struct rpc_pipe_msg *);
116
117struct nfs4_deviceid_node *bl_alloc_deviceid_node(struct nfs_server *server,
118 struct pnfs_device *pdev, gfp_t gfp_mask);
119void bl_free_deviceid_node(struct nfs4_deviceid_node *d);
120
121/* blocklayoutdm.c */
122void bl_dm_remove(struct net *net, dev_t dev);
123
124/* extent_tree.c */ 113/* extent_tree.c */
125int ext_tree_insert(struct pnfs_block_layout *bl, 114int ext_tree_insert(struct pnfs_block_layout *bl,
126 struct pnfs_block_extent *new); 115 struct pnfs_block_extent *new);
@@ -133,4 +122,12 @@ bool ext_tree_lookup(struct pnfs_block_layout *bl, sector_t isect,
133int ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg); 122int ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg);
134void ext_tree_mark_committed(struct nfs4_layoutcommit_args *arg, int status); 123void ext_tree_mark_committed(struct nfs4_layoutcommit_args *arg, int status);
135 124
125/* rpc_pipefs.c */
126struct nfs4_deviceid_node *bl_alloc_deviceid_node(struct nfs_server *server,
127 struct pnfs_device *pdev, gfp_t gfp_mask);
128void bl_free_deviceid_node(struct nfs4_deviceid_node *d);
129
130int __init bl_init_pipefs(void);
131void __exit bl_cleanup_pipefs(void);
132
136#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */ 133#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c
deleted file mode 100644
index 2b54e2940288..000000000000
--- a/fs/nfs/blocklayout/blocklayoutdev.c
+++ /dev/null
@@ -1,172 +0,0 @@
1/*
2 * linux/fs/nfs/blocklayout/blocklayoutdev.c
3 *
4 * Device operations for the pnfs nfs4 file layout driver.
5 *
6 * Copyright (c) 2006 The Regents of the University of Michigan.
7 * All rights reserved.
8 *
9 * Andy Adamson <andros@citi.umich.edu>
10 * Fred Isaman <iisaman@umich.edu>
11 *
12 * permission is granted to use, copy, create derivative works and
13 * redistribute this software and such derivative works for any purpose,
14 * so long as the name of the university of michigan is not used in
15 * any advertising or publicity pertaining to the use or distribution
16 * of this software without specific, written prior authorization. if
17 * the above copyright notice or any other identification of the
18 * university of michigan is included in any copy of any portion of
19 * this software, then the disclaimer below must also be included.
20 *
21 * this software is provided as is, without representation from the
22 * university of michigan as to its fitness for any purpose, and without
23 * warranty by the university of michigan of any kind, either express
24 * or implied, including without limitation the implied warranties of
25 * merchantability and fitness for a particular purpose. the regents
26 * of the university of michigan shall not be liable for any damages,
27 * including special, indirect, incidental, or consequential damages,
28 * with respect to any claim arising out or in connection with the use
29 * of the software, even if it has been or is hereafter advised of the
30 * possibility of such damages.
31 */
32#include <linux/module.h>
33#include <linux/buffer_head.h> /* __bread */
34
35#include <linux/genhd.h>
36#include <linux/blkdev.h>
37#include <linux/hash.h>
38
39#include "blocklayout.h"
40
41#define NFSDBG_FACILITY NFSDBG_PNFS_LD
42
43ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
44 size_t mlen)
45{
46 struct nfs_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
47 nfs_net_id);
48
49 if (mlen != sizeof (struct bl_dev_msg))
50 return -EINVAL;
51
52 if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0)
53 return -EFAULT;
54
55 wake_up(&nn->bl_wq);
56
57 return mlen;
58}
59
60void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
61{
62 struct bl_pipe_msg *bl_pipe_msg = container_of(msg, struct bl_pipe_msg, msg);
63
64 if (msg->errno >= 0)
65 return;
66 wake_up(bl_pipe_msg->bl_wq);
67}
68
69/*
70 * Decodes pnfs_block_deviceaddr4 which is XDR encoded in dev->dev_addr_buf.
71 */
72struct nfs4_deviceid_node *
73bl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *dev,
74 gfp_t gfp_mask)
75{
76 struct pnfs_block_dev *rv;
77 struct block_device *bd;
78 struct bl_pipe_msg bl_pipe_msg;
79 struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
80 struct bl_msg_hdr bl_msg = {
81 .type = BL_DEVICE_MOUNT,
82 .totallen = dev->mincount,
83 };
84 uint8_t *dataptr;
85 DECLARE_WAITQUEUE(wq, current);
86 int offset, len, i, rc;
87 struct net *net = server->nfs_client->cl_net;
88 struct nfs_net *nn = net_generic(net, nfs_net_id);
89 struct bl_dev_msg *reply = &nn->bl_mount_reply;
90
91 dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
92 dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data,
93 dev->mincount);
94
95 bl_pipe_msg.bl_wq = &nn->bl_wq;
96 memset(msg, 0, sizeof(*msg));
97 msg->data = kzalloc(sizeof(bl_msg) + dev->mincount, gfp_mask);
98 if (!msg->data)
99 goto out;
100
101 memcpy(msg->data, &bl_msg, sizeof(bl_msg));
102 dataptr = (uint8_t *) msg->data;
103 len = dev->mincount;
104 offset = sizeof(bl_msg);
105 for (i = 0; len > 0; i++) {
106 memcpy(&dataptr[offset], page_address(dev->pages[i]),
107 len < PAGE_CACHE_SIZE ? len : PAGE_CACHE_SIZE);
108 len -= PAGE_CACHE_SIZE;
109 offset += PAGE_CACHE_SIZE;
110 }
111 msg->len = sizeof(bl_msg) + dev->mincount;
112
113 dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
114 add_wait_queue(&nn->bl_wq, &wq);
115 rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
116 if (rc < 0) {
117 remove_wait_queue(&nn->bl_wq, &wq);
118 goto out;
119 }
120
121 set_current_state(TASK_UNINTERRUPTIBLE);
122 schedule();
123 __set_current_state(TASK_RUNNING);
124 remove_wait_queue(&nn->bl_wq, &wq);
125
126 if (reply->status != BL_DEVICE_REQUEST_PROC) {
127 printk(KERN_WARNING "%s failed to decode device: %d\n",
128 __func__, reply->status);
129 goto out;
130 }
131
132 bd = blkdev_get_by_dev(MKDEV(reply->major, reply->minor),
133 FMODE_READ, NULL);
134 if (IS_ERR(bd)) {
135 printk(KERN_WARNING "%s failed to open device %d:%d (%ld)\n",
136 __func__, reply->major, reply->minor,
137 PTR_ERR(bd));
138 goto out;
139 }
140
141 rv = kzalloc(sizeof(*rv), gfp_mask);
142 if (!rv)
143 goto out;
144
145 nfs4_init_deviceid_node(&rv->d_node, server, &dev->dev_id);
146 rv->d_bdev = bd;
147
148 dprintk("%s Created device %s with bd_block_size %u\n",
149 __func__,
150 bd->bd_disk->disk_name,
151 bd->bd_block_size);
152
153 kfree(msg->data);
154 return &rv->d_node;
155
156out:
157 kfree(msg->data);
158 return NULL;
159}
160
161void
162bl_free_deviceid_node(struct nfs4_deviceid_node *d)
163{
164 struct pnfs_block_dev *dev =
165 container_of(d, struct pnfs_block_dev, d_node);
166 struct net *net = d->nfs_client->cl_net;
167
168 blkdev_put(dev->d_bdev, FMODE_READ);
169 bl_dm_remove(net, dev->d_bdev->bd_dev);
170
171 kfree(dev);
172}
diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c
deleted file mode 100644
index abc2e9e45610..000000000000
--- a/fs/nfs/blocklayout/blocklayoutdm.c
+++ /dev/null
@@ -1,84 +0,0 @@
1/*
2 * linux/fs/nfs/blocklayout/blocklayoutdm.c
3 *
4 * Module for the NFSv4.1 pNFS block layout driver.
5 *
6 * Copyright (c) 2007 The Regents of the University of Michigan.
7 * All rights reserved.
8 *
9 * Fred Isaman <iisaman@umich.edu>
10 * Andy Adamson <andros@citi.umich.edu>
11 *
12 * permission is granted to use, copy, create derivative works and
13 * redistribute this software and such derivative works for any purpose,
14 * so long as the name of the university of michigan is not used in
15 * any advertising or publicity pertaining to the use or distribution
16 * of this software without specific, written prior authorization. if
17 * the above copyright notice or any other identification of the
18 * university of michigan is included in any copy of any portion of
19 * this software, then the disclaimer below must also be included.
20 *
21 * this software is provided as is, without representation from the
22 * university of michigan as to its fitness for any purpose, and without
23 * warranty by the university of michigan of any kind, either express
24 * or implied, including without limitation the implied warranties of
25 * merchantability and fitness for a particular purpose. the regents
26 * of the university of michigan shall not be liable for any damages,
27 * including special, indirect, incidental, or consequential damages,
28 * with respect to any claim arising out or in connection with the use
29 * of the software, even if it has been or is hereafter advised of the
30 * possibility of such damages.
31 */
32
33#include <linux/genhd.h> /* gendisk - used in a dprintk*/
34#include <linux/sched.h>
35#include <linux/hash.h>
36
37#include "blocklayout.h"
38
39#define NFSDBG_FACILITY NFSDBG_PNFS_LD
40
41void bl_dm_remove(struct net *net, dev_t dev)
42{
43 struct bl_pipe_msg bl_pipe_msg;
44 struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
45 struct bl_dev_msg bl_umount_request;
46 struct bl_msg_hdr bl_msg = {
47 .type = BL_DEVICE_UMOUNT,
48 .totallen = sizeof(bl_umount_request),
49 };
50 uint8_t *dataptr;
51 DECLARE_WAITQUEUE(wq, current);
52 struct nfs_net *nn = net_generic(net, nfs_net_id);
53
54 dprintk("Entering %s\n", __func__);
55
56 bl_pipe_msg.bl_wq = &nn->bl_wq;
57 memset(msg, 0, sizeof(*msg));
58 msg->len = sizeof(bl_msg) + bl_msg.totallen;
59 msg->data = kzalloc(msg->len, GFP_NOFS);
60 if (!msg->data)
61 goto out;
62
63 memset(&bl_umount_request, 0, sizeof(bl_umount_request));
64 bl_umount_request.major = MAJOR(dev);
65 bl_umount_request.minor = MINOR(dev);
66
67 memcpy(msg->data, &bl_msg, sizeof(bl_msg));
68 dataptr = (uint8_t *) msg->data;
69 memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request));
70
71 add_wait_queue(&nn->bl_wq, &wq);
72 if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) {
73 remove_wait_queue(&nn->bl_wq, &wq);
74 goto out;
75 }
76
77 set_current_state(TASK_UNINTERRUPTIBLE);
78 schedule();
79 __set_current_state(TASK_RUNNING);
80 remove_wait_queue(&nn->bl_wq, &wq);
81
82out:
83 kfree(msg->data);
84}
diff --git a/fs/nfs/blocklayout/rpc_pipefs.c b/fs/nfs/blocklayout/rpc_pipefs.c
new file mode 100644
index 000000000000..bfb04861eb61
--- /dev/null
+++ b/fs/nfs/blocklayout/rpc_pipefs.c
@@ -0,0 +1,362 @@
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 bl_dm_remove(struct net *net, dev_t dev)
38{
39 struct bl_pipe_msg bl_pipe_msg;
40 struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
41 struct bl_dev_msg bl_umount_request;
42 struct bl_msg_hdr bl_msg = {
43 .type = BL_DEVICE_UMOUNT,
44 .totallen = sizeof(bl_umount_request),
45 };
46 uint8_t *dataptr;
47 DECLARE_WAITQUEUE(wq, current);
48 struct nfs_net *nn = net_generic(net, nfs_net_id);
49
50 dprintk("Entering %s\n", __func__);
51
52 bl_pipe_msg.bl_wq = &nn->bl_wq;
53 memset(msg, 0, sizeof(*msg));
54 msg->len = sizeof(bl_msg) + bl_msg.totallen;
55 msg->data = kzalloc(msg->len, GFP_NOFS);
56 if (!msg->data)
57 goto out;
58
59 memset(&bl_umount_request, 0, sizeof(bl_umount_request));
60 bl_umount_request.major = MAJOR(dev);
61 bl_umount_request.minor = MINOR(dev);
62
63 memcpy(msg->data, &bl_msg, sizeof(bl_msg));
64 dataptr = (uint8_t *) msg->data;
65 memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request));
66
67 add_wait_queue(&nn->bl_wq, &wq);
68 if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) {
69 remove_wait_queue(&nn->bl_wq, &wq);
70 goto out;
71 }
72
73 set_current_state(TASK_UNINTERRUPTIBLE);
74 schedule();
75 __set_current_state(TASK_RUNNING);
76 remove_wait_queue(&nn->bl_wq, &wq);
77
78out:
79 kfree(msg->data);
80}
81
82/*
83 * Decodes pnfs_block_deviceaddr4 which is XDR encoded in dev->dev_addr_buf.
84 */
85struct nfs4_deviceid_node *
86bl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *dev,
87 gfp_t gfp_mask)
88{
89 struct pnfs_block_dev *rv;
90 struct block_device *bd;
91 struct bl_pipe_msg bl_pipe_msg;
92 struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
93 struct bl_msg_hdr bl_msg = {
94 .type = BL_DEVICE_MOUNT,
95 .totallen = dev->mincount,
96 };
97 uint8_t *dataptr;
98 DECLARE_WAITQUEUE(wq, current);
99 int offset, len, i, rc;
100 struct net *net = server->nfs_client->cl_net;
101 struct nfs_net *nn = net_generic(net, nfs_net_id);
102 struct bl_dev_msg *reply = &nn->bl_mount_reply;
103
104 dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
105 dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data,
106 dev->mincount);
107
108 bl_pipe_msg.bl_wq = &nn->bl_wq;
109 memset(msg, 0, sizeof(*msg));
110 msg->data = kzalloc(sizeof(bl_msg) + dev->mincount, gfp_mask);
111 if (!msg->data)
112 goto out;
113
114 memcpy(msg->data, &bl_msg, sizeof(bl_msg));
115 dataptr = (uint8_t *) msg->data;
116 len = dev->mincount;
117 offset = sizeof(bl_msg);
118 for (i = 0; len > 0; i++) {
119 memcpy(&dataptr[offset], page_address(dev->pages[i]),
120 len < PAGE_CACHE_SIZE ? len : PAGE_CACHE_SIZE);
121 len -= PAGE_CACHE_SIZE;
122 offset += PAGE_CACHE_SIZE;
123 }
124 msg->len = sizeof(bl_msg) + dev->mincount;
125
126 dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
127 add_wait_queue(&nn->bl_wq, &wq);
128 rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
129 if (rc < 0) {
130 remove_wait_queue(&nn->bl_wq, &wq);
131 goto out;
132 }
133
134 set_current_state(TASK_UNINTERRUPTIBLE);
135 schedule();
136 __set_current_state(TASK_RUNNING);
137 remove_wait_queue(&nn->bl_wq, &wq);
138
139 if (reply->status != BL_DEVICE_REQUEST_PROC) {
140 printk(KERN_WARNING "%s failed to decode device: %d\n",
141 __func__, reply->status);
142 goto out;
143 }
144
145 bd = blkdev_get_by_dev(MKDEV(reply->major, reply->minor),
146 FMODE_READ, NULL);
147 if (IS_ERR(bd)) {
148 printk(KERN_WARNING "%s failed to open device %d:%d (%ld)\n",
149 __func__, reply->major, reply->minor,
150 PTR_ERR(bd));
151 goto out;
152 }
153
154 rv = kzalloc(sizeof(*rv), gfp_mask);
155 if (!rv)
156 goto out;
157
158 nfs4_init_deviceid_node(&rv->d_node, server, &dev->dev_id);
159 rv->d_bdev = bd;
160
161 dprintk("%s Created device %s with bd_block_size %u\n",
162 __func__,
163 bd->bd_disk->disk_name,
164 bd->bd_block_size);
165
166 kfree(msg->data);
167 return &rv->d_node;
168
169out:
170 kfree(msg->data);
171 return NULL;
172}
173
174void
175bl_free_deviceid_node(struct nfs4_deviceid_node *d)
176{
177 struct pnfs_block_dev *dev =
178 container_of(d, struct pnfs_block_dev, d_node);
179 struct net *net = d->nfs_client->cl_net;
180
181 blkdev_put(dev->d_bdev, FMODE_READ);
182 bl_dm_remove(net, dev->d_bdev->bd_dev);
183
184 kfree(dev);
185}
186
187static ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
188 size_t mlen)
189{
190 struct nfs_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
191 nfs_net_id);
192
193 if (mlen != sizeof (struct bl_dev_msg))
194 return -EINVAL;
195
196 if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0)
197 return -EFAULT;
198
199 wake_up(&nn->bl_wq);
200
201 return mlen;
202}
203
204static void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
205{
206 struct bl_pipe_msg *bl_pipe_msg =
207 container_of(msg, struct bl_pipe_msg, msg);
208
209 if (msg->errno >= 0)
210 return;
211 wake_up(bl_pipe_msg->bl_wq);
212}
213
214static const struct rpc_pipe_ops bl_upcall_ops = {
215 .upcall = rpc_pipe_generic_upcall,
216 .downcall = bl_pipe_downcall,
217 .destroy_msg = bl_pipe_destroy_msg,
218};
219
220static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb,
221 struct rpc_pipe *pipe)
222{
223 struct dentry *dir, *dentry;
224
225 dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME);
226 if (dir == NULL)
227 return ERR_PTR(-ENOENT);
228 dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe);
229 dput(dir);
230 return dentry;
231}
232
233static void nfs4blocklayout_unregister_sb(struct super_block *sb,
234 struct rpc_pipe *pipe)
235{
236 if (pipe->dentry)
237 rpc_unlink(pipe->dentry);
238}
239
240static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
241 void *ptr)
242{
243 struct super_block *sb = ptr;
244 struct net *net = sb->s_fs_info;
245 struct nfs_net *nn = net_generic(net, nfs_net_id);
246 struct dentry *dentry;
247 int ret = 0;
248
249 if (!try_module_get(THIS_MODULE))
250 return 0;
251
252 if (nn->bl_device_pipe == NULL) {
253 module_put(THIS_MODULE);
254 return 0;
255 }
256
257 switch (event) {
258 case RPC_PIPEFS_MOUNT:
259 dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe);
260 if (IS_ERR(dentry)) {
261 ret = PTR_ERR(dentry);
262 break;
263 }
264 nn->bl_device_pipe->dentry = dentry;
265 break;
266 case RPC_PIPEFS_UMOUNT:
267 if (nn->bl_device_pipe->dentry)
268 nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe);
269 break;
270 default:
271 ret = -ENOTSUPP;
272 break;
273 }
274 module_put(THIS_MODULE);
275 return ret;
276}
277
278static struct notifier_block nfs4blocklayout_block = {
279 .notifier_call = rpc_pipefs_event,
280};
281
282static struct dentry *nfs4blocklayout_register_net(struct net *net,
283 struct rpc_pipe *pipe)
284{
285 struct super_block *pipefs_sb;
286 struct dentry *dentry;
287
288 pipefs_sb = rpc_get_sb_net(net);
289 if (!pipefs_sb)
290 return NULL;
291 dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe);
292 rpc_put_sb_net(net);
293 return dentry;
294}
295
296static void nfs4blocklayout_unregister_net(struct net *net,
297 struct rpc_pipe *pipe)
298{
299 struct super_block *pipefs_sb;
300
301 pipefs_sb = rpc_get_sb_net(net);
302 if (pipefs_sb) {
303 nfs4blocklayout_unregister_sb(pipefs_sb, pipe);
304 rpc_put_sb_net(net);
305 }
306}
307
308static int nfs4blocklayout_net_init(struct net *net)
309{
310 struct nfs_net *nn = net_generic(net, nfs_net_id);
311 struct dentry *dentry;
312
313 init_waitqueue_head(&nn->bl_wq);
314 nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
315 if (IS_ERR(nn->bl_device_pipe))
316 return PTR_ERR(nn->bl_device_pipe);
317 dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe);
318 if (IS_ERR(dentry)) {
319 rpc_destroy_pipe_data(nn->bl_device_pipe);
320 return PTR_ERR(dentry);
321 }
322 nn->bl_device_pipe->dentry = dentry;
323 return 0;
324}
325
326static void nfs4blocklayout_net_exit(struct net *net)
327{
328 struct nfs_net *nn = net_generic(net, nfs_net_id);
329
330 nfs4blocklayout_unregister_net(net, nn->bl_device_pipe);
331 rpc_destroy_pipe_data(nn->bl_device_pipe);
332 nn->bl_device_pipe = NULL;
333}
334
335static struct pernet_operations nfs4blocklayout_net_ops = {
336 .init = nfs4blocklayout_net_init,
337 .exit = nfs4blocklayout_net_exit,
338};
339
340int __init bl_init_pipefs(void)
341{
342 int ret;
343
344 ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block);
345 if (ret)
346 goto out;
347 ret = register_pernet_subsys(&nfs4blocklayout_net_ops);
348 if (ret)
349 goto out_unregister_notifier;
350 return 0;
351
352out_unregister_notifier:
353 rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
354out:
355 return ret;
356}
357
358void __exit bl_cleanup_pipefs(void)
359{
360 rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
361 unregister_pernet_subsys(&nfs4blocklayout_net_ops);
362}