~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Minix Cross Reference
Minix/fs/device.c


  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.