| [9] | 1 | /* When a needed block is not in the cache, it must be fetched from the disk. | 
|---|
|  | 2 | * Special character files also require I/O.  The routines for these are here. | 
|---|
|  | 3 | * | 
|---|
|  | 4 | * The entry points in this file are: | 
|---|
|  | 5 | *   dev_open:   FS opens a device | 
|---|
|  | 6 | *   dev_close:  FS closes a device | 
|---|
|  | 7 | *   dev_io:     FS does a read or write on a device | 
|---|
|  | 8 | *   dev_status: FS processes callback request alert | 
|---|
|  | 9 | *   gen_opcl:   generic call to a task to perform an open/close | 
|---|
|  | 10 | *   gen_io:     generic call to a task to perform an I/O operation | 
|---|
|  | 11 | *   no_dev:     open/close processing for devices that don't exist | 
|---|
|  | 12 | *   no_dev_io:  i/o processing for devices that don't exist | 
|---|
|  | 13 | *   tty_opcl:   perform tty-specific processing for open/close | 
|---|
|  | 14 | *   ctty_opcl:  perform controlling-tty-specific processing for open/close | 
|---|
|  | 15 | *   ctty_io:    perform controlling-tty-specific processing for I/O | 
|---|
|  | 16 | *   do_ioctl:   perform the IOCTL system call | 
|---|
|  | 17 | *   do_setsid:  perform the SETSID system call (FS side) | 
|---|
|  | 18 | */ | 
|---|
|  | 19 |  | 
|---|
|  | 20 | #include "fs.h" | 
|---|
|  | 21 | #include <fcntl.h> | 
|---|
|  | 22 | #include <minix/callnr.h> | 
|---|
|  | 23 | #include <minix/com.h> | 
|---|
|  | 24 | #include <minix/endpoint.h> | 
|---|
|  | 25 | #include "file.h" | 
|---|
|  | 26 | #include "fproc.h" | 
|---|
|  | 27 | #include "inode.h" | 
|---|
|  | 28 | #include "param.h" | 
|---|
|  | 29 | #include "super.h" | 
|---|
|  | 30 |  | 
|---|
|  | 31 | #define ELEMENTS(a) (sizeof(a)/sizeof((a)[0])) | 
|---|
|  | 32 |  | 
|---|
|  | 33 | extern int dmap_size; | 
|---|
|  | 34 | PRIVATE int dummyproc; | 
|---|
|  | 35 |  | 
|---|
|  | 36 | /*===========================================================================* | 
|---|
|  | 37 | *                              dev_open                                     * | 
|---|
|  | 38 | *===========================================================================*/ | 
|---|
|  | 39 | PUBLIC int dev_open(dev, proc, flags) | 
|---|
|  | 40 | dev_t dev;                      /* device to open */ | 
|---|
|  | 41 | int proc;                       /* process to open for */ | 
|---|
|  | 42 | int flags;                      /* mode bits and flags */ | 
|---|
|  | 43 | { | 
|---|
|  | 44 | int major, r; | 
|---|
|  | 45 | struct dmap *dp; | 
|---|
|  | 46 |  | 
|---|
|  | 47 | /* Determine the major device number call the device class specific | 
|---|
|  | 48 | * open/close routine.  (This is the only routine that must check the | 
|---|
|  | 49 | * device number for being in range.  All others can trust this check.) | 
|---|
|  | 50 | */ | 
|---|
|  | 51 | major = (dev >> MAJOR) & BYTE; | 
|---|
|  | 52 | if (major >= NR_DEVICES) major = 0; | 
|---|
|  | 53 | dp = &dmap[major]; | 
|---|
|  | 54 | if (dp->dmap_driver == NONE) | 
|---|
|  | 55 | return ENXIO; | 
|---|
|  | 56 | r = (*dp->dmap_opcl)(DEV_OPEN, dev, proc, flags); | 
|---|
|  | 57 | if (r == SUSPEND) panic(__FILE__,"suspend on open from", dp->dmap_driver); | 
|---|
|  | 58 | return(r); | 
|---|
|  | 59 | } | 
|---|
|  | 60 |  | 
|---|
|  | 61 | /*===========================================================================* | 
|---|
|  | 62 | *                              dev_close                                    * | 
|---|
|  | 63 | *===========================================================================*/ | 
|---|
|  | 64 | PUBLIC void dev_close(dev) | 
|---|
|  | 65 | dev_t dev;                      /* device to close */ | 
|---|
|  | 66 | { | 
|---|
|  | 67 | /* See if driver is roughly valid. */ | 
|---|
|  | 68 | if (dmap[(dev >> MAJOR)].dmap_driver == NONE) { | 
|---|
|  | 69 | return; | 
|---|
|  | 70 | } | 
|---|
|  | 71 | (void) (*dmap[(dev >> MAJOR) & BYTE].dmap_opcl)(DEV_CLOSE, dev, 0, 0); | 
|---|
|  | 72 | } | 
|---|
|  | 73 |  | 
|---|
|  | 74 | /*===========================================================================* | 
|---|
|  | 75 | *                              dev_status                                      * | 
|---|
|  | 76 | *===========================================================================*/ | 
|---|
|  | 77 | PUBLIC void dev_status(message *m) | 
|---|
|  | 78 | { | 
|---|
|  | 79 | message st; | 
|---|
|  | 80 | int d, get_more = 1; | 
|---|
|  | 81 |  | 
|---|
|  | 82 | for(d = 0; d < NR_DEVICES; d++) | 
|---|
|  | 83 | if (dmap[d].dmap_driver != NONE && | 
|---|
|  | 84 | dmap[d].dmap_driver == m->m_source) | 
|---|
|  | 85 | break; | 
|---|
|  | 86 |  | 
|---|
|  | 87 | if (d >= NR_DEVICES) | 
|---|
|  | 88 | return; | 
|---|
|  | 89 |  | 
|---|
|  | 90 | do { | 
|---|
|  | 91 | int r; | 
|---|
|  | 92 | st.m_type = DEV_STATUS; | 
|---|
|  | 93 | if ((r=sendrec(m->m_source, &st)) != OK) { | 
|---|
|  | 94 | printf("DEV_STATUS failed to %d: %d\n", m->m_source, r); | 
|---|
|  | 95 | if (r == EDEADSRCDST) return; | 
|---|
|  | 96 | if (r == EDSTDIED) return; | 
|---|
|  | 97 | if (r == ESRCDIED) return; | 
|---|
|  | 98 | panic(__FILE__,"couldn't sendrec for DEV_STATUS", r); | 
|---|
|  | 99 | } | 
|---|
|  | 100 |  | 
|---|
|  | 101 | switch(st.m_type) { | 
|---|
|  | 102 | case DEV_REVIVE: | 
|---|
|  | 103 | revive(st.REP_ENDPT, st.REP_STATUS); | 
|---|
|  | 104 | break; | 
|---|
|  | 105 | case DEV_IO_READY: | 
|---|
|  | 106 | select_notified(d, st.DEV_MINOR, st.DEV_SEL_OPS); | 
|---|
|  | 107 | break; | 
|---|
|  | 108 | default: | 
|---|
|  | 109 | printf("FS: unrecognized reply %d to DEV_STATUS\n", st.m_type); | 
|---|
|  | 110 | /* Fall through. */ | 
|---|
|  | 111 | case DEV_NO_STATUS: | 
|---|
|  | 112 | get_more = 0; | 
|---|
|  | 113 | break; | 
|---|
|  | 114 | } | 
|---|
|  | 115 | } while(get_more); | 
|---|
|  | 116 |  | 
|---|
|  | 117 | return; | 
|---|
|  | 118 | } | 
|---|
|  | 119 |  | 
|---|
|  | 120 | /*===========================================================================* | 
|---|
|  | 121 | *                              dev_io                                       * | 
|---|
|  | 122 | *===========================================================================*/ | 
|---|
|  | 123 | PUBLIC int dev_io(op, dev, proc_e, buf, pos, bytes, flags) | 
|---|
|  | 124 | int op;                         /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */ | 
|---|
|  | 125 | dev_t dev;                      /* major-minor device number */ | 
|---|
|  | 126 | int proc_e;                     /* in whose address space is buf? */ | 
|---|
|  | 127 | void *buf;                      /* virtual address of the buffer */ | 
|---|
|  | 128 | off_t pos;                      /* byte position */ | 
|---|
|  | 129 | int bytes;                      /* how many bytes to transfer */ | 
|---|
|  | 130 | int flags;                      /* special flags, like O_NONBLOCK */ | 
|---|
|  | 131 | { | 
|---|
|  | 132 | /* Read or write from a device.  The parameter 'dev' tells which one. */ | 
|---|
|  | 133 | struct dmap *dp; | 
|---|
|  | 134 | message dev_mess; | 
|---|
|  | 135 |  | 
|---|
|  | 136 | /* Determine task dmap. */ | 
|---|
|  | 137 | dp = &dmap[(dev >> MAJOR) & BYTE]; | 
|---|
|  | 138 |  | 
|---|
|  | 139 | /* See if driver is roughly valid. */ | 
|---|
|  | 140 | if (dp->dmap_driver == NONE) { | 
|---|
|  | 141 | printf("FS: dev_io: no driver for dev %x\n", dev); | 
|---|
|  | 142 | return ENXIO; | 
|---|
|  | 143 | } | 
|---|
|  | 144 |  | 
|---|
|  | 145 | if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { | 
|---|
|  | 146 | printf("FS: dev_io: old driver for dev %x (%d)\n", | 
|---|
|  | 147 | dev, dp->dmap_driver); | 
|---|
|  | 148 | return ENXIO; | 
|---|
|  | 149 | } | 
|---|
|  | 150 |  | 
|---|
|  | 151 | /* Set up the message passed to task. */ | 
|---|
|  | 152 | dev_mess.m_type   = op; | 
|---|
|  | 153 | dev_mess.DEVICE   = (dev >> MINOR) & BYTE; | 
|---|
|  | 154 | dev_mess.POSITION = pos; | 
|---|
|  | 155 | dev_mess.IO_ENDPT = proc_e; | 
|---|
|  | 156 | dev_mess.ADDRESS  = buf; | 
|---|
|  | 157 | dev_mess.COUNT    = bytes; | 
|---|
|  | 158 | dev_mess.TTY_FLAGS = flags; | 
|---|
|  | 159 |  | 
|---|
|  | 160 | /* Call the task. */ | 
|---|
|  | 161 | (*dp->dmap_io)(dp->dmap_driver, &dev_mess); | 
|---|
|  | 162 |  | 
|---|
|  | 163 | if(dp->dmap_driver == NONE) { | 
|---|
|  | 164 | /* Driver has vanished. */ | 
|---|
|  | 165 | return EIO; | 
|---|
|  | 166 | } | 
|---|
|  | 167 |  | 
|---|
|  | 168 | /* Task has completed.  See if call completed. */ | 
|---|
|  | 169 | if (dev_mess.REP_STATUS == SUSPEND) { | 
|---|
|  | 170 | if (flags & O_NONBLOCK) { | 
|---|
|  | 171 | /* Not supposed to block. */ | 
|---|
|  | 172 | dev_mess.m_type = CANCEL; | 
|---|
|  | 173 | dev_mess.IO_ENDPT = proc_e; | 
|---|
|  | 174 | dev_mess.DEVICE = (dev >> MINOR) & BYTE; | 
|---|
|  | 175 | (*dp->dmap_io)(dp->dmap_driver, &dev_mess); | 
|---|
|  | 176 | if (dev_mess.REP_STATUS == EINTR) dev_mess.REP_STATUS = EAGAIN; | 
|---|
|  | 177 | } else { | 
|---|
|  | 178 | /* Suspend user. */ | 
|---|
|  | 179 | suspend(dp->dmap_driver); | 
|---|
|  | 180 | return(SUSPEND); | 
|---|
|  | 181 | } | 
|---|
|  | 182 | } | 
|---|
|  | 183 | return(dev_mess.REP_STATUS); | 
|---|
|  | 184 | } | 
|---|
|  | 185 |  | 
|---|
|  | 186 | /*===========================================================================* | 
|---|
|  | 187 | *                              gen_opcl                                     * | 
|---|
|  | 188 | *===========================================================================*/ | 
|---|
|  | 189 | PUBLIC int gen_opcl(op, dev, proc_e, flags) | 
|---|
|  | 190 | int op;                         /* operation, DEV_OPEN or DEV_CLOSE */ | 
|---|
|  | 191 | dev_t dev;                      /* device to open or close */ | 
|---|
|  | 192 | int proc_e;                     /* process to open/close for */ | 
|---|
|  | 193 | int flags;                      /* mode bits and flags */ | 
|---|
|  | 194 | { | 
|---|
|  | 195 | /* Called from the dmap struct in table.c on opens & closes of special files.*/ | 
|---|
|  | 196 | struct dmap *dp; | 
|---|
|  | 197 | message dev_mess; | 
|---|
|  | 198 |  | 
|---|
|  | 199 | /* Determine task dmap. */ | 
|---|
|  | 200 | dp = &dmap[(dev >> MAJOR) & BYTE]; | 
|---|
|  | 201 |  | 
|---|
|  | 202 | dev_mess.m_type   = op; | 
|---|
|  | 203 | dev_mess.DEVICE   = (dev >> MINOR) & BYTE; | 
|---|
|  | 204 | dev_mess.IO_ENDPT = proc_e; | 
|---|
|  | 205 | dev_mess.COUNT    = flags; | 
|---|
|  | 206 |  | 
|---|
|  | 207 | if (dp->dmap_driver == NONE) { | 
|---|
|  | 208 | printf("FS: gen_opcl: no driver for dev %x\n", dev); | 
|---|
|  | 209 | return ENXIO; | 
|---|
|  | 210 | } | 
|---|
|  | 211 | if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { | 
|---|
|  | 212 | printf("FS: gen_opcl: old driver for dev %x (%d)\n", | 
|---|
|  | 213 | dev, dp->dmap_driver); | 
|---|
|  | 214 | return ENXIO; | 
|---|
|  | 215 | } | 
|---|
|  | 216 |  | 
|---|
|  | 217 | /* Call the task. */ | 
|---|
|  | 218 | (*dp->dmap_io)(dp->dmap_driver, &dev_mess); | 
|---|
|  | 219 |  | 
|---|
|  | 220 | return(dev_mess.REP_STATUS); | 
|---|
|  | 221 | } | 
|---|
|  | 222 |  | 
|---|
|  | 223 | /*===========================================================================* | 
|---|
|  | 224 | *                              tty_opcl                                     * | 
|---|
|  | 225 | *===========================================================================*/ | 
|---|
|  | 226 | PUBLIC int tty_opcl(op, dev, proc_e, flags) | 
|---|
|  | 227 | int op;                         /* operation, DEV_OPEN or DEV_CLOSE */ | 
|---|
|  | 228 | dev_t dev;                      /* device to open or close */ | 
|---|
|  | 229 | int proc_e;                     /* process to open/close for */ | 
|---|
|  | 230 | int flags;                      /* mode bits and flags */ | 
|---|
|  | 231 | { | 
|---|
|  | 232 | /* This procedure is called from the dmap struct on tty open/close. */ | 
|---|
|  | 233 |  | 
|---|
|  | 234 | int r; | 
|---|
|  | 235 | register struct fproc *rfp; | 
|---|
|  | 236 |  | 
|---|
|  | 237 | /* Add O_NOCTTY to the flags if this process is not a session leader, or | 
|---|
|  | 238 | * if it already has a controlling tty, or if it is someone elses | 
|---|
|  | 239 | * controlling tty. | 
|---|
|  | 240 | */ | 
|---|
|  | 241 | if (!fp->fp_sesldr || fp->fp_tty != 0) { | 
|---|
|  | 242 | flags |= O_NOCTTY; | 
|---|
|  | 243 | } else { | 
|---|
|  | 244 | for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) { | 
|---|
|  | 245 | if(rfp->fp_pid == PID_FREE) continue; | 
|---|
|  | 246 | if (rfp->fp_tty == dev) flags |= O_NOCTTY; | 
|---|
|  | 247 | } | 
|---|
|  | 248 | } | 
|---|
|  | 249 |  | 
|---|
|  | 250 | r = gen_opcl(op, dev, proc_e, flags); | 
|---|
|  | 251 |  | 
|---|
|  | 252 | /* Did this call make the tty the controlling tty? */ | 
|---|
|  | 253 | if (r == 1) { | 
|---|
|  | 254 | fp->fp_tty = dev; | 
|---|
|  | 255 | r = OK; | 
|---|
|  | 256 | } | 
|---|
|  | 257 | return(r); | 
|---|
|  | 258 | } | 
|---|
|  | 259 |  | 
|---|
|  | 260 | /*===========================================================================* | 
|---|
|  | 261 | *                              ctty_opcl                                    * | 
|---|
|  | 262 | *===========================================================================*/ | 
|---|
|  | 263 | PUBLIC int ctty_opcl(op, dev, proc_e, flags) | 
|---|
|  | 264 | int op;                         /* operation, DEV_OPEN or DEV_CLOSE */ | 
|---|
|  | 265 | dev_t dev;                      /* device to open or close */ | 
|---|
|  | 266 | int proc_e;                     /* process to open/close for */ | 
|---|
|  | 267 | int flags;                      /* mode bits and flags */ | 
|---|
|  | 268 | { | 
|---|
|  | 269 | /* This procedure is called from the dmap struct in table.c on opening/closing | 
|---|
|  | 270 | * /dev/tty, the magic device that translates to the controlling tty. | 
|---|
|  | 271 | */ | 
|---|
|  | 272 |  | 
|---|
|  | 273 | return(fp->fp_tty == 0 ? ENXIO : OK); | 
|---|
|  | 274 | } | 
|---|
|  | 275 |  | 
|---|
|  | 276 | /*===========================================================================* | 
|---|
|  | 277 | *                              do_setsid                                    * | 
|---|
|  | 278 | *===========================================================================*/ | 
|---|
|  | 279 | PUBLIC int do_setsid() | 
|---|
|  | 280 | { | 
|---|
|  | 281 | /* Perform the FS side of the SETSID call, i.e. get rid of the controlling | 
|---|
|  | 282 | * terminal of a process, and make the process a session leader. | 
|---|
|  | 283 | */ | 
|---|
|  | 284 | register struct fproc *rfp; | 
|---|
|  | 285 | int slot; | 
|---|
|  | 286 |  | 
|---|
|  | 287 | /* Only MM may do the SETSID call directly. */ | 
|---|
|  | 288 | if (who_e != PM_PROC_NR) return(ENOSYS); | 
|---|
|  | 289 |  | 
|---|
|  | 290 | /* Make the process a session leader with no controlling tty. */ | 
|---|
|  | 291 | okendpt(m_in.endpt1, &slot); | 
|---|
|  | 292 | rfp = &fproc[slot]; | 
|---|
|  | 293 | rfp->fp_sesldr = TRUE; | 
|---|
|  | 294 | rfp->fp_tty = 0; | 
|---|
|  | 295 | return(OK); | 
|---|
|  | 296 | } | 
|---|
|  | 297 |  | 
|---|
|  | 298 | /*===========================================================================* | 
|---|
|  | 299 | *                              do_ioctl                                     * | 
|---|
|  | 300 | *===========================================================================*/ | 
|---|
|  | 301 | PUBLIC int do_ioctl() | 
|---|
|  | 302 | { | 
|---|
|  | 303 | /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */ | 
|---|
|  | 304 |  | 
|---|
|  | 305 | struct filp *f; | 
|---|
|  | 306 | register struct inode *rip; | 
|---|
|  | 307 | dev_t dev; | 
|---|
|  | 308 |  | 
|---|
|  | 309 | if ( (f = get_filp(m_in.ls_fd)) == NIL_FILP) return(err_code); | 
|---|
|  | 310 | rip = f->filp_ino;            /* get inode pointer */ | 
|---|
|  | 311 | if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL | 
|---|
|  | 312 | && (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY); | 
|---|
|  | 313 | dev = (dev_t) rip->i_zone[0]; | 
|---|
|  | 314 |  | 
|---|
|  | 315 | #if ENABLE_BINCOMPAT | 
|---|
|  | 316 | if ((m_in.TTY_REQUEST >> 8) == 't') { | 
|---|
|  | 317 | /* Obsolete sgtty ioctl, message contains more than is sane. */ | 
|---|
|  | 318 | struct dmap *dp; | 
|---|
|  | 319 | message dev_mess; | 
|---|
|  | 320 |  | 
|---|
|  | 321 | dp = &dmap[(dev >> MAJOR) & BYTE]; | 
|---|
|  | 322 |  | 
|---|
|  | 323 | dev_mess = m;   /* Copy full message with all the weird bits. */ | 
|---|
|  | 324 | dev_mess.m_type   = DEV_IOCTL; | 
|---|
|  | 325 | dev_mess.PROC_NR  = who_e; | 
|---|
|  | 326 | dev_mess.TTY_LINE = (dev >> MINOR) & BYTE; | 
|---|
|  | 327 |  | 
|---|
|  | 328 | /* Call the task. */ | 
|---|
|  | 329 |  | 
|---|
|  | 330 | if (dp->dmap_driver == NONE) { | 
|---|
|  | 331 | printf("FS: do_ioctl: no driver for dev %x\n", dev); | 
|---|
|  | 332 | return ENXIO; | 
|---|
|  | 333 | } | 
|---|
|  | 334 |  | 
|---|
|  | 335 | if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { | 
|---|
|  | 336 | printf("FS: do_ioctl: old driver for dev %x (%d)\n", | 
|---|
|  | 337 | dev, dp->dmap_driver); | 
|---|
|  | 338 | return ENXIO; | 
|---|
|  | 339 | } | 
|---|
|  | 340 |  | 
|---|
|  | 341 | (*dp->dmap_io)(dp->dmap_driver, &dev_mess); | 
|---|
|  | 342 |  | 
|---|
|  | 343 | m_out.TTY_SPEK = dev_mess.TTY_SPEK;     /* erase and kill */ | 
|---|
|  | 344 | m_out.TTY_FLAGS = dev_mess.TTY_FLAGS;   /* flags */ | 
|---|
|  | 345 | return(dev_mess.REP_STATUS); | 
|---|
|  | 346 | } | 
|---|
|  | 347 | #endif | 
|---|
|  | 348 |  | 
|---|
|  | 349 | return(dev_io(DEV_IOCTL, dev, who_e, m_in.ADDRESS, 0L, | 
|---|
|  | 350 | m_in.REQUEST, f->filp_flags)); | 
|---|
|  | 351 | } | 
|---|
|  | 352 |  | 
|---|
|  | 353 | /*===========================================================================* | 
|---|
|  | 354 | *                              gen_io                                       * | 
|---|
|  | 355 | *===========================================================================*/ | 
|---|
|  | 356 | PUBLIC int gen_io(task_nr, mess_ptr) | 
|---|
|  | 357 | int task_nr;                    /* which task to call */ | 
|---|
|  | 358 | message *mess_ptr;              /* pointer to message for task */ | 
|---|
|  | 359 | { | 
|---|
|  | 360 | /* All file system I/O ultimately comes down to I/O on major/minor device | 
|---|
|  | 361 | * pairs.  These lead to calls on the following routines via the dmap table. | 
|---|
|  | 362 | */ | 
|---|
|  | 363 |  | 
|---|
|  | 364 | int r, proc_e; | 
|---|
|  | 365 |  | 
|---|
|  | 366 | proc_e = mess_ptr->IO_ENDPT; | 
|---|
|  | 367 |  | 
|---|
|  | 368 | #if DEAD_CODE | 
|---|
|  | 369 | while ((r = sendrec(task_nr, mess_ptr)) == ELOCKED) { | 
|---|
|  | 370 | /* sendrec() failed to avoid deadlock. The task 'task_nr' is | 
|---|
|  | 371 | * trying to send a REVIVE message for an earlier request. | 
|---|
|  | 372 | * Handle it and go try again. | 
|---|
|  | 373 | */ | 
|---|
|  | 374 | if ((r = receive(task_nr, &local_m)) != OK) { | 
|---|
|  | 375 | break; | 
|---|
|  | 376 | } | 
|---|
|  | 377 |  | 
|---|
|  | 378 | /* If we're trying to send a cancel message to a task which has just | 
|---|
|  | 379 | * sent a completion reply, ignore the reply and abort the cancel | 
|---|
|  | 380 | * request. The caller will do the revive for the process. | 
|---|
|  | 381 | */ | 
|---|
|  | 382 | if (mess_ptr->m_type == CANCEL && local_m.REP_ENDPT == proc_e) { | 
|---|
|  | 383 | return OK; | 
|---|
|  | 384 | } | 
|---|
|  | 385 |  | 
|---|
|  | 386 | /* Otherwise it should be a REVIVE. */ | 
|---|
|  | 387 | if (local_m.m_type != REVIVE) { | 
|---|
|  | 388 | printf( | 
|---|
|  | 389 | "fs: strange device reply from %d, type = %d, proc = %d (1)\n", | 
|---|
|  | 390 | local_m.m_source, | 
|---|
|  | 391 | local_m.m_type, local_m.REP_ENDPT); | 
|---|
|  | 392 | continue; | 
|---|
|  | 393 | } | 
|---|
|  | 394 |  | 
|---|
|  | 395 | revive(local_m.REP_ENDPT, local_m.REP_STATUS); | 
|---|
|  | 396 | } | 
|---|
|  | 397 | #endif | 
|---|
|  | 398 |  | 
|---|
|  | 399 | /* The message received may be a reply to this call, or a REVIVE for some | 
|---|
|  | 400 | * other process. | 
|---|
|  | 401 | */ | 
|---|
|  | 402 | r = sendrec(task_nr, mess_ptr); | 
|---|
|  | 403 | for(;;) { | 
|---|
|  | 404 | if (r != OK) { | 
|---|
|  | 405 | if (r == EDEADSRCDST || r == EDSTDIED || r == ESRCDIED) { | 
|---|
|  | 406 | printf("fs: dead driver %d\n", task_nr); | 
|---|
|  | 407 | dmap_unmap_by_endpt(task_nr); | 
|---|
|  | 408 | return r; | 
|---|
|  | 409 | } | 
|---|
|  | 410 | if (r == ELOCKED) { | 
|---|
|  | 411 | printf("fs: ELOCKED talking to %d\n", task_nr); | 
|---|
|  | 412 | return r; | 
|---|
|  | 413 | } | 
|---|
|  | 414 | panic(__FILE__,"call_task: can't send/receive", r); | 
|---|
|  | 415 | } | 
|---|
|  | 416 |  | 
|---|
|  | 417 | /* Did the process we did the sendrec() for get a result? */ | 
|---|
|  | 418 | if (mess_ptr->REP_ENDPT == proc_e) { | 
|---|
|  | 419 | break; | 
|---|
|  | 420 | } else if (mess_ptr->m_type == REVIVE) { | 
|---|
|  | 421 | /* Otherwise it should be a REVIVE. */ | 
|---|
|  | 422 | revive(mess_ptr->REP_ENDPT, mess_ptr->REP_STATUS); | 
|---|
|  | 423 | } else { | 
|---|
|  | 424 | printf( | 
|---|
|  | 425 | "fs: strange device reply from %d, type = %d, proc = %d (2) ignored\n", | 
|---|
|  | 426 | mess_ptr->m_source, | 
|---|
|  | 427 | mess_ptr->m_type, mess_ptr->REP_ENDPT); | 
|---|
|  | 428 | } | 
|---|
|  | 429 | r = receive(task_nr, mess_ptr); | 
|---|
|  | 430 | } | 
|---|
|  | 431 |  | 
|---|
|  | 432 | return OK; | 
|---|
|  | 433 | } | 
|---|
|  | 434 |  | 
|---|
|  | 435 | /*===========================================================================* | 
|---|
|  | 436 | *                              ctty_io                                      * | 
|---|
|  | 437 | *===========================================================================*/ | 
|---|
|  | 438 | PUBLIC int ctty_io(task_nr, mess_ptr) | 
|---|
|  | 439 | int task_nr;                    /* not used - for compatibility with dmap_t */ | 
|---|
|  | 440 | message *mess_ptr;              /* pointer to message for task */ | 
|---|
|  | 441 | { | 
|---|
|  | 442 | /* This routine is only called for one device, namely /dev/tty.  Its job | 
|---|
|  | 443 | * is to change the message to use the controlling terminal, instead of the | 
|---|
|  | 444 | * major/minor pair for /dev/tty itself. | 
|---|
|  | 445 | */ | 
|---|
|  | 446 |  | 
|---|
|  | 447 | struct dmap *dp; | 
|---|
|  | 448 |  | 
|---|
|  | 449 | if (fp->fp_tty == 0) { | 
|---|
|  | 450 | /* No controlling tty present anymore, return an I/O error. */ | 
|---|
|  | 451 | mess_ptr->REP_STATUS = EIO; | 
|---|
|  | 452 | } else { | 
|---|
|  | 453 | /* Substitute the controlling terminal device. */ | 
|---|
|  | 454 | dp = &dmap[(fp->fp_tty >> MAJOR) & BYTE]; | 
|---|
|  | 455 | mess_ptr->DEVICE = (fp->fp_tty >> MINOR) & BYTE; | 
|---|
|  | 456 |  | 
|---|
|  | 457 | if (dp->dmap_driver == NONE) { | 
|---|
|  | 458 | printf("FS: ctty_io: no driver for dev\n"); | 
|---|
|  | 459 | return EIO; | 
|---|
|  | 460 | } | 
|---|
|  | 461 |  | 
|---|
|  | 462 | if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { | 
|---|
|  | 463 | printf("FS: ctty_io: old driver %d\n", | 
|---|
|  | 464 | dp->dmap_driver); | 
|---|
|  | 465 | return EIO; | 
|---|
|  | 466 | } | 
|---|
|  | 467 |  | 
|---|
|  | 468 | (*dp->dmap_io)(dp->dmap_driver, mess_ptr); | 
|---|
|  | 469 | } | 
|---|
|  | 470 | return OK; | 
|---|
|  | 471 | } | 
|---|
|  | 472 |  | 
|---|
|  | 473 | /*===========================================================================* | 
|---|
|  | 474 | *                              no_dev                                       * | 
|---|
|  | 475 | *===========================================================================*/ | 
|---|
|  | 476 | PUBLIC int no_dev(op, dev, proc, flags) | 
|---|
|  | 477 | int op;                         /* operation, DEV_OPEN or DEV_CLOSE */ | 
|---|
|  | 478 | dev_t dev;                      /* device to open or close */ | 
|---|
|  | 479 | int proc;                       /* process to open/close for */ | 
|---|
|  | 480 | int flags;                      /* mode bits and flags */ | 
|---|
|  | 481 | { | 
|---|
|  | 482 | /* Called when opening a nonexistent device. */ | 
|---|
|  | 483 | return(ENODEV); | 
|---|
|  | 484 | } | 
|---|
|  | 485 |  | 
|---|
|  | 486 | /*===========================================================================* | 
|---|
|  | 487 | *                              no_dev_io                                    * | 
|---|
|  | 488 | *===========================================================================*/ | 
|---|
|  | 489 | PUBLIC int no_dev_io(int proc, message *m) | 
|---|
|  | 490 | { | 
|---|
|  | 491 | /* Called when doing i/o on a nonexistent device. */ | 
|---|
|  | 492 | printf("FS: I/O on unmapped device number\n"); | 
|---|
|  | 493 | return EIO; | 
|---|
|  | 494 | } | 
|---|
|  | 495 |  | 
|---|
|  | 496 | /*===========================================================================* | 
|---|
|  | 497 | *                              clone_opcl                                   * | 
|---|
|  | 498 | *===========================================================================*/ | 
|---|
|  | 499 | PUBLIC int clone_opcl(op, dev, proc_e, flags) | 
|---|
|  | 500 | int op;                         /* operation, DEV_OPEN or DEV_CLOSE */ | 
|---|
|  | 501 | dev_t dev;                      /* device to open or close */ | 
|---|
|  | 502 | int proc_e;                     /* process to open/close for */ | 
|---|
|  | 503 | int flags;                      /* mode bits and flags */ | 
|---|
|  | 504 | { | 
|---|
|  | 505 | /* Some devices need special processing upon open.  Such a device is "cloned", | 
|---|
|  | 506 | * i.e. on a succesful open it is replaced by a new device with a new unique | 
|---|
|  | 507 | * minor device number.  This new device number identifies a new object (such | 
|---|
|  | 508 | * as a new network connection) that has been allocated within a task. | 
|---|
|  | 509 | */ | 
|---|
|  | 510 | struct dmap *dp; | 
|---|
|  | 511 | int r, minor; | 
|---|
|  | 512 | message dev_mess; | 
|---|
|  | 513 |  | 
|---|
|  | 514 | /* Determine task dmap. */ | 
|---|
|  | 515 | dp = &dmap[(dev >> MAJOR) & BYTE]; | 
|---|
|  | 516 | minor = (dev >> MINOR) & BYTE; | 
|---|
|  | 517 |  | 
|---|
|  | 518 | dev_mess.m_type   = op; | 
|---|
|  | 519 | dev_mess.DEVICE   = minor; | 
|---|
|  | 520 | dev_mess.IO_ENDPT = proc_e; | 
|---|
|  | 521 | dev_mess.COUNT    = flags; | 
|---|
|  | 522 |  | 
|---|
|  | 523 |  | 
|---|
|  | 524 | if (dp->dmap_driver == NONE) { | 
|---|
|  | 525 | printf("FS: clone_opcl: no driver for dev %x\n", dev); | 
|---|
|  | 526 | return ENXIO; | 
|---|
|  | 527 | } | 
|---|
|  | 528 |  | 
|---|
|  | 529 | if(isokendpt(dp->dmap_driver, &dummyproc) != OK) { | 
|---|
|  | 530 | printf("FS: clone_opcl: old driver for dev %x (%d)\n", | 
|---|
|  | 531 | dev, dp->dmap_driver); | 
|---|
|  | 532 | return ENXIO; | 
|---|
|  | 533 | } | 
|---|
|  | 534 |  | 
|---|
|  | 535 | /* Call the task. */ | 
|---|
|  | 536 | r= (*dp->dmap_io)(dp->dmap_driver, &dev_mess); | 
|---|
|  | 537 | if (r != OK) | 
|---|
|  | 538 | return r; | 
|---|
|  | 539 |  | 
|---|
|  | 540 | if (op == DEV_OPEN && dev_mess.REP_STATUS >= 0) { | 
|---|
|  | 541 | if (dev_mess.REP_STATUS != minor) { | 
|---|
|  | 542 | /* A new minor device number has been returned.  Create a | 
|---|
|  | 543 | * temporary device file to hold it. | 
|---|
|  | 544 | */ | 
|---|
|  | 545 | struct inode *ip; | 
|---|
|  | 546 |  | 
|---|
|  | 547 | /* Device number of the new device. */ | 
|---|
|  | 548 | dev = (dev & ~(BYTE << MINOR)) | (dev_mess.REP_STATUS << MINOR); | 
|---|
|  | 549 |  | 
|---|
|  | 550 | ip = alloc_inode(root_dev, ALL_MODES | I_CHAR_SPECIAL); | 
|---|
|  | 551 | if (ip == NIL_INODE) { | 
|---|
|  | 552 | /* Oops, that didn't work.  Undo open. */ | 
|---|
|  | 553 | (void) clone_opcl(DEV_CLOSE, dev, proc_e, 0); | 
|---|
|  | 554 | return(err_code); | 
|---|
|  | 555 | } | 
|---|
|  | 556 | ip->i_zone[0] = dev; | 
|---|
|  | 557 |  | 
|---|
|  | 558 | put_inode(fp->fp_filp[m_in.fd]->filp_ino); | 
|---|
|  | 559 | fp->fp_filp[m_in.fd]->filp_ino = ip; | 
|---|
|  | 560 | } | 
|---|
|  | 561 | dev_mess.REP_STATUS = OK; | 
|---|
|  | 562 | } | 
|---|
|  | 563 | return(dev_mess.REP_STATUS); | 
|---|
|  | 564 | } | 
|---|
|  | 565 |  | 
|---|
|  | 566 | /*===========================================================================* | 
|---|
|  | 567 | *                              dev_up                                       * | 
|---|
|  | 568 | *===========================================================================*/ | 
|---|
|  | 569 | PUBLIC void dev_up(int maj) | 
|---|
|  | 570 | { | 
|---|
|  | 571 | /* A new device driver has been mapped in. This function | 
|---|
|  | 572 | * checks if any filesystems are mounted on it, and if so, | 
|---|
|  | 573 | * dev_open()s them so the filesystem can be reused. | 
|---|
|  | 574 | */ | 
|---|
|  | 575 | struct super_block *sb; | 
|---|
|  | 576 | struct filp *fp; | 
|---|
|  | 577 | int r; | 
|---|
|  | 578 |  | 
|---|
|  | 579 | /* Open a device once for every filp that's opened on it, | 
|---|
|  | 580 | * and once for every filesystem mounted from it. | 
|---|
|  | 581 | */ | 
|---|
|  | 582 |  | 
|---|
|  | 583 | for(sb = super_block; sb < &super_block[NR_SUPERS]; sb++) { | 
|---|
|  | 584 | int minor; | 
|---|
|  | 585 | if(sb->s_dev == NO_DEV) | 
|---|
|  | 586 | continue; | 
|---|
|  | 587 | if(((sb->s_dev >> MAJOR) & BYTE) != maj) | 
|---|
|  | 588 | continue; | 
|---|
|  | 589 | minor = ((sb->s_dev >> MINOR) & BYTE); | 
|---|
|  | 590 | printf("FS: remounting dev %d/%d\n", maj, minor); | 
|---|
|  | 591 | if((r = dev_open(sb->s_dev, FS_PROC_NR, | 
|---|
|  | 592 | sb->s_rd_only ? R_BIT : (R_BIT|W_BIT))) != OK) { | 
|---|
|  | 593 | printf("FS: mounted dev %d/%d re-open failed: %d.\n", | 
|---|
|  | 594 | maj, minor, r); | 
|---|
|  | 595 | } | 
|---|
|  | 596 | } | 
|---|
|  | 597 |  | 
|---|
|  | 598 | for(fp = filp; fp < &filp[NR_FILPS]; fp++) { | 
|---|
|  | 599 | struct inode *in; | 
|---|
|  | 600 | int minor; | 
|---|
|  | 601 |  | 
|---|
|  | 602 | if(fp->filp_count < 1 || !(in=fp->filp_ino)) continue; | 
|---|
|  | 603 | if(((in->i_zone[0] >> MAJOR) & BYTE) != maj) continue; | 
|---|
|  | 604 | if(!(in->i_mode & (I_BLOCK_SPECIAL|I_CHAR_SPECIAL))) continue; | 
|---|
|  | 605 |  | 
|---|
|  | 606 | minor = ((in->i_zone[0] >> MINOR) & BYTE); | 
|---|
|  | 607 |  | 
|---|
|  | 608 | printf("FS: reopening special %d/%d..\n", maj, minor); | 
|---|
|  | 609 |  | 
|---|
|  | 610 | if((r = dev_open(in->i_zone[0], FS_PROC_NR, | 
|---|
|  | 611 | in->i_mode & (R_BIT|W_BIT))) != OK) { | 
|---|
|  | 612 | int n; | 
|---|
|  | 613 | /* This function will set the fp_filp[]s of processes | 
|---|
|  | 614 | * holding that fp to NULL, but _not_ clear | 
|---|
|  | 615 | * fp_filp_inuse, so that fd can't be recycled until | 
|---|
|  | 616 | * it's close()d. | 
|---|
|  | 617 | */ | 
|---|
|  | 618 | n = inval_filp(fp); | 
|---|
|  | 619 | if(n != fp->filp_count) | 
|---|
|  | 620 | printf("FS: warning: invalidate/count " | 
|---|
|  | 621 | "discrepancy (%d, %d)\n", n, fp->filp_count); | 
|---|
|  | 622 | fp->filp_count = 0; | 
|---|
|  | 623 | printf("FS: file on dev %d/%d re-open failed: %d; " | 
|---|
|  | 624 | "invalidated %d fd's.\n", maj, minor, r, n); | 
|---|
|  | 625 | } | 
|---|
|  | 626 | } | 
|---|
|  | 627 |  | 
|---|
|  | 628 | return; | 
|---|
|  | 629 | } | 
|---|
|  | 630 |  | 
|---|