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