Remove building with NOCRYPTO option
[minix3.git] / minix / servers / vfs / bdev.c
blob714e246484fb42f198a6cd592437dee6a93c2cc4
1 /*
2 * This file contains routines to perform certain block device operations.
3 * These routines are called when a user application opens or closes a block
4 * device node, or performs an ioctl(2) call on such an opened node. Reading
5 * and writing on an opened block device is routed through the file system
6 * service that has mounted that block device, or the root file system service
7 * if the block device is not mounted. All block device operations by file
8 * system services themselves are going directly to the block device, and not
9 * through VFS.
11 * Block device drivers may not suspend operations for later processing, and
12 * thus, block device operations simply block their calling thread for the
13 * duration of the operation.
15 * The entry points in this file are:
16 * bdev_open: open a block device
17 * bdev_close: close a block device
18 * bdev_ioctl: issue an I/O control request on a block device
19 * bdev_reply: process the result of a block driver request
20 * bdev_up: a block driver has been mapped in
23 #include "fs.h"
24 #include "vnode.h"
25 #include "file.h"
26 #include <string.h>
27 #include <assert.h>
30 * Send a request to a block device, and suspend the current thread until a
31 * reply from the driver comes in.
33 static int
34 bdev_sendrec(endpoint_t driver_e, message * mess_ptr)
36 int r, status, retry_count;
37 message mess_retry;
39 assert(IS_BDEV_RQ(mess_ptr->m_type));
40 mess_retry = *mess_ptr;
41 retry_count = 0;
43 do {
44 r = drv_sendrec(driver_e, mess_ptr);
45 if (r != OK)
46 return r;
48 status = mess_ptr->m_lblockdriver_lbdev_reply.status;
49 if (status == ERESTART) {
50 r = EDEADEPT;
51 *mess_ptr = mess_retry;
52 retry_count++;
54 } while (status == ERESTART && retry_count < 5);
56 /* If we failed to restart the request, return EIO. */
57 if (status == ERESTART && retry_count >= 5)
58 return EIO;
60 if (r != OK) {
61 if (r == EDEADSRCDST || r == EDEADEPT) {
62 printf("VFS: dead driver %d\n", driver_e);
63 dmap_unmap_by_endpt(driver_e);
64 return EIO;
65 } else if (r == ELOCKED) {
66 printf("VFS: deadlock talking to %d\n", driver_e);
67 return EIO;
69 panic("VFS: uncaught bdev_sendrec failure: %d", r);
72 return OK;
76 * Open a block device.
78 int
79 bdev_open(dev_t dev, int bits)
81 devmajor_t major_dev;
82 devminor_t minor_dev;
83 message dev_mess;
84 int r, access;
86 major_dev = major(dev);
87 minor_dev = minor(dev);
88 if (major_dev < 0 || major_dev >= NR_DEVICES) return ENXIO;
89 if (dmap[major_dev].dmap_driver == NONE) return ENXIO;
91 access = 0;
92 if (bits & R_BIT) access |= BDEV_R_BIT;
93 if (bits & W_BIT) access |= BDEV_W_BIT;
95 /* Set up the message passed to the driver. */
96 memset(&dev_mess, 0, sizeof(dev_mess));
97 dev_mess.m_type = BDEV_OPEN;
98 dev_mess.m_lbdev_lblockdriver_msg.minor = minor_dev;
99 dev_mess.m_lbdev_lblockdriver_msg.access = access;
100 dev_mess.m_lbdev_lblockdriver_msg.id = 0;
102 /* Call the driver. */
103 r = bdev_sendrec(dmap[major_dev].dmap_driver, &dev_mess);
104 if (r != OK)
105 return r;
107 return dev_mess.m_lblockdriver_lbdev_reply.status;
111 * Close a block device.
114 bdev_close(dev_t dev)
116 devmajor_t major_dev;
117 devminor_t minor_dev;
118 message dev_mess;
119 int r;
121 major_dev = major(dev);
122 minor_dev = minor(dev);
123 if (major_dev < 0 || major_dev >= NR_DEVICES) return ENXIO;
124 if (dmap[major_dev].dmap_driver == NONE) return ENXIO;
126 /* Set up the message passed to the driver. */
127 memset(&dev_mess, 0, sizeof(dev_mess));
128 dev_mess.m_type = BDEV_CLOSE;
129 dev_mess.m_lbdev_lblockdriver_msg.minor = minor_dev;
130 dev_mess.m_lbdev_lblockdriver_msg.id = 0;
132 /* Call the driver. */
133 r = bdev_sendrec(dmap[major_dev].dmap_driver, &dev_mess);
134 if (r != OK)
135 return r;
137 return dev_mess.m_lblockdriver_lbdev_reply.status;
141 * Perform an I/O control operation on a block device.
144 bdev_ioctl(dev_t dev, endpoint_t proc_e, unsigned long req, vir_bytes buf)
146 struct dmap *dp;
147 cp_grant_id_t grant;
148 message dev_mess;
149 devmajor_t major_dev;
150 devminor_t minor_dev;
151 int r;
153 major_dev = major(dev);
154 minor_dev = minor(dev);
156 /* Determine driver dmap. */
157 dp = &dmap[major_dev];
158 if (dp->dmap_driver == NONE) {
159 printf("VFS: bdev_ioctl: no driver for major %d\n", major_dev);
160 return ENXIO;
163 /* Set up a grant if necessary. */
164 grant = make_ioctl_grant(dp->dmap_driver, proc_e, buf, req);
166 /* Set up the message passed to the driver. */
167 memset(&dev_mess, 0, sizeof(dev_mess));
168 dev_mess.m_type = BDEV_IOCTL;
169 dev_mess.m_lbdev_lblockdriver_msg.minor = minor_dev;
170 dev_mess.m_lbdev_lblockdriver_msg.request = req;
171 dev_mess.m_lbdev_lblockdriver_msg.grant = grant;
172 dev_mess.m_lbdev_lblockdriver_msg.user = proc_e;
173 dev_mess.m_lbdev_lblockdriver_msg.id = 0;
175 /* Call the driver. */
176 r = bdev_sendrec(dp->dmap_driver, &dev_mess);
178 /* Clean up. */
179 if (GRANT_VALID(grant)) cpf_revoke(grant);
181 /* Return the result. */
182 if (r != OK)
183 return r;
185 return dev_mess.m_lblockdriver_lbdev_reply.status;
189 * A block driver has results for a call. There must be a thread waiting for
190 * these results; wake it up. This function MUST NOT block its calling thread.
192 void
193 bdev_reply(void)
195 struct worker_thread *wp;
196 struct dmap *dp;
198 if ((dp = get_dmap_by_endpt(who_e)) == NULL) {
199 printf("VFS: ignoring block dev reply from unknown driver "
200 "%d\n", who_e);
201 return;
204 if (dp->dmap_servicing == INVALID_THREAD) {
205 printf("VFS: ignoring spurious block dev reply from %d\n",
206 who_e);
207 return;
210 wp = worker_get(dp->dmap_servicing);
211 if (wp == NULL || wp->w_task != who_e || wp->w_drv_sendrec == NULL) {
212 printf("VFS: no worker thread waiting for a reply from %d\n",
213 who_e);
214 return;
217 *wp->w_drv_sendrec = m_in;
218 wp->w_drv_sendrec = NULL;
219 worker_signal(wp);
223 * A new block device driver has been mapped in. This may affect both mounted
224 * file systems and open block-special files.
226 void
227 bdev_up(devmajor_t maj)
229 int r, found, bits;
230 struct filp *rfilp;
231 struct vmnt *vmp;
232 struct vnode *vp;
233 char *label;
235 if (maj < 0 || maj >= NR_DEVICES) panic("VFS: out-of-bound major");
236 label = dmap[maj].dmap_label;
237 found = 0;
240 * For each block-special file that was previously opened on the
241 * affected device, we need to reopen it on the new driver.
243 for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) {
244 if (rfilp->filp_count < 1) continue;
245 if ((vp = rfilp->filp_vno) == NULL) continue;
246 if (major(vp->v_sdev) != maj) continue;
247 if (!S_ISBLK(vp->v_mode)) continue;
249 /* Reopen the device on the driver, once per filp. */
250 bits = rfilp->filp_mode & (R_BIT | W_BIT);
251 if ((r = bdev_open(vp->v_sdev, bits)) != OK) {
252 printf("VFS: mounted dev %d/%d re-open failed: %d\n",
253 maj, minor(vp->v_sdev), r);
254 dmap[maj].dmap_recovering = 0;
255 return; /* Give up entirely */
258 found = 1;
261 /* Tell each affected mounted file system about the new endpoint. */
262 for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp) {
263 if (major(vmp->m_dev) != maj) continue;
265 /* Send the driver label to the mounted file system. */
266 if (req_newdriver(vmp->m_fs_e, vmp->m_dev, label) != OK)
267 printf("VFS: error sending new driver label to %d\n",
268 vmp->m_fs_e);
272 * If any block-special file was open for this major at all, also
273 * inform the root file system about the new driver. We do this even
274 * if the block-special file is linked to another mounted file system,
275 * merely because it is more work to check for that case.
277 if (found) {
278 if (req_newdriver(ROOT_FS_E, makedev(maj, 0), label) != OK)
279 printf("VFS: error sending new driver label to %d\n",
280 ROOT_FS_E);