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. 10 * 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. 14 * 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 21 */ 22 23 #include "fs.h" 24 #include "vnode.h" 25 #include "file.h" 26 #include <string.h> 27 #include <assert.h> 28 29 /* 30 * Send a request to a block device, and suspend the current thread until a 31 * reply from the driver comes in. 32 */ 33 static int 34 bdev_sendrec(endpoint_t driver_e, message * mess_ptr) 35 { 36 int r, status, retry_count; 37 message mess_retry; 38 39 assert(IS_BDEV_RQ(mess_ptr->m_type)); 40 mess_retry = *mess_ptr; 41 retry_count = 0; 42 43 do { 44 r = drv_sendrec(driver_e, mess_ptr); 45 if (r != OK) 46 return r; 47 48 status = mess_ptr->m_lblockdriver_lbdev_reply.status; 49 if (status == ERESTART) { 50 r = EDEADEPT; 51 *mess_ptr = mess_retry; 52 retry_count++; 53 } 54 } while (status == ERESTART && retry_count < 5); 55 56 /* If we failed to restart the request, return EIO. */ 57 if (status == ERESTART && retry_count >= 5) 58 return EIO; 59 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; 68 } 69 panic("VFS: uncaught bdev_sendrec failure: %d", r); 70 } 71 72 return OK; 73 } 74 75 /* 76 * Open a block device. 77 */ 78 int 79 bdev_open(dev_t dev, int bits) 80 { 81 devmajor_t major_dev; 82 devminor_t minor_dev; 83 message dev_mess; 84 int r, access; 85 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; 90 91 access = 0; 92 if (bits & R_BIT) access |= BDEV_R_BIT; 93 if (bits & W_BIT) access |= BDEV_W_BIT; 94 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; 101 102 /* Call the driver. */ 103 r = bdev_sendrec(dmap[major_dev].dmap_driver, &dev_mess); 104 if (r != OK) 105 return r; 106 107 return dev_mess.m_lblockdriver_lbdev_reply.status; 108 } 109 110 /* 111 * Close a block device. 112 */ 113 int 114 bdev_close(dev_t dev) 115 { 116 devmajor_t major_dev; 117 devminor_t minor_dev; 118 message dev_mess; 119 int r; 120 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; 125 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; 131 132 /* Call the driver. */ 133 r = bdev_sendrec(dmap[major_dev].dmap_driver, &dev_mess); 134 if (r != OK) 135 return r; 136 137 return dev_mess.m_lblockdriver_lbdev_reply.status; 138 } 139 140 /* 141 * Perform an I/O control operation on a block device. 142 */ 143 int 144 bdev_ioctl(dev_t dev, endpoint_t proc_e, unsigned long req, vir_bytes buf) 145 { 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; 152 153 major_dev = major(dev); 154 minor_dev = minor(dev); 155 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; 161 } 162 163 /* Set up a grant if necessary. */ 164 grant = make_ioctl_grant(dp->dmap_driver, proc_e, buf, req); 165 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; 174 175 /* Call the driver. */ 176 r = bdev_sendrec(dp->dmap_driver, &dev_mess); 177 178 /* Clean up. */ 179 if (GRANT_VALID(grant)) cpf_revoke(grant); 180 181 /* Return the result. */ 182 if (r != OK) 183 return r; 184 185 return dev_mess.m_lblockdriver_lbdev_reply.status; 186 } 187 188 /* 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. 191 */ 192 void 193 bdev_reply(void) 194 { 195 struct worker_thread *wp; 196 struct dmap *dp; 197 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; 202 } 203 204 if (dp->dmap_servicing == INVALID_THREAD) { 205 printf("VFS: ignoring spurious block dev reply from %d\n", 206 who_e); 207 return; 208 } 209 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; 215 } 216 217 *wp->w_drv_sendrec = m_in; 218 wp->w_drv_sendrec = NULL; 219 worker_signal(wp); 220 } 221 222 /* 223 * A new block device driver has been mapped in. This may affect both mounted 224 * file systems and open block-special files. 225 */ 226 void 227 bdev_up(devmajor_t maj) 228 { 229 int r, found, bits; 230 struct filp *rfilp; 231 struct vmnt *vmp; 232 struct vnode *vp; 233 char *label; 234 235 if (maj < 0 || maj >= NR_DEVICES) panic("VFS: out-of-bound major"); 236 label = dmap[maj].dmap_label; 237 found = 0; 238 239 /* 240 * For each block-special file that was previously opened on the 241 * affected device, we need to reopen it on the new driver. 242 */ 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; 248 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 */ 256 } 257 258 found = 1; 259 } 260 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; 264 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); 269 } 270 271 /* 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. 276 */ 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); 281 } 282 } 283