exit(-1);
}
+int open_audio(unsigned int *fragment_size, unsigned int channels,
+ unsigned int samples_per_sec, unsigned int bits)
+{
+ unsigned int sign;
+ int audio;
+
+ /* Open DSP */
+ if ((audio = open("/dev/audio", O_RDWR | O_REOPEN)) < 0)
+ {
+ printf("Cannot open /dev/audio: %s\n", strerror(errno));
+ exit(-1);
+ }
+
+ ioctl(audio, DSPIOMAX, fragment_size); /* Get maximum fragment size. */
+
+ /* Set DSP parameters (should check return values..) */
+ ioctl(audio, DSPIOSIZE, fragment_size); /* Use max. fragment size. */
+ ioctl(audio, DSPIOSTEREO, &channels);
+ ioctl(audio, DSPIORATE, &samples_per_sec);
+ ioctl(audio, DSPIOBITS, &bits);
+ sign = (bits == 16 ? 1 : 0);
+ ioctl(audio, DSPIOSIGN, &sign);
+ return audio;
+}
int main ( int argc, char *argv[] )
{
int i, r, audio, file;
char *buffer, *file_name = NULL;
- unsigned int sign;
- unsigned int fragment_size;
- unsigned int channels;
- unsigned int bits;
+ unsigned int fragment_size, fragment_size2;
long data_pos;
int showinfo = 0;
}
else file_name = argv[1];
- /* Open DSP */
- if ((audio = open("/dev/audio", O_RDWR | O_REOPEN)) < 0)
- {
- printf("Cannot open /dev/audio: %s\n", strerror(errno));
- exit(-1);
- }
-
- /* Get maximum fragment size and try to allocate a buffer */
- ioctl(audio, DSPIOMAX, &fragment_size);
- if ((buffer = malloc(fragment_size)) == (char *)0)
- {
- fprintf(stderr, "Cannot allocate buffer\n");
- exit(-1);
- }
- ioctl(audio, DSPIOSIZE, &fragment_size);
-
/* Open wav file */
if((file = open(file_name, O_RDONLY)) < 0)
{
exit(1);
}
- /* Set DSP parameters */
- channels = c_fields.Channels;
- channels--;
- bits = s_fields.BitsPerSample;
- ioctl(audio, DSPIOSTEREO, &channels);
- ioctl(audio, DSPIORATE, &c_fields.SamplesPerSec);
- ioctl(audio, DSPIOBITS, &bits);
- sign = (bits == 16 ? 1 : 0);
- ioctl(audio, DSPIOSIGN, &sign);
+ /* Open audio device and set DSP parameters */
+ audio = open_audio(&fragment_size, c_fields.Channels - 1,
+ c_fields.SamplesPerSec, s_fields.BitsPerSample);
+
+ if ((buffer = malloc(fragment_size)) == (char *)0)
+ {
+ fprintf(stderr, "Cannot allocate buffer\n");
+ exit(-1);
+ }
/* Goto data chunk */
lseek(file, data_pos, SEEK_SET);
{
fprintf(stderr, "playwave: write to audio device failed: %s\n",
strerror(errno));
+
+ /* If we get EIO, the driver might have restarted. Reopen the
+ * audio device.
+ */
+ if (errno == EIO) {
+ close(audio);
+ audio = open_audio(&fragment_size2,
+ c_fields.Channels - 1, c_fields.SamplesPerSec,
+ s_fields.BitsPerSample);
+ if (fragment_size2 != fragment_size) {
+ fprintf(stderr, "Fragment size has changed\n");
+ exit(1);
+ }
+ }
}
else
{
#define DEV_OPEN (DEV_RQ_BASE + 6) /* open a minor device */
#define DEV_CLOSE (DEV_RQ_BASE + 7) /* close a minor device */
#define DEV_SELECT (DEV_RQ_BASE + 12) /* request select() attention */
-#define DEV_REOPEN (DEV_RQ_BASE + 14) /* reopen a minor device */
#define DEV_READ_S (DEV_RQ_BASE + 20) /* (safecopy) read from minor */
#define DEV_WRITE_S (DEV_RQ_BASE + 21) /* (safecopy) write to minor */
#define IS_DEV_RQ(type) (((type) & ~0xff) == DEV_RQ_BASE)
#define DEV_REVIVE (DEV_RS_BASE + 2) /* driver revives process */
-#define DEV_REOPEN_REPL (DEV_RS_BASE + 5) /* reply to DEV_REOPEN */
#define DEV_CLOSE_REPL (DEV_RS_BASE + 6) /* reply to DEV_CLOSE */
#define DEV_SEL_REPL1 (DEV_RS_BASE + 7) /* first reply to DEV_SELECT */
#define DEV_SEL_REPL2 (DEV_RS_BASE + 8) /* (opt) second reply to DEV_SELECT */
reply_mess.REP_STATUS = r;
break;
- case DEV_REOPEN:
- reply_mess.m_type = DEV_REOPEN_REPL;
- reply_mess.REP_ENDPT = mess->USER_ENDPT;
- reply_mess.REP_STATUS = r;
- break;
-
case DEV_CLOSE:
reply_mess.m_type = DEV_CLOSE_REPL;
reply_mess.REP_ENDPT = mess->USER_ENDPT;
/*===========================================================================*
* do_open *
*===========================================================================*/
-static int do_open(struct chardriver *cdp, message *m_ptr, int is_reopen)
+static int do_open(struct chardriver *cdp, message *m_ptr)
{
/* Open a minor device. */
endpoint_t user_endpt;
/* Call the open hook. */
minor = m_ptr->DEVICE;
access = m_ptr->COUNT;
- user_endpt = is_reopen ? NONE : m_ptr->USER_ENDPT; /* XXX FIXME */
+ user_endpt = m_ptr->USER_ENDPT;
r = cdp->cdr_open(minor, access, user_endpt);
*/
if (IS_DEV_RQ(m_ptr->m_type) && !is_open_dev(m_ptr->DEVICE)) {
/* Ignore spurious requests for unopened devices. */
- if (m_ptr->m_type != DEV_OPEN && m_ptr->m_type != DEV_REOPEN)
+ if (m_ptr->m_type != DEV_OPEN)
return; /* do not send a reply */
/* Mark the device as opened otherwise. */
/* Call the appropriate function(s) for this request. */
switch (m_ptr->m_type) {
- case DEV_OPEN: r = do_open(cdp, m_ptr, FALSE); break;
- case DEV_REOPEN: r = do_open(cdp, m_ptr, TRUE); break;
+ case DEV_OPEN: r = do_open(cdp, m_ptr); break;
case DEV_CLOSE: r = do_close(cdp, m_ptr); break;
case DEV_READ_S: r = do_transfer(cdp, m_ptr, FALSE); break;
case DEV_WRITE_S: r = do_transfer(cdp, m_ptr, TRUE); break;
There are several special tasks that require a worker thread, and these are
implemented as normal work associated with a certain special process that does
not make regular VFS calls anyway. For example, the initial ramdisk mount
-procedure and the post-crash filp garbage collector use a thread associated
-with the VFS process. Some of these special tasks require protection against
-being started multiple times at once, as this is not only undesirable but also
-disallowed. The full list of worker thread task types and subtypes is shown in
-Table 1.
+procedure uses a thread associated with the VFS process. Some of these special
+tasks require protection against being started multiple times at once, as this
+is not only undesirable but also disallowed. The full list of worker thread
+task types and subtypes is shown in Table 1.
{{{
-------------------------------------------------------------------------
+---------------------------+--------+-----------------+----------------+
| DS event notification | normal | DS | yes |
+---------------------------+--------+-----------------+----------------+
-| filp garbage collection | normal | VFS | no |
-+---------------------------+--------+-----------------+----------------+
| initial ramdisk mounting | normal | VFS | no |
+---------------------------+--------+-----------------+----------------+
| reboot sequence | normal | PM | no |
=== Recovery from character driver crashes ===
## 5.2 Recovery from character driver crashes
-Character special files are treated differently. Once VFS has found out a
-driver has been restarted, it will stop the current request (if there is
-any). It makes no sense to retry requests due to the nature of character
-special files. If a character special driver can restart without changing
-endpoints, this merely results in the current request (e.g., read, write, or
-ioctl) failing and allows the user process to reissue the same request. On
-the other hand, if a driver restart causes the driver to change endpoint
-number, all associated file descriptors are marked invalid and subsequent
-operations on them will always fail with a bad file descriptor error.
+While VFS used to support minimal recovery from character driver crashes, the
+added complexity has so far proven to outweigh the benefits, especially since
+such crash recovery can never be fully transparent: it depends entirely on the
+character device as to whether repeating an I/O request makes sense at all.
+Currently, all operations except close(2) on a file descriptor that identifies
+a device on a crashed character driver, will result in an EIO error. It is up
+to the application to reopen the character device and retry whatever it was
+doing in the appropriate manner. In the future, automatic reopen and I/O
+restart may be reintroduced for a limited subset of character drivers.
=== Recovery from File Server crashes ===
## 5.3 Recovery from File Server crashes
*
* The entry points in this file are:
* dev_open: open a character device
- * dev_reopen: reopen a character device after a driver crash
* dev_close: close a character device
* cdev_reply: process the result of a character driver request
* bdev_open: open a block device
static int block_io(endpoint_t driver_e, message *mess_ptr);
static cp_grant_id_t make_grant(endpoint_t driver_e, endpoint_t user_e, int op,
void *buf, unsigned long size);
-static void restart_reopen(devmajor_t major);
-static void reopen_reply(message *m_ptr);
static int dummyproc;
}
-/*===========================================================================*
- * dev_reopen *
- *===========================================================================*/
-int dev_reopen(
- dev_t dev, /* device to open */
- int filp_no, /* filp to reopen for */
- int flags /* mode bits and flags */
-)
-{
-/* Reopen a character device after a failing device driver. */
- devmajor_t major_dev;
- struct dmap *dp;
- int r;
-
- /* Determine the major device number and call the device class specific
- * open/close routine. (This is the only routine that must check the device
- * number for being in range. All others can trust this check.)
- */
- major_dev = major(dev);
- if (major_dev < 0 || major_dev >= NR_DEVICES) return(ENXIO);
- dp = &dmap[major_dev];
- if (dp->dmap_driver == NONE) return(ENXIO);
- r = (*dp->dmap_opcl)(DEV_REOPEN, dev, filp_no, flags);
- if (r == SUSPEND) r = OK;
- return(r);
-}
-
-
/*===========================================================================*
* dev_close *
*===========================================================================*/
void *buf, /* virtual address of the buffer */
off_t pos, /* byte position */
size_t bytes, /* how many bytes to transfer */
- int flags, /* special flags, like O_NONBLOCK */
- int suspend_reopen /* Just suspend the process */
+ int flags /* special flags, like O_NONBLOCK */
)
{
/* Initiate a read, write, or ioctl to a device. */
/* See if driver is roughly valid. */
if (dp->dmap_driver == NONE) return(ENXIO);
- if (suspend_reopen) {
- /* Suspend user. */
- fp->fp_grant = GRANT_INVALID;
- fp->fp_ioproc = NONE;
- wait_for(dp->dmap_driver);
- fp->fp_flags |= FP_SUSP_REOPEN;
- return(SUSPEND);
- }
-
if(isokendpt(dp->dmap_driver, &dummyproc) != OK) {
printf("VFS: dev_io: old driver for major %x (%d)\n", major_dev,
dp->dmap_driver);
}
lock_vnode(vp, VNODE_OPCL);
- assert(FD_ISSET(scratch(fp).file.fd_nr, &fp->fp_filp_inuse));
+ assert(fp->fp_filp[scratch(fp).file.fd_nr] != NULL);
unlock_vnode(fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno);
put_vnode(fp->fp_filp[scratch(fp).file.fd_nr]->filp_vno);
* gen_opcl *
*===========================================================================*/
int gen_opcl(
- int op, /* operation, DEV_OPEN/DEV_REOPEN/DEV_CLOSE */
+ int op, /* operation, DEV_OPEN or DEV_CLOSE */
dev_t dev, /* device to open or close */
endpoint_t proc_e, /* process to open/close for */
int flags /* mode bits and flags */
if (r != OK) return(r);
- if (op == DEV_OPEN || op == DEV_CLOSE) {
- /* Block the thread waiting for a reply. */
- fp->fp_task = dp->dmap_driver;
- self->w_task = dp->dmap_driver;
- self->w_drv_sendrec = &dev_mess;
+ /* Block the thread waiting for a reply. */
+ fp->fp_task = dp->dmap_driver;
+ self->w_task = dp->dmap_driver;
+ self->w_drv_sendrec = &dev_mess;
- worker_wait();
+ worker_wait();
- self->w_task = NONE;
- self->w_drv_sendrec = NULL;
- }
+ self->w_task = NONE;
+ self->w_drv_sendrec = NULL;
/* Return the result from the driver. */
return(dev_mess.REP_STATUS);
{
/* Perform the ioctl(ls_fd, request, argx) system call */
unsigned long ioctlrequest;
- int r = OK, suspend_reopen;
+ int r = OK;
struct filp *f;
register struct vnode *vp;
dev_t dev;
}
if (r == OK) {
- suspend_reopen = (f->filp_state & FS_NEEDS_REOPEN);
dev = (dev_t) vp->v_sdev;
if (S_ISBLK(vp->v_mode))
r = bdev_ioctl(dev, who_e, ioctlrequest, argx);
else
r = dev_io(DEV_IOCTL_S, dev, who_e, argx, 0,
- ioctlrequest, f->filp_flags, suspend_reopen);
+ ioctlrequest, f->filp_flags);
}
unlock_filp(f);
}
-/*===========================================================================*
- * cdev_up *
- *===========================================================================*/
-void cdev_up(devmajor_t maj)
-{
- /* A new character device driver has been mapped in.
- */
- int needs_reopen;
- struct filp *rfilp;
- struct vnode *vp;
-
- needs_reopen= FALSE;
- for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) {
- if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue;
- if (major(vp->v_sdev) != maj) continue;
- if (!S_ISCHR(vp->v_mode)) continue;
-
- rfilp->filp_state |= FS_NEEDS_REOPEN;
- needs_reopen = TRUE;
- }
-
- if (needs_reopen)
- restart_reopen(maj);
-}
-
/*===========================================================================*
* opcl_reply *
*===========================================================================*/
switch (call_nr) {
case DEV_OPEN_REPL:
case DEV_CLOSE_REPL: opcl_reply(&m_in); break;
- case DEV_REOPEN_REPL: reopen_reply(&m_in); break;
case DEV_REVIVE: task_reply(&m_in); break;
case DEV_SEL_REPL1:
select_reply1(m_in.m_source, m_in.DEV_MINOR, m_in.DEV_SEL_OPS);
wp->w_drv_sendrec = NULL;
worker_signal(wp);
}
-
-/*===========================================================================*
- * filp_gc_thread *
- *===========================================================================*/
-static void filp_gc_thread(void)
-{
-/* Filp garbage collection thread function. Since new filps may be invalidated
- * while the actual garbage collection procedure is running, we repeat the
- * procedure until it can not find any more work to do.
- */
-
- while (do_filp_gc())
- /* simply repeat */;
-}
-
-/*===========================================================================*
- * restart_reopen *
- *===========================================================================*/
-static void restart_reopen(devmajor_t maj)
-{
- devmajor_t major_dev;
- devminor_t minor_dev;
- endpoint_t driver_e;
- struct vnode *vp;
- struct filp *rfilp;
- struct fproc *rfp;
- message m_out;
- int n, r;
-
- memset(&m_out, 0, sizeof(m_out));
-
- if (maj < 0 || maj >= NR_DEVICES) panic("VFS: out-of-bound major");
-
- for (rfilp = filp; rfilp < &filp[NR_FILPS]; rfilp++) {
- if (rfilp->filp_count < 1 || !(vp = rfilp->filp_vno)) continue;
- if (!(rfilp->filp_state & FS_NEEDS_REOPEN)) continue;
- if (!S_ISCHR(vp->v_mode)) continue;
-
- major_dev = major(vp->v_sdev);
- minor_dev = minor(vp->v_sdev);
- if (major_dev != maj) continue;
-
- if (rfilp->filp_flags & O_REOPEN) {
- /* Try to reopen a file upon driver restart */
- r = dev_reopen(vp->v_sdev, rfilp-filp,
- rfilp->filp_mode & (R_BIT|W_BIT));
-
- if (r == OK)
- return;
-
- printf("VFS: file on dev %d/%d re-open failed: %d\n",
- major_dev, minor_dev, r);
- }
-
- /* File descriptor is to be closed when driver restarts. */
- n = invalidate_filp(rfilp);
- if (n != rfilp->filp_count) {
- printf("VFS: warning: invalidate/count "
- "discrepancy (%d, %d)\n", n, rfilp->filp_count);
- }
- rfilp->filp_count = 0;
-
- /* We have to clean up this filp and vnode, but can't do that yet as
- * it's locked by a worker thread. Start a new job to garbage collect
- * invalidated filps associated with this device driver. This thread
- * is associated with a process that we know is idle otherwise: VFS.
- * Be careful that we don't start two threads or lose work, though.
- */
- if (worker_can_start(fproc_addr(VFS_PROC_NR))) {
- worker_start(fproc_addr(VFS_PROC_NR), filp_gc_thread,
- &m_out /*unused*/, FALSE /*use_spare*/);
- }
- }
-
- /* Nothing more to re-open. Restart suspended processes */
- driver_e = dmap[maj].dmap_driver;
- for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
- if(rfp->fp_pid == PID_FREE) continue;
- if(rfp->fp_blocked_on == FP_BLOCKED_ON_OTHER &&
- rfp->fp_task == driver_e && (rfp->fp_flags & FP_SUSP_REOPEN)) {
- rfp->fp_flags &= ~FP_SUSP_REOPEN;
- rfp->fp_blocked_on = FP_BLOCKED_ON_NONE;
- reply(&m_out, rfp->fp_endpoint, ERESTART);
- }
- }
-}
-
-
-/*===========================================================================*
- * reopen_reply *
- *===========================================================================*/
-static void reopen_reply(message *m_ptr)
-{
- endpoint_t driver_e;
- devmajor_t maj;
- int filp_no, status;
- struct filp *rfilp;
- struct vnode *vp;
- struct dmap *dp;
-
- driver_e = m_ptr->m_source;
- filp_no = m_ptr->REP_ENDPT;
- status = m_ptr->REP_STATUS;
-
- if (filp_no < 0 || filp_no >= NR_FILPS) {
- printf("VFS: reopen_reply: bad filp number %d from driver %d\n",
- filp_no, driver_e);
- return;
- }
-
- rfilp = &filp[filp_no];
- if (rfilp->filp_count < 1) {
- printf("VFS: reopen_reply: filp number %d not inuse (from driver %d)\n",
- filp_no, driver_e);
- return;
- }
-
- vp = rfilp->filp_vno;
- if (!vp) {
- printf("VFS: reopen_reply: no vnode for filp number %d (from driver "
- "%d)\n", filp_no, driver_e);
- return;
- }
-
- if (!(rfilp->filp_state & FS_NEEDS_REOPEN)) {
- printf("VFS: reopen_reply: bad state %d for filp number %d"
- " (from driver %d)\n", rfilp->filp_state, filp_no, driver_e);
- return;
- }
-
- if (!S_ISCHR(vp->v_mode)) {
- printf("VFS: reopen_reply: bad mode 0%o for filp number %d"
- " (from driver %d)\n", vp->v_mode, filp_no, driver_e);
- return;
- }
-
- maj = major(vp->v_sdev);
- dp = &dmap[maj];
- if (dp->dmap_driver != driver_e) {
- printf("VFS: reopen_reply: bad major %d for filp number %d "
- "(from driver %d, current driver is %d)\n", maj, filp_no,
- driver_e, dp->dmap_driver);
- return;
- }
-
- if (status == OK) {
- rfilp->filp_state &= ~FS_NEEDS_REOPEN;
- } else {
- printf("VFS: reopen_reply: should handle error status\n");
- return;
- }
-
- restart_reopen(maj);
-}
worker = worker_get(dp->dmap_servicing);
worker_stop(worker);
}
- cdev_up(major);
+ invalidate_filp_by_char_major(major);
}
}
}
newfilp->filp_count = 1;
newfilp->filp_vno = vp;
newfilp->filp_flags = O_RDONLY;
- FD_SET(newfd, &vmfp->fp_filp_inuse);
vmfp->fp_filp[newfd] = newfilp;
/* dup_vnode(vp); */
execi.vmfd = newfd;
EXTERN struct filp {
mode_t filp_mode; /* RW bits, telling how file is opened */
int filp_flags; /* flags from open and fcntl */
- int filp_state; /* state for crash recovery */
int filp_count; /* how many file descriptors share this slot?*/
struct vnode *filp_vno; /* vnode belonging to this file */
off_t filp_pos; /* file position */
int filp_pipe_select_ops;
} filp[NR_FILPS];
-#define FILP_CLOSED 0 /* filp_mode: associated device closed */
-
-#define FS_NORMAL 000 /* file descriptor can be used normally */
-#define FS_NEEDS_REOPEN 001 /* file descriptor needs to be re-opened */
-#define FS_INVALIDATED 002 /* file was invalidated */
+#define FILP_CLOSED 0 /* filp_mode: associated device closed/gone */
#define FSF_UPDATE 001 /* The driver should be informed about new
* state.
#endif
}
-/*===========================================================================*
- * do_filp_gc *
- *===========================================================================*/
-int do_filp_gc(void)
-{
-/* Perform filp garbage collection. Return whether at least one invalidated
- * filp was found, in which case the entire procedure will be invoked again.
- */
- struct filp *f;
- struct vnode *vp;
- int found = FALSE;
-
- for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
- if (!(f->filp_state & FS_INVALIDATED)) continue;
-
- found = TRUE;
-
- if (f->filp_mode == FILP_CLOSED || f->filp_vno == NULL) {
- /* File was already closed before gc could kick in */
- assert(f->filp_count <= 0);
- f->filp_state &= ~FS_INVALIDATED;
- f->filp_count = 0;
- continue;
- }
-
- assert(f->filp_vno != NULL);
- vp = f->filp_vno;
-
- /* Synchronize with worker thread that might hold a lock on the vp */
- lock_vnode(vp, VNODE_OPCL);
- unlock_vnode(vp);
-
- /* If garbage collection was invoked due to a failed device open
- * request, then common_open has already cleaned up and we have
- * nothing to do.
- */
- if (!(f->filp_state & FS_INVALIDATED)) {
- continue;
- }
-
- /* If garbage collection was invoked due to a failed device close
- * request, the close_filp has already cleaned up and we have nothing
- * to do.
- */
- if (f->filp_mode != FILP_CLOSED) {
- assert(f->filp_count == 0);
- f->filp_count = 1; /* So lock_filp and close_filp will do
- * their job */
- lock_filp(f, VNODE_READ);
- close_filp(f);
- }
-
- f->filp_state &= ~FS_INVALIDATED;
- }
-
- return found;
-}
-
/*===========================================================================*
* init_filps *
*===========================================================================*/
/* Search the fproc fp_filp table for a free file descriptor. */
for (i = start; i < OPEN_MAX; i++) {
- if (rfp->fp_filp[i] == NULL && !FD_ISSET(i, &rfp->fp_filp_inuse)) {
+ if (rfp->fp_filp[i] == NULL) {
/* A file descriptor has been located. */
*k = i;
break;
f->filp_select_ops = 0;
f->filp_pipe_select_ops = 0;
f->filp_flags = 0;
- f->filp_state = FS_NORMAL;
f->filp_select_flags = 0;
f->filp_softlock = NULL;
*fpt = f;
filp = NULL;
if (fild < 0 || fild >= OPEN_MAX)
err_code = EBADF;
- else if (rfp->fp_filp[fild] == NULL && FD_ISSET(fild, &rfp->fp_filp_inuse))
- err_code = EIO; /* The filedes is not there, but is not closed either.
- */
+ else if (locktype != VNODE_OPCL && rfp->fp_filp[fild] != NULL &&
+ rfp->fp_filp[fild]->filp_mode == FILP_CLOSED)
+ err_code = EIO; /* disallow all use except close(2) */
else if ((filp = rfp->fp_filp[fild]) == NULL)
err_code = EBADF;
else
/*===========================================================================*
* invalidate_filp *
*===========================================================================*/
-int invalidate_filp(struct filp *rfilp)
+void invalidate_filp(struct filp *rfilp)
{
-/* Invalidate filp. fp_filp_inuse is not cleared, so filp can't be reused
- until it is closed first. */
-
- int f, fd, n = 0;
- for (f = 0; f < NR_PROCS; f++) {
- if (fproc[f].fp_pid == PID_FREE) continue;
- for (fd = 0; fd < OPEN_MAX; fd++) {
- if(fproc[f].fp_filp[fd] && fproc[f].fp_filp[fd] == rfilp) {
- fproc[f].fp_filp[fd] = NULL;
- n++;
- }
- }
- }
+/* Invalidate filp. */
- rfilp->filp_state |= FS_INVALIDATED;
- return(n); /* Report back how often this filp has been invalidated. */
+ rfilp->filp_mode = FILP_CLOSED;
}
/*===========================================================================*
if (f->filp_count != 0 && f->filp_vno != NULL) {
if (major(f->filp_vno->v_sdev) == major &&
S_ISCHR(f->filp_vno->v_mode)) {
- (void) invalidate_filp(f);
+ invalidate_filp(f);
}
}
}
for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
if (f->filp_count != 0 && f->filp_vno != NULL) {
if (f->filp_vno->v_fs_e == proc_e)
- (void) invalidate_filp(f);
+ invalidate_filp(f);
}
}
}
if (filp->filp_softlock != NULL)
assert(filp->filp_softlock == fp);
- if (filp->filp_count > 0 || filp->filp_state & FS_INVALIDATED) {
+ if (filp->filp_count > 0) {
/* Only unlock vnode if filp is still in use */
/* and if we don't hold a soft lock */
/* Find an open slot in fp_filp */
for (fd = 0; fd < OPEN_MAX; fd++) {
- if (rfp->fp_filp[fd] == NULL &&
- !FD_ISSET(fd, &rfp->fp_filp_inuse)) {
-
+ if (rfp->fp_filp[fd] == NULL) {
/* Found a free slot, add descriptor */
- FD_SET(fd, &rfp->fp_filp_inuse);
rfp->fp_filp[fd] = cfilp;
rfp->fp_filp[fd]->filp_count++;
return(fd);
rfilp = (struct filp *) verify_fd(ep, fd);
if (rfilp != NULL) {
/* Found a valid descriptor, remove it */
- FD_CLR(fd, &rfp->fp_filp_inuse);
if (rfp->fp_filp[fd]->filp_count == 0) {
unlock_filp(rfilp);
printf("VFS: filp_count for slot %d fd %d already zero", slot,
}
unlock_bsf();
- /* Attempt to close only when feasible */
- if (!(f->filp_state & FS_INVALIDATED)) {
- (void) bdev_close(dev); /* Ignore errors */
- }
+ (void) bdev_close(dev); /* Ignore errors */
} else {
- /* Attempt to close only when feasible */
- if (!(f->filp_state & FS_INVALIDATED)) {
- (void) dev_close(dev); /* Ignore errors */
- }
+ (void) dev_close(dev); /* Ignore errors */
}
f->filp_mode = FILP_CLOSED;
release(vp, rw, susp_count);
}
- f->filp_count--; /* If filp got invalidated at device closure, the
- * count might've become negative now */
- if (f->filp_count == 0 ||
- (f->filp_count < 0 && f->filp_state & FS_INVALIDATED)) {
+ if (--f->filp_count == 0) {
if (S_ISFIFO(vp->v_mode)) {
/* Last reader or writer is going. Tell PFS about latest
* pipe size.
struct vnode *fp_wd; /* working directory; NULL during reboot */
struct vnode *fp_rd; /* root directory; NULL during reboot */
- struct filp *fp_filp[OPEN_MAX];/* the file descriptor table */
- fd_set fp_filp_inuse; /* which fd's are in use? */
+ struct filp *fp_filp[OPEN_MAX];/* the file descriptor table (free if NULL) */
fd_set fp_cloexec_set; /* bit map for POSIX Table 6-2 FD_CLOEXEC */
dev_t fp_tty; /* major/minor of controlling tty */
} fproc[NR_PROCS];
/* fp_flags */
-#define FP_NOFLAGS 00
-#define FP_SUSP_REOPEN 01 /* Process is suspended until the reopens are
- * completed (after the restart of a driver).
- */
+#define FP_NOFLAGS 0000
+#define FP_SRV_PROC 0001 /* Set if process is a service */
#define FP_REVIVED 0002 /* Indicates process is being revived */
#define FP_SESLDR 0004 /* Set if process is session leader */
#define FP_PENDING 0010 /* Set if process has pending work */
#define FP_EXITING 0020 /* Set if process is exiting */
#define FP_PM_WORK 0040 /* Set if process has a postponed PM request */
-#define FP_SRV_PROC 0100 /* Set if process is a service */
/* Field values. */
#define NOT_REVIVING 0xC0FFEEE /* process is not being revived */
/* Initialize process directories. mount_fs will set them to the
* correct values.
*/
- FD_ZERO(&(rfp->fp_filp_inuse));
+ for (i = 0; i < OPEN_MAX; i++)
+ rfp->fp_filp[i] = NULL;
rfp->fp_rd = NULL;
rfp->fp_wd = NULL;
}
else if ((r = get_fd(fp, fcntl_argx, 0, &new_fd, NULL)) == OK) {
f->filp_count++;
fp->fp_filp[new_fd] = f;
- FD_SET(new_fd, &fp->fp_filp_inuse);
r = new_fd;
}
break;
assert(f->filp_count > 0);
vmf->fp_filp[procfd] = f;
- /* mmap FD's are inuse */
- FD_SET(procfd, &vmf->fp_filp_inuse);
-
*newfilp = f;
return OK;
/* Claim the file descriptor and filp slot and fill them in. */
fp->fp_filp[scratch(fp).file.fd_nr] = filp;
- FD_SET(scratch(fp).file.fd_nr, &fp->fp_filp_inuse);
filp->filp_count = 1;
filp->filp_vno = vp;
filp->filp_flags = oflags;
if (r != OK) {
if (r != SUSPEND) {
fp->fp_filp[scratch(fp).file.fd_nr] = NULL;
- FD_CLR(scratch(fp).file.fd_nr, &fp->fp_filp_inuse);
filp->filp_count = 0;
filp->filp_vno = NULL;
- filp->filp_state &= ~FS_INVALIDATED; /* Prevent garbage col. */
put_vnode(vp);
}
} else {
close_filp(rfilp);
FD_CLR(fd_nr, &rfp->fp_cloexec_set);
- FD_CLR(fd_nr, &rfp->fp_filp_inuse);
/* Check to see if the file is locked. If so, release all locks. */
if (nr_locks > 0) {
return(r);
}
rfp->fp_filp[fil_des[0]] = fil_ptr0;
- FD_SET(fil_des[0], &rfp->fp_filp_inuse);
fil_ptr0->filp_count = 1; /* mark filp in use */
if ((r = get_fd(fp, 0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) {
rfp->fp_filp[fil_des[0]] = NULL;
- FD_CLR(fil_des[0], &rfp->fp_filp_inuse);
fil_ptr0->filp_count = 0; /* mark filp free */
unlock_filp(fil_ptr0);
unlock_vnode(vp);
return(r);
}
rfp->fp_filp[fil_des[1]] = fil_ptr1;
- FD_SET(fil_des[1], &rfp->fp_filp_inuse);
fil_ptr1->filp_count = 1;
/* Create a named pipe inode on PipeFS */
if (r != OK) {
rfp->fp_filp[fil_des[0]] = NULL;
- FD_CLR(fil_des[0], &rfp->fp_filp_inuse);
fil_ptr0->filp_count = 0;
rfp->fp_filp[fil_des[1]] = NULL;
- FD_CLR(fil_des[1], &rfp->fp_filp_inuse);
fil_ptr1->filp_count = 0;
unlock_filp(fil_ptr1);
unlock_filp(fil_ptr0);
fp->fp_blocked_on = why;
assert(fp->fp_grant == GRANT_INVALID || !GRANT_VALID(fp->fp_grant));
fp->fp_block_callnr = job_call_nr;
- fp->fp_flags &= ~FP_SUSP_REOPEN; /* Clear this flag. The caller
- * can set it when needed.
- */
}
/*===========================================================================*
for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) {
if (rp->fp_pid == PID_FREE) continue;
if (rp->fp_blocked_on == FP_BLOCKED_ON_OTHER && rp->fp_task == proc_e)
- revive(rp->fp_endpoint, EAGAIN);
+ revive(rp->fp_endpoint, EIO);
}
/* Revive processes waiting in drivers on select()s with EAGAIN too */
if (rp->fp_blocked_on == FP_BLOCKED_ON_POPEN ||
rp->fp_blocked_on == FP_BLOCKED_ON_LOCK ||
rp->fp_blocked_on == FP_BLOCKED_ON_OTHER) {
- if (!FD_ISSET(scratch(rp).file.fd_nr,
- &rp->fp_filp_inuse))
+ f = rp->fp_filp[scratch(rp).file.fd_nr];
+ if (f == NULL || f->filp_mode == FILP_CLOSED)
continue;
if (rp->fp_filp[scratch(rp).file.fd_nr]->filp_vno != vp)
continue;
break;
case FP_BLOCKED_ON_OTHER:/* process trying to do device I/O (e.g. tty)*/
- if (fp->fp_flags & FP_SUSP_REOPEN) {
- /* Process is suspended while waiting for a reopen.
- * Just reply EINTR.
- */
- fp->fp_flags &= ~FP_SUSP_REOPEN;
- status = EINTR;
- break;
- }
-
fild = scratch(fp).file.fd_nr;
if (fild < 0 || fild >= OPEN_MAX)
panic("file descriptor out-of-range");
/* device.c */
int dev_open(dev_t dev, int flags);
-int dev_reopen(dev_t dev, int filp_no, int flags);
int dev_close(dev_t dev);
void cdev_reply(void);
int bdev_open(dev_t dev, int access);
int bdev_close(dev_t dev);
void bdev_reply(struct dmap *dp);
int dev_io(int op, dev_t dev, endpoint_t proc_e, void *buf, off_t pos,
- size_t bytes, int flags, int suspend_reopen);
+ size_t bytes, int flags);
int gen_opcl(int op, dev_t dev, endpoint_t task_nr, int flags);
int gen_io(endpoint_t drv_e, message *mess_ptr);
int no_dev(int op, dev_t dev, endpoint_t proc, int flags);
int dev_cancel(dev_t dev);
void pm_setsid(endpoint_t proc_e);
void bdev_up(int major);
-void cdev_up(int major);
/* dmap.c */
void lock_dmap(struct dmap *dp);
vir_bytes *pc, vir_bytes *newsp, vir_bytes *ps_str, int flags);
/* filedes.c */
-int do_filp_gc(void);
void check_filp_locks(void);
void check_filp_locks_by_me(void);
void init_filps(void);
void lock_filp(struct filp *filp, tll_access_t locktype);
void unlock_filp(struct filp *filp);
void unlock_filps(struct filp *filp1, struct filp *filp2);
-int invalidate_filp(struct filp *);
+void invalidate_filp(struct filp *);
void invalidate_filp_by_endpt(endpoint_t proc_e);
void invalidate_filp_by_char_major(int major);
int do_verify_fd(message *m_out);
if (((f->filp_mode) & (ro ? R_BIT : W_BIT)) == 0) {
unlock_filp(f);
- return(f->filp_mode == FILP_CLOSED ? EIO : EBADF);
+ return(EBADF);
}
if (scratch(rfp).io.io_nbytes == 0) {
unlock_filp(f);
r = rw_pipe(rw_flag, for_e, f, buf, size);
} else if (S_ISCHR(vp->v_mode)) { /* Character special files. */
dev_t dev;
- int suspend_reopen;
int op = (rw_flag == READING ? DEV_READ_S : DEV_WRITE_S);
if(rw_flag == PEEKING) {
if (vp->v_sdev == NO_DEV)
panic("VFS: read_write tries to access char dev NO_DEV");
- suspend_reopen = (f->filp_state & FS_NEEDS_REOPEN);
dev = (dev_t) vp->v_sdev;
- r = dev_io(op, dev, for_e, buf, position, size, f->filp_flags,
- suspend_reopen);
+ r = dev_io(op, dev, for_e, buf, position, size, f->filp_flags);
if (r >= 0) {
/* This should no longer happen: all calls are asynchronous. */
printf("VFS: I/O to device %x succeeded immediately!?\n", dev);
major = major(f->filp_vno->v_sdev);
if (dmap_driver_match(proc_e, major)) {
se->filps[fd] = NULL;
- se->error = EINTR;
+ se->error = EIO;
select_cancel_filp(f);
wakehim = 1;
}