Remove support for reopening character devices

Previously, VFS would reopen a character device after a driver crash
if the associated file descriptor was opened with the O_REOPEN flag.
This patch removes support for this feature. The code was complex,
full of uncovered corner cases, and hard to test. Moreover, it did not
actually hide the crash from user applications: they would get an
error code to indicate that something went wrong, and have to decide
based on the nature of the underlying device how to continue.

- remove support for O_REOPEN, and make playwave(1) reopen its device;
- remove support for the DEV_REOPEN protocol message;
- remove all code in VFS related to reopening character devices;
- no longer change VFS filp reference count and FD bitmap upon filp
  invalidation; instead, make get_filp* fail all calls on invalidated
  FDs except when obtained with the locktype VNODE_OPCL which is used
  by close_fd only;
- remove the VFS fproc file descriptor bitmap entirely, returning to
  the situation that a FD is in use if its slot points to a filp; use
  FILP_CLOSED as single means of marking a filp as invalidated.

Change-Id: I34f6bc69a036b3a8fc667c1f80435ff3af56558f
This commit is contained in:
David van Moolenbroek 2013-09-10 16:06:37 +02:00 committed by Lionel Sambuc
parent a4277506a2
commit 87337273e4
17 changed files with 106 additions and 448 deletions

View file

@ -66,15 +66,36 @@ void usage()
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;
@ -91,22 +112,6 @@ int main ( int argc, char *argv[] )
}
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)
{
@ -141,15 +146,15 @@ int main ( int argc, char *argv[] )
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);
@ -203,6 +208,20 @@ int main ( int argc, char *argv[] )
{
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
{

View file

@ -198,7 +198,6 @@
#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 */
@ -209,7 +208,6 @@
#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 */

View file

@ -228,12 +228,6 @@ static void chardriver_reply(message *mess, int ipc_status, int r)
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;
@ -266,7 +260,7 @@ static void chardriver_reply(message *mess, int ipc_status, int r)
/*===========================================================================*
* 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;
@ -280,7 +274,7 @@ static int do_open(struct chardriver *cdp, message *m_ptr, int is_reopen)
/* 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);
@ -481,7 +475,7 @@ void chardriver_process(struct chardriver *cdp, message *m_ptr, int ipc_status)
*/
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. */
@ -490,8 +484,7 @@ void chardriver_process(struct chardriver *cdp, message *m_ptr, int ipc_status)
/* 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;

View file

@ -149,11 +149,10 @@ normal and PM work is the responsibility of the worker thread infrastructure.
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.
{{{
-------------------------------------------------------------------------
@ -167,8 +166,6 @@ 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 |
@ -677,15 +674,15 @@ a request. VFS does this with an arbitrary maximum of 5 attempts.
=== 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

View file

@ -3,7 +3,6 @@
*
* 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
@ -44,8 +43,6 @@
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;
@ -73,34 +70,6 @@ int dev_open(
}
/*===========================================================================*
* 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 *
*===========================================================================*/
@ -317,8 +286,7 @@ int dev_io(
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. */
@ -339,15 +307,6 @@ int dev_io(
/* 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);
@ -427,7 +386,7 @@ static int cdev_clone(dev_t dev, endpoint_t proc_e, devminor_t new_minor)
}
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);
@ -450,7 +409,7 @@ static int cdev_clone(dev_t dev, endpoint_t proc_e, devminor_t new_minor)
* 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 */
@ -485,17 +444,15 @@ int gen_opcl(
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);
@ -589,7 +546,7 @@ int do_ioctl(message *UNUSED(m_out))
{
/* 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;
@ -607,14 +564,13 @@ int do_ioctl(message *UNUSED(m_out))
}
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);
@ -924,31 +880,6 @@ void bdev_up(devmajor_t maj)
}
/*===========================================================================*
* 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 *
*===========================================================================*/
@ -1032,7 +963,6 @@ void cdev_reply(void)
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);
@ -1070,157 +1000,3 @@ void bdev_reply(struct dmap *dp)
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);
}

View file

@ -359,7 +359,7 @@ void dmap_endpt_up(endpoint_t proc_e, int is_blk)
worker = worker_get(dp->dmap_servicing);
worker_stop(worker);
}
cdev_up(major);
invalidate_filp_by_char_major(major);
}
}
}

View file

@ -325,7 +325,6 @@ int pm_exec(vir_bytes path, size_t path_len, vir_bytes frame, size_t frame_len,
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;

View file

@ -8,7 +8,6 @@
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 */
@ -29,11 +28,7 @@ EXTERN struct filp {
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.

View file

@ -75,64 +75,6 @@ void check_filp_locks(void)
#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 *
*===========================================================================*/
@ -163,7 +105,7 @@ int get_fd(struct fproc *rfp, int start, mode_t bits, int *k, struct filp **fpt)
/* 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;
@ -186,7 +128,6 @@ int get_fd(struct fproc *rfp, int start, mode_t bits, int *k, struct filp **fpt)
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;
@ -226,9 +167,9 @@ tll_access_t locktype;
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
@ -265,24 +206,11 @@ struct filp *find_filp(struct vnode *vp, mode_t bits)
/*===========================================================================*
* 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. */
/* Invalidate filp. */
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++;
}
}
}
rfilp->filp_state |= FS_INVALIDATED;
return(n); /* Report back how often this filp has been invalidated. */
rfilp->filp_mode = FILP_CLOSED;
}
/*===========================================================================*
@ -296,7 +224,7 @@ void invalidate_filp_by_char_major(int major)
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);
}
}
}
@ -312,7 +240,7 @@ void invalidate_filp_by_endpt(endpoint_t proc_e)
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);
}
}
}
@ -372,7 +300,7 @@ struct filp *filp;
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 */
@ -507,11 +435,8 @@ filp_id_t cfilp;
/* 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);
@ -586,7 +511,6 @@ int 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,
@ -653,15 +577,9 @@ struct filp *f;
}
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;
@ -674,10 +592,7 @@ struct filp *f;
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.

View file

@ -20,8 +20,7 @@ EXTERN struct fproc {
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 */
@ -59,16 +58,13 @@ EXTERN struct fproc {
} 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 */

View file

@ -389,7 +389,8 @@ static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *info)
/* 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;
}

View file

@ -121,7 +121,6 @@ int do_fcntl(message *UNUSED(m_out))
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;
@ -337,9 +336,6 @@ int dupvm(struct fproc *rfp, int pfd, int *vmfd, struct filp **newfilp)
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;

View file

@ -127,7 +127,6 @@ int common_open(char path[PATH_MAX], int oflags, mode_t omode)
/* 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;
@ -267,10 +266,8 @@ int common_open(char path[PATH_MAX], int oflags, mode_t omode)
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 {
@ -687,7 +684,6 @@ int fd_nr;
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) {

View file

@ -105,11 +105,9 @@ static int create_pipe(int fil_des[2], int flags)
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);
@ -117,7 +115,6 @@ static int create_pipe(int fil_des[2], int flags)
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 */
@ -126,10 +123,8 @@ static int create_pipe(int fil_des[2], int flags)
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);
@ -332,9 +327,6 @@ void suspend(int why)
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.
*/
}
/*===========================================================================*
@ -381,7 +373,7 @@ void unsuspend_by_endpt(endpoint_t proc_e)
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 */
@ -436,8 +428,8 @@ int count; /* max number of processes to release */
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;
@ -570,15 +562,6 @@ void unpause(void)
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");

View file

@ -30,14 +30,13 @@ void send_work(void);
/* 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);
@ -51,7 +50,6 @@ int dev_select(dev_t dev, int ops);
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);
@ -78,7 +76,6 @@ int pm_exec(vir_bytes path, size_t path_len, vir_bytes frame, size_t frame_len,
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);
@ -90,7 +87,7 @@ struct filp *get_filp2(struct fproc *rfp, int fild, tll_access_t locktype);
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);

View file

@ -105,7 +105,7 @@ int actual_read_write_peek(struct fproc *rfp, int rw_flag, int io_fd,
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);
@ -160,7 +160,6 @@ int read_write(struct fproc *rfp, int rw_flag, struct 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) {
@ -171,11 +170,9 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f,
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);

View file

@ -752,7 +752,7 @@ void select_unsuspend_by_endpt(endpoint_t proc_e)
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;
}