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_io: perform a read or write on a block or character device
6 * dev_opcl: perform generic device-specific processing for open & close
7 * tty_open: perform tty-specific processing for open
8 * ctty_open: perform controlling-tty-specific processing for open
9 * ctty_close: perform controlling-tty-specific processing for close
10 * do_setsid: perform the SETSID system call (FS side)
11 * do_ioctl: perform the IOCTL system call
12 * call_task: procedure that actually calls the kernel tasks
13 * call_ctty: procedure that actually calls task for /dev/tty
14 */
15
16 #include "fs.h"
17 #include <fcntl.h>
18 #include <minix/callnr.h>
19 #include <minix/com.h>
20 #include "dev.h"
21 #include "file.h"
22 #include "fproc.h"
23 #include "inode.h"
24 #include "param.h"
25
26 PRIVATE message dev_mess;
27 PRIVATE major, minor, task;
28
29 FORWARD _PROTOTYPE( void find_dev, (Dev_t dev) );
30
31 /*===========================================================================*
32 * dev_io *
33 *===========================================================================*/
34 PUBLIC int dev_io(op, nonblock, dev, pos, bytes, proc, buff)
35 int op; /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */
36 int nonblock; /* TRUE if nonblocking op */
37 dev_t dev; /* major-minor device number */
38 off_t pos; /* byte position */
39 int bytes; /* how many bytes to transfer */
40 int proc; /* in whose address space is buff? */
41 char *buff; /* virtual address of the buffer */
42 {
43 /* Read or write from a device. The parameter 'dev' tells which one. */
44
45 find_dev(dev); /* load the variables major, minor, and task */
46
47 /* Set up the message passed to task. */
48 dev_mess.m_type = op;
49 dev_mess.DEVICE = (dev >> MINOR) & BYTE;
50 dev_mess.POSITION = pos;
51 dev_mess.PROC_NR = proc;
52 dev_mess.ADDRESS = buff;
53 dev_mess.COUNT = bytes;
54 dev_mess.TTY_FLAGS = nonblock; /* temporary kludge */
55
56 /* Call the task. */
57 (*dmap[major].dmap_rw)(task, &dev_mess);
58
59 /* Task has completed. See if call completed. */
60 if (dev_mess.REP_STATUS == SUSPEND) {
61 if (op == DEV_OPEN) task = XPOPEN;
62 suspend(task); /* suspend user */
63 }
64
65 return(dev_mess.REP_STATUS);
66 }
67
68
69 /*===========================================================================*
70 * dev_opcl *
71 *===========================================================================*/
72 PUBLIC void dev_opcl(task_nr, mess_ptr)
73 int task_nr; /* which task */
74 message *mess_ptr; /* message pointer */
75 {
76 /* Called from the dmap struct in table.c on opens & closes of special files.*/
77
78 int op;
79
80 op = mess_ptr->m_type; /* save DEV_OPEN or DEV_CLOSE for later */
81 mess_ptr->DEVICE = (mess_ptr->DEVICE >> MINOR) & BYTE;
82 mess_ptr->PROC_NR = fp - fproc;
83
84 call_task(task_nr, mess_ptr);
85
86 /* Task has completed. See if call completed. */
87 if (mess_ptr->REP_STATUS == SUSPEND) {
88 if (op == DEV_OPEN) task_nr = XPOPEN;
89 suspend(task_nr); /* suspend user */
90 }
91 }
92
93 /*===========================================================================*
94 * tty_open *
95 *===========================================================================*/
96 PUBLIC void tty_open(task_nr, mess_ptr)
97 int task_nr;
98 message *mess_ptr;
99 {
100 /* This procedure is called from the dmap struct in table.c on tty opens. */
101
102 int r;
103 dev_t dev;
104 int flags, proc;
105 register struct fproc *rfp;
106
107 dev = (dev_t) mess_ptr->DEVICE;
108 flags = mess_ptr->COUNT;
109 proc = fp - fproc;
110
111 /* Add O_NOCTTY to the flags if this process is not a session leader, or
112 * if it already has a controlling tty, or if it is someone elses
113 * controlling tty.
114 */
115 if (!fp->fp_sesldr || fp->fp_tty != 0) {
116 flags |= O_NOCTTY;
117 } else {
118 for (rfp = &fproc[LOW_USER]; rfp < &fproc[NR_PROCS]; rfp++) {
119 if (rfp->fp_tty == dev) flags |= O_NOCTTY;
120 }
121 }
122
123 r = dev_io(DEV_OPEN, mode, dev, (off_t) 0, flags, proc, NIL_PTR);
124
125 if (r == 1) {
126 fp->fp_tty = dev;
127 r = OK;
128 }
129
130 mess_ptr->REP_STATUS = r;
131 }
132
133
134 /*===========================================================================*
135 * ctty_open *
136 *===========================================================================*/
137 PUBLIC void ctty_open(task_nr, mess_ptr)
138 int task_nr;
139 message *mess_ptr;
140 {
141 /* This procedure is called from the dmap struct in table.c on opening
142 * /dev/tty, the magic device that translates to the controlling tty.
143 */
144
145 mess_ptr->REP_STATUS = fp->fp_tty == 0 ? ENXIO : OK;
146 }
147
148
149 /*===========================================================================*
150 * ctty_close *
151 *===========================================================================*/
152 PUBLIC void ctty_close(task_nr, mess_ptr)
153 int task_nr;
154 message *mess_ptr;
155 {
156 /* Close /dev/tty. */
157
158 mess_ptr->REP_STATUS = OK;
159 }
160
161
162 /*===========================================================================*
163 * do_setsid *
164 *===========================================================================*/
165 PUBLIC int do_setsid()
166 {
167 /* Perform the FS side of the SETSID call, i.e. get rid of the controlling
168 * terminal of a process, and make the process a session leader.
169 */
170 register struct fproc *rfp;
171
172 /* Only MM may do the SETSID call directly. */
173 if (who != MM_PROC_NR) return(ENOSYS);
174
175 /* Make the process a session leader with no controlling tty. */
176 rfp = &fproc[slot1];
177 rfp->fp_sesldr = TRUE;
178 rfp->fp_tty = 0;
179 }
180
181
182 /*===========================================================================*
183 * do_ioctl *
184 *===========================================================================*/
185 PUBLIC int do_ioctl()
186 {
187 /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */
188
189 struct filp *f;
190 register struct inode *rip;
191 dev_t dev;
192
193 if ( (f = get_filp(ls_fd)) == NIL_FILP) return(err_code);
194 rip = f->filp_ino; /* get inode pointer */
195 if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL
196 && (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY);
197 dev = (dev_t) rip->i_zone[0];
198 find_dev(dev);
199
200 dev_mess= m;
201
202 dev_mess.m_type = DEV_IOCTL;
203 dev_mess.PROC_NR = who;
204 dev_mess.TTY_LINE = minor;
205
206 /* Call the task. */
207 (*dmap[major].dmap_rw)(task, &dev_mess);
208
209 /* Task has completed. See if call completed. */
210 if (dev_mess.REP_STATUS == SUSPEND) {
211 if (f->filp_flags & O_NONBLOCK) {
212 /* Not supposed to block. */
213 dev_mess.m_type = CANCEL;
214 dev_mess.PROC_NR = who;
215 dev_mess.TTY_LINE = minor;
216 (*dmap[major].dmap_rw)(task, &dev_mess);
217 if (dev_mess.REP_STATUS == EINTR) dev_mess.REP_STATUS = EAGAIN;
218 } else {
219 suspend(task); /* User must be suspended. */
220 }
221 }
222 #if ENABLE_BINCOMPAT
223 m1.TTY_SPEK = dev_mess.TTY_SPEK; /* erase and kill */
224 m1.TTY_FLAGS = dev_mess.TTY_FLAGS; /* flags */
225 #endif
226 return(dev_mess.REP_STATUS);
227 }
228
229
230 /*===========================================================================*
231 * find_dev *
232 *===========================================================================*/
233 PRIVATE void find_dev(dev)
234 dev_t dev; /* device */
235 {
236 /* Extract the major and minor device number from the parameter. */
237
238 major = (dev >> MAJOR) & BYTE; /* major device number */
239 minor = (dev >> MINOR) & BYTE; /* minor device number */
240 if (major >= max_major) {
241 major = minor = 0; /* will fail with ENODEV */
242 }
243 task = dmap[major].dmap_task; /* which task services the device */
244 }
245
246
247 /*===========================================================================*
248 * call_task *
249 *===========================================================================*/
250 PUBLIC void call_task(task_nr, mess_ptr)
251 int task_nr; /* which task to call */
252 message *mess_ptr; /* pointer to message for task */
253 {
254 /* All file system I/O ultimately comes down to I/O on major/minor device
255 * pairs. These lead to calls on the following routines via the dmap table.
256 */
257
258 int r, proc_nr;
259 message local_m;
260
261 proc_nr = mess_ptr->PROC_NR;
262
263 while ((r = sendrec(task_nr, mess_ptr)) == ELOCKED) {
264 /* sendrec() failed to avoid deadlock. The task 'task_nr' is
265 * trying to send a REVIVE message for an earlier request.
266 * Handle it and go try again.
267 */
268 if ((r = receive(task_nr, &local_m)) != OK) break;
269
270 /* If we're trying to send a cancel message to a task which has just
271 * sent a completion reply, ignore the reply and abort the cancel
272 * request. The caller will do the revive for the process.
273 */
274 if (mess_ptr->m_type == CANCEL && local_m.REP_PROC_NR == proc_nr)
275 return;
276
277 /* Otherwise it should be a REVIVE. */
278 if (local_m.m_type != REVIVE) {
279 printf(
280 "fs: strange device reply from %d, type = %d, proc = %d\n",
281 local_m.m_source,
282 local_m.m_type, local_m.REP_PROC_NR);
283 continue;
284 }
285
286 revive(local_m.REP_PROC_NR, local_m.REP_STATUS);
287 }
288
289 /* The message received may be a reply to this call, or a REVIVE for some
290 * other process.
291 */
292 for (;;) {
293 if (r != OK) panic("call_task: can't send/receive", NO_NUM);
294
295 /* Did the process we did the sendrec() for get a result? */
296 if (mess_ptr->REP_PROC_NR == proc_nr) break;
297
298 /* Otherwise it should be a REVIVE. */
299 if (mess_ptr->m_type != REVIVE) {
300 printf(
301 "fs: strange device reply from %d, type = %d, proc = %d\n",
302 mess_ptr->m_source,
303 mess_ptr->m_type, mess_ptr->REP_PROC_NR);
304 continue;
305 }
306 revive(mess_ptr->REP_PROC_NR, mess_ptr->REP_STATUS);
307
308 r = receive(task_nr, mess_ptr);
309 }
310 }
311
312
313 /*===========================================================================*
314 * call_ctty *
315 *===========================================================================*/
316 PUBLIC void call_ctty(task_nr, mess_ptr)
317 int task_nr; /* not used - for compatibility with dmap_t */
318 message *mess_ptr; /* pointer to message for task */
319 {
320 /* This routine is only called for one device, namely /dev/tty. Its job
321 * is to change the message to use the controlling terminal, instead of the
322 * major/minor pair for /dev/tty itself.
323 */
324
325 int major_device;
326
327 if (fp->fp_tty == 0) {
328 /* No controlling tty present anymore, return an I/O error. */
329 mess_ptr->REP_STATUS = EIO;
330 return;
331 }
332 major_device = (fp->fp_tty >> MAJOR) & BYTE;
333 task_nr = dmap[major_device].dmap_task; /* task for controlling tty */
334 mess_ptr->DEVICE = (fp->fp_tty >> MINOR) & BYTE;
335 call_task(task_nr, mess_ptr);
336 }
337
338
339 /*===========================================================================*
340 * no_dev *
341 *===========================================================================*/
342 PUBLIC void no_dev(task_nr, m_ptr)
343 int task_nr; /* not used - for compatibility with dmap_t */
344 message *m_ptr; /* message pointer */
345 {
346 /* No device there. */
347
348 m_ptr->REP_STATUS = ENODEV;
349 }
350
351
352 #if ENABLE_NETWORKING
353 /*===========================================================================*
354 * net_open *
355 *===========================================================================*/
356 PUBLIC void net_open(task_nr, mess_ptr)
357 int task_nr; /* task to send message to */
358 message *mess_ptr; /* pointer to message to send */
359 {
360 /* Network files need special processing upon open. A network device is
361 * "cloned", i.e. on a succesful open it is replaced by a new network device
362 * with a new unique minor device number. This new device number identifies
363 * the new IP connection with the network task.
364 */
365
366 dev_t dev;
367 struct inode *rip, *nrip;
368 int result;
369 int ncount, proc;
370
371 rip = fp->fp_filp[fd]->filp_ino;
372
373 nrip = alloc_inode(rip->i_dev, ALL_MODES | I_CHAR_SPECIAL);
374 if (nrip == NIL_INODE) {
375 mess_ptr->REP_STATUS = err_code;
376 return;
377 }
378
379 dev = (dev_t) mess_ptr->DEVICE;
380 ncount = mess_ptr->COUNT;
381 proc = fp - fproc;
382 result = dev_io(DEV_OPEN, mode, dev, (off_t) 0, ncount, proc, NIL_PTR);
383
384 if (result < 0) {
385 put_inode(nrip);
386 mess_ptr->REP_STATUS = result;
387 return;
388 }
389
390 dev= rip->i_zone[0];
391 dev= (dev & ~(BYTE << MINOR)) | ((result & BYTE) << MINOR);
392
393 nrip->i_zone[0]= dev;
394 put_inode(rip);
395 fp->fp_filp[fd]->filp_ino = nrip;
396 mess_ptr->REP_STATUS = OK;
397 }
398 #endif /* ENABLE_NETWORKING */
399
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.