-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I have a some test code which basically creates a proc file within uml
which you can attach to a pair of host file descriptors using a command
line option. The idea here is to be able to run programs inside uml
with their input/output piped to/from processeses on the host.

My issue is with os_read_file()... initially, I used blocking I/O on the
host file descriptor with a single call to os_read_file() in the proc
entry's f_ops->read callback. I found out pretty quick that calling
system calls using blocking I/O locks up the whole user-mode kernel.

So, after browsing through the sources in arch/um/drivers/, I took some
pretty easy to understand code that uses nonblocking I/O and calls
schedule_timeout in a loop until a non-blocking read returns some data.
Here is my code for the procfile read callback and the schedule/read
loop helper...


static int hostfd_in = -1;
  ...

static ssize_t os_read_interruptible(int fd, struct file *filp,
  char *buf, size_t size, loff_t * offp)
{
  int n, ret = 0, err;

  err = os_set_fd_block(fd, 0);
  if(err != 0) {
    return err;
  }

  while(size) {
    n = os_read_file(fd, buf, size);
    if(n > 0) {
      return n;
    } else if(n == -EAGAIN) {
      if (filp->f_flags & O_NONBLOCK) {
        return ret ? : -EAGAIN;
      }
      if(need_resched()) {
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(1);
      }
    } else {
      return n;
    }
    if (signal_pending (current)) {
      return ret ? : -ERESTARTSYS;
    }
  }
  return ret;
}


static ssize_t hostfd_read(struct file *file, char *userbuf, size_t len,
  loff_t * offset)
{
  char *tmpbuf = NULL;
  int i = 0;

  if(hostfd_in < 0)
    return -EIO;

  tmpbuf = kmalloc(len, GFP_KERNEL);
  if(!tmpbuf)
    return -ENOMEM;

  i = os_read_interruptible(hostfd_in, file, tmpbuf, len, offset);

  if(i > 0) {
    if(copy_to_user(userbuf, tmpbuf, i)) {
      i = -EFAULT;
      goto out;
    }
  } else if(i == -EAGAIN) {
    i = 0;
    goto out;
  } else if(i == 0) {
    i = -EIO;
    goto out;
  }

out:
  kfree(tmpbuf);
  return i;
}


This is does the job, but while the os_read_interruptible helper is
waiting for data to arrive, since the time we wait before attempting
another non-blocking read is very short, the uml process uses a pretty
significant amount of the host's cpu cycles. I could increase the
timeout interval, but at the cost of extra latency between when data
actually becomes available on the fd and when we come back from the
schedule_timeout call to get it. This is obviously a suboptimal method.

So my question is: what is the right way to go about waiting for host
I/O to become available on a givel FD? It seems from looking at the uml
drivers that um_request_irq is used to request notification of various
asynchronous events from the host. If this can be used for waiting until
an fd is available for read or write, how? I tried looking around for
some code that uses um_request_irq for read/write, but couldn't seem to
find any.

If I am completely wrong about um_request_irq, then is there a mechanism
implented in UML for sleeping until a host FD becomes available? If not,
I assume that maybe it could be done with a helper process?

Thanks very much for your help!

- - V. Condino

(I appologize for bothering the UML developers with specific "How do I?"
questions... I'm not new to kernel programming, but some of the more
complicated aspects of UML's kernel APIs and implementation are still a
little .)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFDLnCJuFIK+j0m2f8RAkRgAKDKIl7fXnnaH+GMBNGwrfh/OkInQgCfYdcB
t7BLb2INkLiAyV77z2Wo2Z8=
=UmYA
-----END PGP SIGNATURE-----

Attachment: 0x7DBFE136.asc
Description: application/pgp-keys

Reply via email to