9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* Re: [9fans] 9P reading directories client/server behavior
@ 2021-03-09 14:05 nicolagi via 9fans
  2021-03-09 20:01 ` Anthony Martin
  0 siblings, 1 reply; 6+ messages in thread
From: nicolagi via 9fans @ 2021-03-09 14:05 UTC (permalink / raw)
  To: 9fans

As it often happens to me, a few minutes after hitting send, I am
enlightened and embarassed. :-) I had a bit of tunnel vision there, and
didn't think of looking at another 9P trace.  When I run "9p ls foo/bar"
I get the below trace, which answers most of my questions.

        Tread tag 0 fid 1 offset 0 count 8168
        Rread tag 0 count 8109
        Tread tag 0 fid 1 offset 8109 count 8168
        Rread tag 0 count 5410
        Tread tag 0 fid 1 offset 13519 count 8168
        Rread tag 0 count 0

I took a quick look at sys/src/cmd/cwfs/9p2.c and I think it shows the
server should silently return 0 bytes and no errors, even if the 0-byte
return is due to the read buffer not being large enough for the next
dir entry.

The only question that still stands is the last in my original post:
What happens and what should happen when a dir entry is larger than
msize-24? Possibly written from a connection with a large msize, and to
be read from a connection with a smaller msize?

Thanks,

Nicola


------------------------------------------
9fans: 9fans
Permalink: https://9fans.topicbox.com/groups/9fans/T42be63e964005519-Md34dba086f695e0bf63be25f
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [9fans] 9P reading directories client/server behavior
  2021-03-09 14:05 [9fans] 9P reading directories client/server behavior nicolagi via 9fans
@ 2021-03-09 20:01 ` Anthony Martin
  0 siblings, 0 replies; 6+ messages in thread
From: Anthony Martin @ 2021-03-09 20:01 UTC (permalink / raw)
  To: 9fans

nicolagi via 9fans <9fans@9fans.net> once said:
> The only question that still stands is the last in my original post:
> What happens and what should happen when a dir entry is larger than
> msize-24? Possibly written from a connection with a large msize, and to
> be read from a connection with a smaller msize?

In that case either the server or client lied about it's
msize and is not correctly speaking the 9p protocol.

From version(5):

        The client suggests a maximum message size, msize, that is
        the maximum length, in bytes, it will ever generate or ex-
        pect to receive in a single 9P message. This count includes
        all 9P protocol data, starting from the size field and ex-
        tending through the message, but excludes enveloping trans-
        port protocols. The server responds with its own maximum,
        msize, which must be less than or equal to the client's
        value. Thenceforth, both sides of the connection must honor
        this limit.

Cheers,
  Anthony

------------------------------------------
9fans: 9fans
Permalink: https://9fans.topicbox.com/groups/9fans/T42be63e964005519-Mcceb79ab7dadcad157ebec8a
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [9fans] 9P reading directories client/server behavior
  2021-04-09 20:00 ` Russ Cox
@ 2021-04-14 18:06   ` nicolagi via 9fans
  0 siblings, 0 replies; 6+ messages in thread
From: nicolagi via 9fans @ 2021-04-14 18:06 UTC (permalink / raw)
  To: 9fans

On Fri, Apr 09, 2021 at 04:00:35PM -0400, Russ Cox wrote:
> On March 9, 2021, Plan 9 from Bell Labs <9fans@9fans.net> wrote:
> > I was trying to use 9fans/go/plan9/client.Fid.Dirreadall
> > [https://github.com/9fans/go/blob/master/plan9/client/fid.go#L54-L60]
> > and found that it returned fewer entries than a single Dirread. The
> > reason is that Dirreadall uses ioutil.ReadAll which doesn't work
> > well with a fid corresponding to a directory, because it spuriously
> > detects io.EOF when in fact there are more dir entries, but none
> > fits into the read buffer.
> 
> Fixed, thanks.

Argh, I totally forgot to send a patch, sorry about that!
OTOH, I'm sure it took you a minute or so to fix this issue...

Thank you for all the answers.

------------------------------------------
9fans: 9fans
Permalink: https://9fans.topicbox.com/groups/9fans/T36fa75fb83c81d6d-M733cffffc82853c8d11e70e8
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [9fans] 9P reading directories client/server behavior
  2021-03-09 13:32 nicolagi via 9fans
@ 2021-04-09 20:00 ` Russ Cox
  2021-04-14 18:06   ` nicolagi via 9fans
  0 siblings, 1 reply; 6+ messages in thread
From: Russ Cox @ 2021-04-09 20:00 UTC (permalink / raw)
  To: Plan 9 from Bell Labs

[-- Attachment #1: Type: text/plain, Size: 3058 bytes --]

On March 9, 2021, Plan 9 from Bell Labs <9fans@9fans.net> wrote:
> I was trying to use 9fans/go/plan9/client.Fid.Dirreadall
> [https://github.com/9fans/go/blob/master/plan9/client/fid.go#L54-L60]
> and found that it returned fewer entries than a single Dirread. The
> reason is that Dirreadall uses ioutil.ReadAll which doesn't work
> well with a fid corresponding to a directory, because it spuriously
> detects io.EOF when in fact there are more dir entries, but none
> fits into the read buffer.

Fixed, thanks.

As for Linux,

> When it gets a 0-byte Rread, it tries a new Tread with the largest
> possible buffer size (msize=8192 in this connection). You see this
> behavior twice above. Only after getting 0-byte Rread twice in a
> row, it gives up.
>
> QUESTION. The last Tread/Rread seems superflous to me. After
> enlarging the buffer size from 2758 to 8168 and still getting 0, I'd
> think the client could detect EOF. I don't see the point of an
> additional Tread of 8168 bytes.

Probably the code just always retries with max, even if the buffer was
already max'ed. I agree that it seems unnecessary.

> QUESTION. But other than that, is that what a client should do for
> reading directories? Enlarge the read buffer and see if it still
> gets 0 bytes? I'm asking because my initial fix to Dirreadall was to
> always issue Treads with count=msize-24, and because I find the
> above approach to incur 2x the round trips necessary.

Properly, a client should always make sure there are STATMAX bytes
available in the read (perhaps limited by msize).


> QUESTION. Similarly, is the server supposed to silently return a
> 0-byte Rread when no dir entries fit in the response buffer, despite
> there being more dir entries available?

It would appear that that's what keeps things working.
The original Plan 9 dirread and dirreadall did not exercise this case,
so there's not likely to be agreement between servers on the answer.

> Finally, I noticed the plan9.STATMAX (65535) as the buffer size used
> in Dirread (a few lines above Dirreadall). That points to the fact
> that in theory that's the max size of a serialized dir entry, which
> leads me to ask one last
>
> QUESTION. What happens and what should happen when a dir entry is
> larger than msize-24? Possibly written from a connection with a
> large msize, and to be read from a connection with a smaller msize?

Probably that should return an error, rather than a silent EOF.
It honestly never came up, because first a server would have to
let you create a file with an almost-8k name (or else have very long
user and group names). disk/kfs limited names to 27 bytes, and
fossil limited all strings to 1k. So the max directory entry size in
any server anyone ran was under 4k.��

Best,
Russ

------------------------------------------
9fans: 9fans
Permalink: https://9fans.topicbox.com/groups/9fans/T36fa75fb83c81d6d-M1168d8ea3f8e0caf83fb6f27
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription

[-- Attachment #2: Type: text/html, Size: 6166 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [9fans] 9P reading directories client/server behavior
@ 2021-03-10 19:36 nicolagi via 9fans
  0 siblings, 0 replies; 6+ messages in thread
From: nicolagi via 9fans @ 2021-03-10 19:36 UTC (permalink / raw)
  To: 9fans

Quoting Anthony Martin <ality@pbrane.org>:
> nicolagi via 9fans <9fans@9fans.net> once said:
>> The only question that still stands is the last in my original post:
>> What happens and what should happen when a dir entry is larger than
>> msize-24? Possibly written from a connection with a large msize, and to
>> be read from a connection with a smaller msize?
> 
> In that case either the server or client lied about it's
> msize and is not correctly speaking the 9p protocol.
> 
>>From version(5):
> 
>         The client suggests a maximum message size, msize, that is
>         the maximum length, in bytes, it will ever generate or ex-
>         pect to receive in a single 9P message. This count includes
>         all 9P protocol data, starting from the size field and ex-
>         tending through the message, but excludes enveloping trans-
>         port protocols. The server responds with its own maximum,
>         msize, which must be less than or equal to the client's
>         value. Thenceforth, both sides of the connection must honor
>         this limit.

Different clients can still negotiate different values for msize.
I've written a program to show that the scenario I'm talking about
is real.  Here's the trace that shows creating a file with an absurdly
large name (name omitted):

        Tversion msize 131072 version '9P2000'
        Rversion msize 131072 version '9P2000'
        Tattach fid 1 afid 4294967295 uname 'nicolagi' nuname 4294967295 aname ''
        Rattach aqid (16061c98c25a5b1c 1 'd')
        Twalk fid 1 newfid 2 0:'tmp' 
        Rwalk (16061c9a5c4069e4 1 'd') 
        Tcreate fid 2 name 'ality.OMITTED' perm 666 mode 0 
        Rcreate qid (166b10d3f614e29e 1 '') iounit 0
        Tclunk fid 2
        Rclunk

Listing using a connection with msize 8192 and grepping the new file:

        ; 9p ls pine/tmp | grep ality | wc -l
        0

I can create another file after the absurdly named one, but I can't
list it, because the client wrongly detects EOF before reaching that:

        ; date > another
        ; ls | grep another | wc -l
        0

You can see why I thought a server may return Rerror instead of silently
clipping the listing.  But it's fine, nobody will generate such large
dir entries, I was just confused to find this edge case and around how
to handle it.

I'll go write some client code to clean up my tmp folder now. :-)


------------------------------------------
9fans: 9fans
Permalink: https://9fans.topicbox.com/groups/9fans/T65a81624b7b9db0f-Mf45bcfc5bcd0d01d25fda0e1
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [9fans] 9P reading directories client/server behavior
@ 2021-03-09 13:32 nicolagi via 9fans
  2021-04-09 20:00 ` Russ Cox
  0 siblings, 1 reply; 6+ messages in thread
From: nicolagi via 9fans @ 2021-03-09 13:32 UTC (permalink / raw)
  To: 9fans

Dear 9fans,

I'm confused regarding the correct behavior for a Tread handler for
directories, and the corresponding correct behavior for a client
that wants to read the whole contents of a directory.

I was trying to use 9fans/go/plan9/client.Fid.Dirreadall
[https://github.com/9fans/go/blob/master/plan9/client/fid.go#L54-L60]
and found that it returned fewer entries than a single Dirread. The
reason is that Dirreadall uses ioutil.ReadAll which doesn't work
well with a fid corresponding to a directory, because it spuriously
detects io.EOF when in fact there are more dir entries, but none
fits into the read buffer. Example trace:

        Tread tag 65535 fid 2 offset 0 count 512
        Rread tag 65535 count 499
        Tread tag 65535 fid 2 offset 499 count 13
        Rread tag 65535 count 0

There would be more dir entries, but the one at offset 499 is longer
than 13 bytes, so none is returned.

It follows that Dirreadall is buggy, but let's set aside the
discussion of a fix for a moment. Now consider this instead: I also
thought that my server was at fault: perhaps it should respond with
Rerror of some kind instead of a 0-byte Rread. The rationale was
that it's risky for directory contents to disappear if the client
doesn't have large enough buffers.

When I tried that change in my fs, I found that I could no
longer list directories when mounted under Linux. Restoring the
original code that responds with 0-byte Rread, I traced the Linux
driver's behaviour when listing a directory:

        Tread tag 0 fid 2 offset 0 count 8168
        Rread tag 0 count 8109
        Tread tag 0 fid 2 offset 8109 count 59
        Rread tag 0 count 0
        Tread tag 0 fid 2 offset 8109 count 8168
        Rread tag 0 count 5410
        Tread tag 0 fid 2 offset 13519 count 2758
        Rread tag 0 count 0
        Tread tag 0 fid 2 offset 13519 count 8168
        Rread tag 0 count 0
        Tread tag 0 fid 2 offset 13519 count 8168
        Rread tag 0 count 0

When it gets a 0-byte Rread, it tries a new Tread with the largest
possible buffer size (msize=8192 in this connection). You see this
behavior twice above. Only after getting 0-byte Rread twice in a
row, it gives up.

QUESTION. The last Tread/Rread seems superflous to me. After
enlarging the buffer size from 2758 to 8168 and still getting 0, I'd
think the client could detect EOF. I don't see the point of an
additional Tread of 8168 bytes.

QUESTION. But other than that, is that what a client should do for
reading directories? Enlarge the read buffer and see if it still
gets 0 bytes? I'm asking because my initial fix to Dirreadall was to
always issue Treads with count=msize-24, and because I find the
above approach to incur 2x the round trips necessary.

QUESTION. Similarly, is the server supposed to silently return a
0-byte Rread when no dir entries fit in the response buffer, despite
there being more dir entries available?

Finally, I noticed the plan9.STATMAX (65535) as the buffer size used
in Dirread (a few lines above Dirreadall). That points to the fact
that in theory that's the max size of a serialized dir entry, which
leads me to ask one last

QUESTION. What happens and what should happen when a dir entry is
larger than msize-24? Possibly written from a connection with a
large msize, and to be read from a connection with a smaller msize?

Thank you,

Nicola


------------------------------------------
9fans: 9fans
Permalink: https://9fans.topicbox.com/groups/9fans/T36fa75fb83c81d6d-Ma709ac1a88a1167f9a50ce45
Delivery options: https://9fans.topicbox.com/groups/9fans/subscription

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-04-14 18:06 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-09 14:05 [9fans] 9P reading directories client/server behavior nicolagi via 9fans
2021-03-09 20:01 ` Anthony Martin
  -- strict thread matches above, loose matches on Subject: below --
2021-03-10 19:36 nicolagi via 9fans
2021-03-09 13:32 nicolagi via 9fans
2021-04-09 20:00 ` Russ Cox
2021-04-14 18:06   ` nicolagi via 9fans

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).