diff options
author | Christoph Hellwig <hch@lst.de> | 2014-09-10 20:37:26 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-09-12 13:33:50 -0400 |
commit | 871760ce97a9a544cfb1ae4589598b25b8570a25 (patch) | |
tree | f2c1b9348487b91f6a82b55ff8cdc85104234fd5 /fs/nfs | |
parent | ca0fe1dfa5acac6ec4ef5820d2eb5460b02648d5 (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/Makefile | 4 | ||||
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.c | 145 | ||||
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.h | 19 | ||||
-rw-r--r-- | fs/nfs/blocklayout/blocklayoutdev.c | 172 | ||||
-rw-r--r-- | fs/nfs/blocklayout/blocklayoutdm.c | 84 | ||||
-rw-r--r-- | fs/nfs/blocklayout/rpc_pipefs.c | 362 |
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 | # |
4 | obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o | 4 | obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o |
5 | blocklayoutdriver-objs := blocklayout.o blocklayoutdev.o blocklayoutdm.o \ | 5 | |
6 | extent_tree.o | 6 | blocklayoutdriver-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 | ||
866 | static 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 | |||
872 | static 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 | |||
885 | static 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 | |||
892 | static 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 | |||
930 | static struct notifier_block nfs4blocklayout_block = { | ||
931 | .notifier_call = rpc_pipefs_event, | ||
932 | }; | ||
933 | |||
934 | static 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 | |||
948 | static 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 | |||
960 | static 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 | |||
978 | static 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 | |||
987 | static struct pernet_operations nfs4blocklayout_net_ops = { | ||
988 | .init = nfs4blocklayout_net_init, | ||
989 | .exit = nfs4blocklayout_net_exit, | ||
990 | }; | ||
991 | |||
992 | static int __init nfs4blocklayout_init(void) | 866 | static 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; |
1008 | out: | 878 | return 0; |
1009 | return ret; | ||
1010 | 879 | ||
1011 | out_notifier: | 880 | out_unregister: |
1012 | rpc_pipefs_notifier_unregister(&nfs4blocklayout_block); | ||
1013 | out_remove: | ||
1014 | pnfs_unregister_layoutdriver(&blocklayout_type); | 881 | pnfs_unregister_layoutdriver(&blocklayout_type); |
882 | out: | ||
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 */ | ||
114 | ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t); | ||
115 | void bl_pipe_destroy_msg(struct rpc_pipe_msg *); | ||
116 | |||
117 | struct nfs4_deviceid_node *bl_alloc_deviceid_node(struct nfs_server *server, | ||
118 | struct pnfs_device *pdev, gfp_t gfp_mask); | ||
119 | void bl_free_deviceid_node(struct nfs4_deviceid_node *d); | ||
120 | |||
121 | /* blocklayoutdm.c */ | ||
122 | void bl_dm_remove(struct net *net, dev_t dev); | ||
123 | |||
124 | /* extent_tree.c */ | 113 | /* extent_tree.c */ |
125 | int ext_tree_insert(struct pnfs_block_layout *bl, | 114 | int 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, | |||
133 | int ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg); | 122 | int ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg); |
134 | void ext_tree_mark_committed(struct nfs4_layoutcommit_args *arg, int status); | 123 | void ext_tree_mark_committed(struct nfs4_layoutcommit_args *arg, int status); |
135 | 124 | ||
125 | /* rpc_pipefs.c */ | ||
126 | struct nfs4_deviceid_node *bl_alloc_deviceid_node(struct nfs_server *server, | ||
127 | struct pnfs_device *pdev, gfp_t gfp_mask); | ||
128 | void bl_free_deviceid_node(struct nfs4_deviceid_node *d); | ||
129 | |||
130 | int __init bl_init_pipefs(void); | ||
131 | void __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 | |||
43 | ssize_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 | |||
60 | void 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 | */ | ||
72 | struct nfs4_deviceid_node * | ||
73 | bl_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 | |||
156 | out: | ||
157 | kfree(msg->data); | ||
158 | return NULL; | ||
159 | } | ||
160 | |||
161 | void | ||
162 | bl_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 | |||
41 | void 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 | |||
82 | out: | ||
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 | |||
37 | static 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 | |||
78 | out: | ||
79 | kfree(msg->data); | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * Decodes pnfs_block_deviceaddr4 which is XDR encoded in dev->dev_addr_buf. | ||
84 | */ | ||
85 | struct nfs4_deviceid_node * | ||
86 | bl_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 | |||
169 | out: | ||
170 | kfree(msg->data); | ||
171 | return NULL; | ||
172 | } | ||
173 | |||
174 | void | ||
175 | bl_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 | |||
187 | static 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 | |||
204 | static 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 | |||
214 | static 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 | |||
220 | static 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 | |||
233 | static 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 | |||
240 | static 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 | |||
278 | static struct notifier_block nfs4blocklayout_block = { | ||
279 | .notifier_call = rpc_pipefs_event, | ||
280 | }; | ||
281 | |||
282 | static 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 | |||
296 | static 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 | |||
308 | static 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 | |||
326 | static 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 | |||
335 | static struct pernet_operations nfs4blocklayout_net_ops = { | ||
336 | .init = nfs4blocklayout_net_init, | ||
337 | .exit = nfs4blocklayout_net_exit, | ||
338 | }; | ||
339 | |||
340 | int __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 | |||
352 | out_unregister_notifier: | ||
353 | rpc_pipefs_notifier_unregister(&nfs4blocklayout_block); | ||
354 | out: | ||
355 | return ret; | ||
356 | } | ||
357 | |||
358 | void __exit bl_cleanup_pipefs(void) | ||
359 | { | ||
360 | rpc_pipefs_notifier_unregister(&nfs4blocklayout_block); | ||
361 | unregister_pernet_subsys(&nfs4blocklayout_net_ops); | ||
362 | } | ||