logo       

Re: file: module and character special files: msg#00338

lang.erlang.general

Subject: Re: file: module and character special files

Hello,

They say I should comment on this, so I'll do it.

The interesting part is last, so read from the end if you're only interested in that :-)

Richard A. O'Keefe wrote:

I asked why file: doesn't handle /dev/null correctly.

"Erik Stenman" <Erik.Stenman@xxxxxxx> and matthias@xxxxxxxxxxxx
both pointed me to Patrik Nyblom's explanation from nearly four
years ago:

http://www.erlang.org/ml-archive/erlang-questions/200003/msg00018.html

The argument goes like this:
(a) it is hard to get non-blocking I/O going portably across UNIXes.
(b) therefore the file: module relies on a driver which does blocking
I/O, which only really works if the I/O *doesn't* block, means
that only "fast" devices are supported.
(c) which means that only 'regular' files are supported.
(d) which is why /dev/null is rejected.
(e) which is why you get the "eisdir" error message.


Ad (e): there is no excuse for giving the wrong error message.
The error message should indicate plainly that only regular files
are supported; it certainly should NOT state something that is
patently untrue! If nothing else is done, 4 years is quite long
enough for a badly misleading message to be KNOWN to lurk in the
system; time to fix it.

As I originally said, the return value is misleading. The return value is one issue, the fact that
device files cannot be opened is another. My post was aimed at explaining the reason, not the exact
return value. As you focus the argumentation on the return value in itself, I'll try to explain that as well...

Someone decided, a long time ago, that EISDIR was a good return value here, when something
on the line of "this is not a regular file" would have been better. That may have been a bad choise.
However, changing return values isn't all that popular among people having miljons of lines of code
slushing around in systems supposed to have an ISP of 99.999 or better. Therefore the prio of such a
change isn't all that high. It's not really a big deal either, honestly. I think most users think there are
larger issues we should work on, but I might be wrong :-)


Ad (d): /dev/null is the fastest device there is. Read from it,
and you're immediately told "end of file" without any peripheral
activity at all. Write to it, and the bytes are immediately thrown
away without any peripheral activity at all. Nyblom's argument
about tape drives blocking Erlang processes for long times is
NO ARGUMENT AT ALL against supporting /dev/null. /dev/null is
so useful for testing that if the driver has to make a special case:
if stat(2) says the file is a regular file
or stat(2) says the file is a character special file
and the name is /dev/null
then open the file
otherwise report "regular file needed"
then so be it. I _think_ the requisite change is to
erts/emulator/drivers/unix/unix_efile.c
in the function efile_openfile(), where the lines
if (!ISREG(statbuf)) {
close(fd);
errno = EISDIR;
return check_error(-1, errInfo);
}
should be
if (!ISREG(statbuf)
&& !(ISDEV(statbuf) && 0 == strcmp(name, "/dev/null"))
) {
close(fd);
errno = EISDIR;
return check_error(-1, errInfo);
}
This is also the place where something should be done about (e),
even if it does mean defining an ENOTREG error number that is not
one of the usual UNIX error numbers.

I get your point, but obviously the suggested patch would not solve any real problem.

With your patch applied:
----------------------
Erlang (BEAM) emulator version 5.4 [source] [threads:0]

Eshell V5.4 (abort with ^G)
1> file:open("/dev/null",[read]).
{ok,<0.31.0>}
2> cd("/dev"). /dev
ok
3> file:open("null",[read]).
{error,eisdir}
4>
---------------------------
This is of course easy to fix, but it indicates that the string-matching-magic-filename approach is no good.
In fact the approach works even worse for other obvious cases, i.e. with a hard link to /dev/null, opening /dev/zero (which is bleeding fast as well) etc.

Whoever wrote the original file driver draw the line at regular files, as that can be determined.

Whoever that person was, I think he or she was right in doing this.

However, with a different implementation than the original, the line could be drawn somewhere else, see below.


Ad (c): it has NOT been true for a long time that "operations won't
block" on regular files. Not since RFS and NFS came into use.
The file system I see on my main machine is spread across three
different nodes; the machine I'm posting from brings in another.
I have known read() operations on what *looked* like "regular" files
take 30 seconds. (On one memorable occasion, several hours.)

It is true that NFS can make reading from regular files block. We cannot handle that
and we cannot "see" if a file is on local or remote filesystem from the driver. The OS'es
don't provide sufficient interfaces to del with such things.

We do not recommend people writing real-time systems relying on NFS over unstable network
connections either, but that's beside the point.

Still, it would not help to use select or poll. File handles for NFS files behave like file handles for
any other file system, they are always available for reading and writing. It's not unsolvable, but
looking for the unix-dialect where select/poll can be used to se if the nfs server is accessible is
not a feasible solution.


Ad (b): I don't really understand the present design (the internal
documentation of the file driver code is, shall we say, sparse), so
I can't comment.

Ad (a): while there may be UNIX systems whose implementors have
disgraced themselves by failing to make poll() or select() work
on files, in the light of the fact that "regular" file operations
can't really be trusted to be fast, it might be a good thing to have
a poll/select-based driver that could be used in UNIX systems where
those functions *do* work with files. (This is the kind of thing that
./configure can figure out.)

I wrote "lots of u*x'es" in the four year old letter, I should have written "any unix system we know of" instead.
If things have changed during the last years, that might have been interesting if we hadn't found a more
general solution to the problem.

Note that select/poll does indeed "work" on regular files in the sense that they don't
result in an error return, they simply always signal that data is writable to and
readable from the file descriptor regardless of the actual facts.

*****************************************************************
End of implementation discussion. Now comes the interesting part:

Tony Rogvall (together with others) has made a remarkable
*real, working, and portable* implementation
of a threaded file driver, submitted it to us, and that is the one nowdays present in the emulator.

That driver, to some extent, solves the NFS problem. It's working well for
all unixes that haven't failed to implement threads properly in the kernel
(maybe those without kernel threads are the one that really have disgraced themselves :-).

Among platforms where this work well are Solaris, Linux, Windows and many others.

This obviously means that given a large enough thread pool, opening device files like /dev/null with this driver
would be a much better idea than it was in the single threaded case. So, what *should* be changed in the file driver,
is more on the lines of

If the file is regular then
open
else
If the file is not a directory and
you have more than one I/O thread and
you have chosen to explicitly enable the feature by some means then
open the thing anyway
else
return some error
endif
endif

Were "return some error" actually still might mean "eisdir", especially if one wants
the fix done in time for the next release...


Erik Stenman ended his reply thus:
That post ends with:
"Maybe an alternative "any-type-of-file-driver" which uses
threads/separate processes would be nice though."

Maybe we can get OTP to implement this if there are enough requests
for a feature like that on the list, or maybe someone already has such a driver somewhere that could be contributed to the community?

So, allowing device files to be opened from within the file driver could
be done.
Is there really anyone needing this? Speak up in that case and someone will add it. The return value is another issue
though, that needs confirmation from the ones actually paying for all this...


I was trying to "sell" the idea of using Erlang to a consultant.
What he _really_ wanted was a framework where he could open
URIs with at least the file, http, and ftp schemes either for input
or for output, like you can in Java. Now, by using an outboard
program like cURL, this could be reduced to the problem of UNIX pipe
I/O, but that does mean that a driver that can handle both files
(with all the network delays that are implied by networked/remote/
shared file systems) and pipes (with all the delays implied by running
programs that may have to wait for other things to happen) would be of
use to Erlang. It's a *much* bigger problem than just /dev/null, and
a much bigger opportunity.

Nice idea, with the change suggested above and a bunch of I/O-threads, nothing in Erlang stops you from writing such a thing.
Ftp is already there, http is a piece of cake, file I/O with threads is non-blocking... A simple wrapper and some HTTP stuff.




Best regards,
/Patrik




<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

News | FAQ | advertise