VFS: update filp_pos on chardev I/O (workaround)

Previously, reading from or writing to a character device would not
update the file position on the corresponding filp object.  Performing
this update correctly is not trivial: during and after the I/O
operation, the filp object must not be locked.  Ideally, read/write
requests on a filp that is already involved in a read/write operation,
should be queued.  For now, we optimistically update the file position
at the start of the I/O; this works under the assumptions listed in
the corresponding comment.

Change-Id: I172a61781850423709924390ae3df1f2d1f94707
This commit is contained in:
David van Moolenbroek 2013-09-02 17:34:44 +02:00 committed by Lionel Sambuc
parent 660d34cd85
commit 5c53b417cd

View file

@ -177,9 +177,31 @@ int read_write(struct fproc *rfp, int rw_flag, struct filp *f,
r = dev_io(op, dev, for_e, buf, position, size, f->filp_flags,
suspend_reopen);
if (r >= 0) {
/* This should no longer happen: all calls are asynchronous. */
printf("VFS: I/O to device %x succeeded immediately!?\n", dev);
cum_io = r;
position += cum_io;
position += r;
r = OK;
} else if (r == SUSPEND) {
/* FIXME: multiple read/write operations on a single filp
* should be serialized. They currently aren't; in order to
* achieve a similar effect, we optimistically advance the file
* position here. This works under the following assumptions:
* - character drivers that use the seek position at all,
* expose a view of a statically-sized range of bytes, i.e.,
* they are basically byte-granular block devices;
* - if short I/O or an error is returned, all subsequent calls
* will return (respectively) EOF and an error;
* - the application never checks its own file seek position,
* or does not care that it may end up having seeked beyond
* the number of bytes it has actually read;
* - communication to the character driver is FIFO (this one
* is actually true! whew).
* Many improvements are possible here, but in the end,
* anything short of queuing concurrent operations will be
* suboptimal - so we settle for this hack for now.
*/
position += size;
}
} else if (S_ISBLK(vp->v_mode)) { /* Block special files. */
if (vp->v_sdev == NO_DEV)