]> git.karo-electronics.de Git - mv-sheeva.git/blob - fs/nfs/blocklayout/blocklayoutdev.c
b23fe601d1c95d2876ebd8a16c84cfb3cc9afc53
[mv-sheeva.git] / fs / nfs / blocklayout / blocklayoutdev.c
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 {
121         struct pnfs_block_dev *rv = NULL;
122         struct block_device *bd = NULL;
123         struct rpc_pipe_msg msg;
124         struct bl_msg_hdr bl_msg = {
125                 .type = BL_DEVICE_MOUNT,
126                 .totallen = dev->mincount,
127         };
128         uint8_t *dataptr;
129         DECLARE_WAITQUEUE(wq, current);
130         struct bl_dev_msg *reply = &bl_mount_reply;
131         int offset, len, i;
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         len = dev->mincount;
147         offset = sizeof(bl_msg);
148         for (i = 0; len > 0; i++) {
149                 memcpy(&dataptr[offset], page_address(dev->pages[i]),
150                                 len < PAGE_CACHE_SIZE ? len : PAGE_CACHE_SIZE);
151                 len -= PAGE_CACHE_SIZE;
152                 offset += PAGE_CACHE_SIZE;
153         }
154         msg.len = sizeof(bl_msg) + dev->mincount;
155
156         dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
157         add_wait_queue(&bl_wq, &wq);
158         if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) {
159                 remove_wait_queue(&bl_wq, &wq);
160                 goto out;
161         }
162
163         set_current_state(TASK_UNINTERRUPTIBLE);
164         schedule();
165         __set_current_state(TASK_RUNNING);
166         remove_wait_queue(&bl_wq, &wq);
167
168         if (reply->status != BL_DEVICE_REQUEST_PROC) {
169                 dprintk("%s failed to open device: %d\n",
170                         __func__, reply->status);
171                 rv = ERR_PTR(-EINVAL);
172                 goto out;
173         }
174
175         bd = nfs4_blkdev_get(MKDEV(reply->major, reply->minor));
176         if (IS_ERR(bd)) {
177                 dprintk("%s failed to open device : %ld\n",
178                         __func__, PTR_ERR(bd));
179                 goto out;
180         }
181
182         rv = kzalloc(sizeof(*rv), GFP_NOFS);
183         if (!rv) {
184                 rv = ERR_PTR(-ENOMEM);
185                 goto out;
186         }
187
188         rv->bm_mdev = bd;
189         memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid));
190         dprintk("%s Created device %s with bd_block_size %u\n",
191                 __func__,
192                 bd->bd_disk->disk_name,
193                 bd->bd_block_size);
194
195 out:
196         kfree(msg.data);
197         return rv;
198 }
199
200 int
201 nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,
202                            struct nfs4_layoutget_res *lgr, gfp_t gfp_flags)
203 {
204         /* STUB */
205         return -EIO;
206 }