diff options
author | Jim Rees <rees@umich.edu> | 2011-07-30 20:52:42 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-07-31 12:18:16 -0400 |
commit | fe0a9b740881d181e3c96c1f6f6043e252692ffe (patch) | |
tree | 11dff7e25a2a9d922fba32d331530d671769c550 | |
parent | 9e69296999362c4e4b2821b64389b47e86e4821b (diff) |
pnfsblock: add device operations
Signed-off-by: Jim Rees <rees@umich.edu>
Signed-off-by: Fred Isaman <iisaman@citi.umich.edu>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: Benny Halevy <bhalevy@tonian.com>
[upcall bugfixes]
Signed-off-by: Peng Tao <peng_tao@emc.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/blocklayout/Makefile | 2 | ||||
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.c | 42 | ||||
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.h | 40 | ||||
-rw-r--r-- | fs/nfs/blocklayout/blocklayoutdev.c | 191 | ||||
-rw-r--r-- | fs/nfs/client.c | 2 | ||||
-rw-r--r-- | include/linux/nfs.h | 2 |
6 files changed, 277 insertions, 2 deletions
diff --git a/fs/nfs/blocklayout/Makefile b/fs/nfs/blocklayout/Makefile index 5cfadf6ebc90..5bf3409084d2 100644 --- a/fs/nfs/blocklayout/Makefile +++ b/fs/nfs/blocklayout/Makefile | |||
@@ -2,4 +2,4 @@ | |||
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 extents.o | 5 | blocklayoutdriver-objs := blocklayout.o extents.o blocklayoutdev.o |
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 8dde3723482e..c83878441047 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
@@ -31,6 +31,8 @@ | |||
31 | */ | 31 | */ |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
34 | #include <linux/mount.h> | ||
35 | #include <linux/namei.h> | ||
34 | 36 | ||
35 | #include "blocklayout.h" | 37 | #include "blocklayout.h" |
36 | 38 | ||
@@ -40,6 +42,9 @@ MODULE_LICENSE("GPL"); | |||
40 | MODULE_AUTHOR("Andy Adamson <andros@citi.umich.edu>"); | 42 | MODULE_AUTHOR("Andy Adamson <andros@citi.umich.edu>"); |
41 | MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver"); | 43 | MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver"); |
42 | 44 | ||
45 | struct dentry *bl_device_pipe; | ||
46 | wait_queue_head_t bl_wq; | ||
47 | |||
43 | static enum pnfs_try_status | 48 | static enum pnfs_try_status |
44 | bl_read_pagelist(struct nfs_read_data *rdata) | 49 | bl_read_pagelist(struct nfs_read_data *rdata) |
45 | { | 50 | { |
@@ -176,13 +181,49 @@ static struct pnfs_layoutdriver_type blocklayout_type = { | |||
176 | .pg_write_ops = &bl_pg_write_ops, | 181 | .pg_write_ops = &bl_pg_write_ops, |
177 | }; | 182 | }; |
178 | 183 | ||
184 | static const struct rpc_pipe_ops bl_upcall_ops = { | ||
185 | .upcall = bl_pipe_upcall, | ||
186 | .downcall = bl_pipe_downcall, | ||
187 | .destroy_msg = bl_pipe_destroy_msg, | ||
188 | }; | ||
189 | |||
179 | static int __init nfs4blocklayout_init(void) | 190 | static int __init nfs4blocklayout_init(void) |
180 | { | 191 | { |
192 | struct vfsmount *mnt; | ||
193 | struct path path; | ||
181 | int ret; | 194 | int ret; |
182 | 195 | ||
183 | dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__); | 196 | dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__); |
184 | 197 | ||
185 | ret = pnfs_register_layoutdriver(&blocklayout_type); | 198 | ret = pnfs_register_layoutdriver(&blocklayout_type); |
199 | if (ret) | ||
200 | goto out; | ||
201 | |||
202 | init_waitqueue_head(&bl_wq); | ||
203 | |||
204 | mnt = rpc_get_mount(); | ||
205 | if (IS_ERR(mnt)) { | ||
206 | ret = PTR_ERR(mnt); | ||
207 | goto out_remove; | ||
208 | } | ||
209 | |||
210 | ret = vfs_path_lookup(mnt->mnt_root, | ||
211 | mnt, | ||
212 | NFS_PIPE_DIRNAME, 0, &path); | ||
213 | if (ret) | ||
214 | goto out_remove; | ||
215 | |||
216 | bl_device_pipe = rpc_mkpipe(path.dentry, "blocklayout", NULL, | ||
217 | &bl_upcall_ops, 0); | ||
218 | if (IS_ERR(bl_device_pipe)) { | ||
219 | ret = PTR_ERR(bl_device_pipe); | ||
220 | goto out_remove; | ||
221 | } | ||
222 | out: | ||
223 | return ret; | ||
224 | |||
225 | out_remove: | ||
226 | pnfs_unregister_layoutdriver(&blocklayout_type); | ||
186 | return ret; | 227 | return ret; |
187 | } | 228 | } |
188 | 229 | ||
@@ -192,6 +233,7 @@ static void __exit nfs4blocklayout_exit(void) | |||
192 | __func__); | 233 | __func__); |
193 | 234 | ||
194 | pnfs_unregister_layoutdriver(&blocklayout_type); | 235 | pnfs_unregister_layoutdriver(&blocklayout_type); |
236 | rpc_unlink(bl_device_pipe); | ||
195 | } | 237 | } |
196 | 238 | ||
197 | MODULE_ALIAS("nfs-layouttype4-3"); | 239 | MODULE_ALIAS("nfs-layouttype4-3"); |
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h index 98e2f60c2143..dd25f1b3fe1e 100644 --- a/fs/nfs/blocklayout/blocklayout.h +++ b/fs/nfs/blocklayout/blocklayout.h | |||
@@ -34,8 +34,16 @@ | |||
34 | 34 | ||
35 | #include <linux/device-mapper.h> | 35 | #include <linux/device-mapper.h> |
36 | #include <linux/nfs_fs.h> | 36 | #include <linux/nfs_fs.h> |
37 | #include <linux/sunrpc/rpc_pipe_fs.h> | ||
38 | |||
37 | #include "../pnfs.h" | 39 | #include "../pnfs.h" |
38 | 40 | ||
41 | struct pnfs_block_dev { | ||
42 | struct list_head bm_node; | ||
43 | struct nfs4_deviceid bm_mdevid; /* associated devid */ | ||
44 | struct block_device *bm_mdev; /* meta device itself */ | ||
45 | }; | ||
46 | |||
39 | enum exstate4 { | 47 | enum exstate4 { |
40 | PNFS_BLOCK_READWRITE_DATA = 0, | 48 | PNFS_BLOCK_READWRITE_DATA = 0, |
41 | PNFS_BLOCK_READ_DATA = 1, | 49 | PNFS_BLOCK_READ_DATA = 1, |
@@ -88,5 +96,37 @@ static inline struct pnfs_block_layout *BLK_LO2EXT(struct pnfs_layout_hdr *lo) | |||
88 | return container_of(lo, struct pnfs_block_layout, bl_layout); | 96 | return container_of(lo, struct pnfs_block_layout, bl_layout); |
89 | } | 97 | } |
90 | 98 | ||
99 | struct bl_dev_msg { | ||
100 | int status; | ||
101 | uint32_t major, minor; | ||
102 | }; | ||
103 | |||
104 | struct bl_msg_hdr { | ||
105 | u8 type; | ||
106 | u16 totallen; /* length of entire message, including hdr itself */ | ||
107 | }; | ||
108 | |||
109 | extern struct dentry *bl_device_pipe; | ||
110 | extern wait_queue_head_t bl_wq; | ||
111 | |||
112 | #define BL_DEVICE_UMOUNT 0x0 /* Umount--delete devices */ | ||
113 | #define BL_DEVICE_MOUNT 0x1 /* Mount--create devices*/ | ||
114 | #define BL_DEVICE_REQUEST_INIT 0x0 /* Start request */ | ||
115 | #define BL_DEVICE_REQUEST_PROC 0x1 /* User level process succeeds */ | ||
116 | #define BL_DEVICE_REQUEST_ERR 0x2 /* User level process fails */ | ||
117 | |||
118 | /* blocklayoutdev.c */ | ||
119 | ssize_t bl_pipe_upcall(struct file *, struct rpc_pipe_msg *, | ||
120 | char __user *, size_t); | ||
121 | ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t); | ||
122 | void bl_pipe_destroy_msg(struct rpc_pipe_msg *); | ||
123 | struct block_device *nfs4_blkdev_get(dev_t dev); | ||
124 | int nfs4_blkdev_put(struct block_device *bdev); | ||
125 | struct pnfs_block_dev *nfs4_blk_decode_device(struct nfs_server *server, | ||
126 | struct pnfs_device *dev, | ||
127 | struct list_head *sdlist); | ||
128 | int nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo, | ||
129 | struct nfs4_layoutget_res *lgr, gfp_t gfp_flags); | ||
130 | |||
91 | void bl_put_extent(struct pnfs_block_extent *be); | 131 | void bl_put_extent(struct pnfs_block_extent *be); |
92 | #endif /* FS_NFS_NFS4BLOCKLAYOUT_H */ | 132 | #endif /* FS_NFS_NFS4BLOCKLAYOUT_H */ |
diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c new file mode 100644 index 000000000000..7e1377fcfdce --- /dev/null +++ b/fs/nfs/blocklayout/blocklayoutdev.c | |||
@@ -0,0 +1,191 @@ | |||
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 | /* Open a block_device by device number. */ | ||
44 | struct block_device *nfs4_blkdev_get(dev_t dev) | ||
45 | { | ||
46 | struct block_device *bd; | ||
47 | |||
48 | dprintk("%s enter\n", __func__); | ||
49 | bd = blkdev_get_by_dev(dev, FMODE_READ, NULL); | ||
50 | if (IS_ERR(bd)) | ||
51 | goto fail; | ||
52 | return bd; | ||
53 | fail: | ||
54 | dprintk("%s failed to open device : %ld\n", | ||
55 | __func__, PTR_ERR(bd)); | ||
56 | return NULL; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Release the block device | ||
61 | */ | ||
62 | int nfs4_blkdev_put(struct block_device *bdev) | ||
63 | { | ||
64 | dprintk("%s for device %d:%d\n", __func__, MAJOR(bdev->bd_dev), | ||
65 | MINOR(bdev->bd_dev)); | ||
66 | return blkdev_put(bdev, FMODE_READ); | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Shouldn't there be a rpc_generic_upcall() to do this for us? | ||
71 | */ | ||
72 | ssize_t bl_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, | ||
73 | char __user *dst, size_t buflen) | ||
74 | { | ||
75 | char *data = (char *)msg->data + msg->copied; | ||
76 | size_t mlen = min(msg->len - msg->copied, buflen); | ||
77 | unsigned long left; | ||
78 | |||
79 | left = copy_to_user(dst, data, mlen); | ||
80 | if (left == mlen) { | ||
81 | msg->errno = -EFAULT; | ||
82 | return -EFAULT; | ||
83 | } | ||
84 | |||
85 | mlen -= left; | ||
86 | msg->copied += mlen; | ||
87 | msg->errno = 0; | ||
88 | return mlen; | ||
89 | } | ||
90 | |||
91 | static struct bl_dev_msg bl_mount_reply; | ||
92 | |||
93 | ssize_t bl_pipe_downcall(struct file *filp, const char __user *src, | ||
94 | size_t mlen) | ||
95 | { | ||
96 | if (mlen != sizeof (struct bl_dev_msg)) | ||
97 | return -EINVAL; | ||
98 | |||
99 | if (copy_from_user(&bl_mount_reply, src, mlen) != 0) | ||
100 | return -EFAULT; | ||
101 | |||
102 | wake_up(&bl_wq); | ||
103 | |||
104 | return mlen; | ||
105 | } | ||
106 | |||
107 | void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg) | ||
108 | { | ||
109 | if (msg->errno >= 0) | ||
110 | return; | ||
111 | wake_up(&bl_wq); | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Decodes pnfs_block_deviceaddr4 which is XDR encoded in dev->dev_addr_buf. | ||
116 | */ | ||
117 | struct pnfs_block_dev * | ||
118 | nfs4_blk_decode_device(struct nfs_server *server, | ||
119 | struct pnfs_device *dev, | ||
120 | struct list_head *sdlist) | ||
121 | { | ||
122 | struct pnfs_block_dev *rv = NULL; | ||
123 | struct block_device *bd = NULL; | ||
124 | struct rpc_pipe_msg msg; | ||
125 | struct bl_msg_hdr bl_msg = { | ||
126 | .type = BL_DEVICE_MOUNT, | ||
127 | .totallen = dev->mincount, | ||
128 | }; | ||
129 | uint8_t *dataptr; | ||
130 | DECLARE_WAITQUEUE(wq, current); | ||
131 | struct bl_dev_msg *reply = &bl_mount_reply; | ||
132 | |||
133 | dprintk("%s CREATING PIPEFS MESSAGE\n", __func__); | ||
134 | dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data, | ||
135 | dev->mincount); | ||
136 | |||
137 | memset(&msg, 0, sizeof(msg)); | ||
138 | msg.data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS); | ||
139 | if (!msg.data) { | ||
140 | rv = ERR_PTR(-ENOMEM); | ||
141 | goto out; | ||
142 | } | ||
143 | |||
144 | memcpy(msg.data, &bl_msg, sizeof(bl_msg)); | ||
145 | dataptr = (uint8_t *) msg.data; | ||
146 | memcpy(&dataptr[sizeof(bl_msg)], dev->area, dev->mincount); | ||
147 | msg.len = sizeof(bl_msg) + dev->mincount; | ||
148 | |||
149 | dprintk("%s CALLING USERSPACE DAEMON\n", __func__); | ||
150 | add_wait_queue(&bl_wq, &wq); | ||
151 | if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) { | ||
152 | remove_wait_queue(&bl_wq, &wq); | ||
153 | goto out; | ||
154 | } | ||
155 | |||
156 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
157 | schedule(); | ||
158 | __set_current_state(TASK_RUNNING); | ||
159 | remove_wait_queue(&bl_wq, &wq); | ||
160 | |||
161 | if (reply->status != BL_DEVICE_REQUEST_PROC) { | ||
162 | dprintk("%s failed to open device: %d\n", | ||
163 | __func__, reply->status); | ||
164 | rv = ERR_PTR(-EINVAL); | ||
165 | goto out; | ||
166 | } | ||
167 | |||
168 | bd = nfs4_blkdev_get(MKDEV(reply->major, reply->minor)); | ||
169 | if (IS_ERR(bd)) { | ||
170 | dprintk("%s failed to open device : %ld\n", | ||
171 | __func__, PTR_ERR(bd)); | ||
172 | goto out; | ||
173 | } | ||
174 | |||
175 | rv = kzalloc(sizeof(*rv), GFP_NOFS); | ||
176 | if (!rv) { | ||
177 | rv = ERR_PTR(-ENOMEM); | ||
178 | goto out; | ||
179 | } | ||
180 | |||
181 | rv->bm_mdev = bd; | ||
182 | memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid)); | ||
183 | dprintk("%s Created device %s with bd_block_size %u\n", | ||
184 | __func__, | ||
185 | bd->bd_disk->disk_name, | ||
186 | bd->bd_block_size); | ||
187 | |||
188 | out: | ||
189 | kfree(msg.data); | ||
190 | return rv; | ||
191 | } | ||
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index de00a373f085..5833fbbf59b0 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -105,7 +105,7 @@ struct rpc_program nfs_program = { | |||
105 | .nrvers = ARRAY_SIZE(nfs_version), | 105 | .nrvers = ARRAY_SIZE(nfs_version), |
106 | .version = nfs_version, | 106 | .version = nfs_version, |
107 | .stats = &nfs_rpcstat, | 107 | .stats = &nfs_rpcstat, |
108 | .pipe_dir_name = "/nfs", | 108 | .pipe_dir_name = NFS_PIPE_DIRNAME, |
109 | }; | 109 | }; |
110 | 110 | ||
111 | struct rpc_stat nfs_rpcstat = { | 111 | struct rpc_stat nfs_rpcstat = { |
diff --git a/include/linux/nfs.h b/include/linux/nfs.h index f387919bbc59..8c6ee44914cb 100644 --- a/include/linux/nfs.h +++ b/include/linux/nfs.h | |||
@@ -29,6 +29,8 @@ | |||
29 | #define NFS_MNT_VERSION 1 | 29 | #define NFS_MNT_VERSION 1 |
30 | #define NFS_MNT3_VERSION 3 | 30 | #define NFS_MNT3_VERSION 3 |
31 | 31 | ||
32 | #define NFS_PIPE_DIRNAME "/nfs" | ||
33 | |||
32 | /* | 34 | /* |
33 | * NFS stats. The good thing with these values is that NFSv3 errors are | 35 | * NFS stats. The good thing with these values is that NFSv3 errors are |
34 | * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which | 36 | * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which |