📄 device.c
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/fs/device.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
27000 /* When a needed block is not in the cache, it must be fetched from the disk.
27001 * Special character files also require I/O. The routines for these are here.
27002 *
27003 * The entry points in this file are:
27004 * dev_io: perform a read or write on a block or character device
27005 * dev_opcl: perform generic device-specific processing for open & close
27006 * tty_open: perform tty-specific processing for open
27007 * ctty_open: perform controlling-tty-specific processing for open
27008 * ctty_close: perform controlling-tty-specific processing for close
27009 * do_setsid: perform the SETSID system call (FS side)
27010 * do_ioctl: perform the IOCTL system call
27011 * call_task: procedure that actually calls the kernel tasks
27012 * call_ctty: procedure that actually calls task for /dev/tty
27013 */
27014
27015 #include "fs.h"
27016 #include <fcntl.h>
27017 #include <minix/callnr.h>
27018 #include <minix/com.h>
27019 #include "dev.h"
27020 #include "file.h"
27021 #include "fproc.h"
27022 #include "inode.h"
27023 #include "param.h"
27024
27025 PRIVATE message dev_mess;
27026 PRIVATE major, minor, task;
27027
27028 FORWARD _PROTOTYPE( void find_dev, (Dev_t dev) );
27029
27030 /*===========================================================================*
27031 * dev_io *
27032 *===========================================================================*/
27033 PUBLIC int dev_io(op, nonblock, dev, pos, bytes, proc, buff)
27034 int op; /* DEV_READ, DEV_WRITE, DEV_IOCTL, etc. */
27035 int nonblock; /* TRUE if nonblocking op */
27036 dev_t dev; /* major-minor device number */
27037 off_t pos; /* byte position */
27038 int bytes; /* how many bytes to transfer */
27039 int proc; /* in whose address space is buff? */
27040 char *buff; /* virtual address of the buffer */
27041 {
27042 /* Read or write from a device. The parameter 'dev' tells which one. */
27043
27044 find_dev(dev); /* load the variables major, minor, and task */
27045
27046 /* Set up the message passed to task. */
27047 dev_mess.m_type = op;
27048 dev_mess.DEVICE = (dev >> MINOR) & BYTE;
27049 dev_mess.POSITION = pos;
27050 dev_mess.PROC_NR = proc;
27051 dev_mess.ADDRESS = buff;
27052 dev_mess.COUNT = bytes;
27053 dev_mess.TTY_FLAGS = nonblock; /* temporary kludge */
27054
27055 /* Call the task. */
27056 (*dmap[major].dmap_rw)(task, &dev_mess);
27057
27058 /* Task has completed. See if call completed. */
27059 if (dev_mess.REP_STATUS == SUSPEND) {
27060 if (op == DEV_OPEN) task = XPOPEN;
27061 suspend(task); /* suspend user */
27062 }
27063
27064 return(dev_mess.REP_STATUS);
27065 }
27068 /*===========================================================================*
27069 * dev_opcl *
27070 *===========================================================================*/
27071 PUBLIC void dev_opcl(task_nr, mess_ptr)
27072 int task_nr; /* which task */
27073 message *mess_ptr; /* message pointer */
27074 {
27075 /* Called from the dmap struct in table.c on opens & closes of special files.*/
27076
27077 int op;
27078
27079 op = mess_ptr->m_type; /* save DEV_OPEN or DEV_CLOSE for later */
27080 mess_ptr->DEVICE = (mess_ptr->DEVICE >> MINOR) & BYTE;
27081 mess_ptr->PROC_NR = fp - fproc;
27082
27083 call_task(task_nr, mess_ptr);
27084
27085 /* Task has completed. See if call completed. */
27086 if (mess_ptr->REP_STATUS == SUSPEND) {
27087 if (op == DEV_OPEN) task_nr = XPOPEN;
27088 suspend(task_nr); /* suspend user */
27089 }
27090 }
27092 /*===========================================================================*
27093 * tty_open *
27094 *===========================================================================*/
27095 PUBLIC void tty_open(task_nr, mess_ptr)
27096 int task_nr;
27097 message *mess_ptr;
27098 {
27099 /* This procedure is called from the dmap struct in table.c on tty opens. */
27100
27101 int r;
27102 dev_t dev;
27103 int flags, proc;
27104 register struct fproc *rfp;
27105
27106 dev = (dev_t) mess_ptr->DEVICE;
27107 flags = mess_ptr->COUNT;
27108 proc = fp - fproc;
27109
27110 /* Add O_NOCTTY to the flags if this process is not a session leader, or
27111 * if it already has a controlling tty, or if it is someone elses
27112 * controlling tty.
27113 */
27114 if (!fp->fp_sesldr || fp->fp_tty != 0) {
27115 flags |= O_NOCTTY;
27116 } else {
27117 for (rfp = &fproc[LOW_USER]; rfp < &fproc[NR_PROCS]; rfp++) {
27118 if (rfp->fp_tty == dev) flags |= O_NOCTTY;
27119 }
27120 }
27121
27122 r = dev_io(DEV_OPEN, mode, dev, (off_t) 0, flags, proc, NIL_PTR);
27123
27124 if (r == 1) {
27125 fp->fp_tty = dev;
27126 r = OK;
27127 }
27128
27129 mess_ptr->REP_STATUS = r;
27130 }
27133 /*===========================================================================*
27134 * ctty_open *
27135 *===========================================================================*/
27136 PUBLIC void ctty_open(task_nr, mess_ptr)
27137 int task_nr;
27138 message *mess_ptr;
27139 {
27140 /* This procedure is called from the dmap struct in table.c on opening
27141 * /dev/tty, the magic device that translates to the controlling tty.
27142 */
27143
27144 mess_ptr->REP_STATUS = fp->fp_tty == 0 ? ENXIO : OK;
27145 }
27148 /*===========================================================================*
27149 * ctty_close *
27150 *===========================================================================*/
27151 PUBLIC void ctty_close(task_nr, mess_ptr)
27152 int task_nr;
27153 message *mess_ptr;
27154 {
27155 /* Close /dev/tty. */
27156
27157 mess_ptr->REP_STATUS = OK;
27158 }
27161 /*===========================================================================*
27162 * do_setsid *
27163 *===========================================================================*/
27164 PUBLIC int do_setsid()
27165 {
27166 /* Perform the FS side of the SETSID call, i.e. get rid of the controlling
27167 * terminal of a process, and make the process a session leader.
27168 */
27169 register struct fproc *rfp;
27170
27171 /* Only MM may do the SETSID call directly. */
27172 if (who != MM_PROC_NR) return(ENOSYS);
27173
27174 /* Make the process a session leader with no controlling tty. */
27175 rfp = &fproc[slot1];
27176 rfp->fp_sesldr = TRUE;
27177 rfp->fp_tty = 0;
27178 }
27181 /*===========================================================================*
27182 * do_ioctl *
27183 *===========================================================================*/
27184 PUBLIC int do_ioctl()
27185 {
27186 /* Perform the ioctl(ls_fd, request, argx) system call (uses m2 fmt). */
27187
27188 struct filp *f;
27189 register struct inode *rip;
27190 dev_t dev;
27191
27192 if ( (f = get_filp(ls_fd)) == NIL_FILP) return(err_code);
27193 rip = f->filp_ino; /* get inode pointer */
27194 if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL
27195 && (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY);
27196 dev = (dev_t) rip->i_zone[0];
27197 find_dev(dev);
27198
27199 dev_mess= m;
27200
27201 dev_mess.m_type = DEV_IOCTL;
27202 dev_mess.PROC_NR = who;
27203 dev_mess.TTY_LINE = minor;
27204
27205 /* Call the task. */
27206 (*dmap[major].dmap_rw)(task, &dev_mess);
27207
27208 /* Task has completed. See if call completed. */
27209 if (dev_mess.REP_STATUS == SUSPEND) {
27210 if (f->filp_flags & O_NONBLOCK) {
27211 /* Not supposed to block. */
27212 dev_mess.m_type = CANCEL;
27213 dev_mess.PROC_NR = who;
27214 dev_mess.TTY_LINE = minor;
27215 (*dmap[major].dmap_rw)(task, &dev_mess);
27216 if (dev_mess.REP_STATUS == EINTR) dev_mess.REP_STATUS = EAGAIN;
27217 } else {
27218 suspend(task); /* User must be suspended. */
27219 }
27220 }
27221 return(dev_mess.REP_STATUS);
27222 }
27225 /*===========================================================================*
27226 * find_dev *
27227 *===========================================================================*/
27228 PRIVATE void find_dev(dev)
27229 dev_t dev; /* device */
27230 {
27231 /* Extract the major and minor device number from the parameter. */
27232
27233 major = (dev >> MAJOR) & BYTE; /* major device number */
27234 minor = (dev >> MINOR) & BYTE; /* minor device number */
27235 if (major >= max_major) {
27236 major = minor = 0; /* will fail with ENODEV */
27237 }
27238 task = dmap[major].dmap_task; /* which task services the device */
27239 }
27242 /*===========================================================================*
27243 * call_task *
27244 *===========================================================================*/
27245 PUBLIC void call_task(task_nr, mess_ptr)
27246 int task_nr; /* which task to call */
27247 message *mess_ptr; /* pointer to message for task */
27248 {
27249 /* All file system I/O ultimately comes down to I/O on major/minor device
27250 * pairs. These lead to calls on the following routines via the dmap table.
27251 */
27252
27253 int r, proc_nr;
27254 message local_m;
27255
27256 proc_nr = mess_ptr->PROC_NR;
27257
27258 while ((r = sendrec(task_nr, mess_ptr)) == ELOCKED) {
27259 /* sendrec() failed to avoid deadlock. The task 'task_nr' is
27260 * trying to send a REVIVE message for an earlier request.
27261 * Handle it and go try again.
27262 */
27263 if ((r = receive(task_nr, &local_m)) != OK) break;
27264
27265 /* If we're trying to send a cancel message to a task which has just
27266 * sent a completion reply, ignore the reply and abort the cancel
27267 * request. The caller will do the revive for the process.
27268 */
27269 if (mess_ptr->m_type == CANCEL && local_m.REP_PROC_NR == proc_nr)
27270 return;
27271
27272 /* Otherwise it should be a REVIVE. */
27273 if (local_m.m_type != REVIVE) {
27274 printf(
27275 "fs: strange device reply from %d, type = %d, proc = %d\n",
27276 local_m.m_source,
27277 local_m.m_type, local_m.REP_PROC_NR);
27278 continue;
27279 }
27280
27281 revive(local_m.REP_PROC_NR, local_m.REP_STATUS);
27282 }
27283
27284 /* The message received may be a reply to this call, or a REVIVE for some
27285 * other process.
27286 */
27287 for (;;) {
27288 if (r != OK) panic("call_task: can't send/receive", NO_NUM);
27289
27290 /* Did the process we did the sendrec() for get a result? */
27291 if (mess_ptr->REP_PROC_NR == proc_nr) break;
27292
27293 /* Otherwise it should be a REVIVE. */
27294 if (mess_ptr->m_type != REVIVE) {
27295 printf(
27296 "fs: strange device reply from %d, type = %d, proc = %d\n",
27297 mess_ptr->m_source,
27298 mess_ptr->m_type, mess_ptr->REP_PROC_NR);
27299 continue;
27300 }
27301 revive(mess_ptr->REP_PROC_NR, mess_ptr->REP_STATUS);
27302
27303 r = receive(task_nr, mess_ptr);
27304 }
27305 }
27308 /*===========================================================================*
27309 * call_ctty *
27310 *===========================================================================*/
27311 PUBLIC void call_ctty(task_nr, mess_ptr)
27312 int task_nr; /* not used - for compatibility with dmap_t */
27313 message *mess_ptr; /* pointer to message for task */
27314 {
27315 /* This routine is only called for one device, namely /dev/tty. Its job
27316 * is to change the message to use the controlling terminal, instead of the
27317 * major/minor pair for /dev/tty itself.
27318 */
27319
27320 int major_device;
27321
27322 if (fp->fp_tty == 0) {
27323 /* No controlling tty present anymore, return an I/O error. */
27324 mess_ptr->REP_STATUS = EIO;
27325 return;
27326 }
27327 major_device = (fp->fp_tty >> MAJOR) & BYTE;
27328 task_nr = dmap[major_device].dmap_task; /* task for controlling tty */
27329 mess_ptr->DEVICE = (fp->fp_tty >> MINOR) & BYTE;
27330 call_task(task_nr, mess_ptr);
27331 }
27334 /*===========================================================================*
27335 * no_dev *
27336 *===========================================================================*/
27337 PUBLIC void no_dev(task_nr, m_ptr)
27338 int task_nr; /* not used - for compatibility with dmap_t */
27339 message *m_ptr; /* message pointer */
27340 {
27341 /* No device there. */
27342
27343 m_ptr->REP_STATUS = ENODEV;
27344 }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -