The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/servers/fs/device.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.