Page MenuHomeFreeBSD

Add sbuf streaming mode to pseudofs(9), use in linprocfs(5)
ClosedPublic

Authored by cem on Nov 2 2020, 12:38 AM.
Tags
None
Referenced Files
Unknown Object (File)
Sun, Dec 8, 6:29 PM
Unknown Object (File)
Wed, Dec 4, 12:56 PM
Unknown Object (File)
Sun, Nov 17, 6:40 PM
Unknown Object (File)
Wed, Nov 13, 8:27 AM
Unknown Object (File)
Mon, Nov 11, 5:07 AM
Unknown Object (File)
Sun, Nov 10, 9:52 PM
Unknown Object (File)
Sun, Nov 10, 6:15 PM
Unknown Object (File)
Sun, Nov 10, 2:53 PM
Subscribers

Details

Summary

Add a pseudofs node flag 'PFS_AUTODRAIN', which automatically emits sbuf
contents to the caller when the sbuf buffer fills. This is only
permissible if the corresponding PFS node fill function can sleep
whenever it appends to the sbuf.

linprocfs' /proc/self/maps node happens to meet this requirement.
Streaming out the file as it is composed avoids truncating the output
and also avoids preallocating a very large buffer.

Test Plan

Eliminates this problem triggered by, e.g., Chrome:

linux: pid 713 (chromium-browse): cannot fill /proc/self/maps; consider bumping PFS_MAXBUFSIZ

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

cem requested review of this revision.Nov 2 2020, 12:38 AM
cem created this revision.

Nice work, thanks - will try to review soon if someone else doesn't first.

sys/fs/pseudofs/pseudofs.h
71 ↗(On Diff #79051)

I guess these flags are documented only here

emaste added subscribers: kib, markj.

Looks fine to the extent of my knowledge of sbuf(9).
I mentioned this review to @markj and @kib out of band in case they have more insight.

sys/fs/pseudofs/pseudofs_vnops.c
732–735 ↗(On Diff #79051)

I'm not sure the C99 compound literal here is an improvement over just

ssh.skip_bytes = uio->uio_offset;
ssh.uio = uio;

No real objection and not a big deal though; I mention it only in case there's some benefit I'm missing.

This revision is now accepted and ready to land.Nov 2 2020, 5:18 PM

Also as it happens there was a reference to the issue fixed by this on -curent in the last day or two

sys/fs/pseudofs/pseudofs_vnops.c
725 ↗(On Diff #79051)

Why is the + 1 here? For AUTODRAIN routines it means that sbuf has to allocate 4097->8192 bytes.

Also as it happens there was a reference to the issue fixed by this on -curent in the last day or two

Yeah, I saw.

sys/fs/pseudofs/pseudofs_vnops.c
725 ↗(On Diff #79051)

I’m not sure it makes any sense for the non-autodrain interface either. I haven’t investigated the history, but IMO it can be dropped.

732–735 ↗(On Diff #79051)

The only real benefit is zeroing new struct fields as they are added in the future. Your proposal plus bzero would be similar. In this context I agree it is not especially useful.

sys/fs/pseudofs/pseudofs_vnops.c
732–735 ↗(On Diff #79051)

Fair point. I guess padding is unspecified in the C99 compound literal still.

sys/fs/pseudofs/pseudofs_vnops.c
725 ↗(On Diff #79051)

I think the idea is that sbufs are always nul-terminated / always reserve a byte of the buffer for a trailing nul. So to the extent buflen is derived from uio_resid, rather than a truncated value, we want to fulfill the entire request. However, I think that just means we should move the + 1 above, something like:

buflen = io->uio_offset + uio->uio_resid + 1;
...
sb = sbuf_new(..., buflen, ...);
...
if (!(pn->pn_flags & PFS_AUTODRAIN)) {
    if (error == 0)
        buflen = sbuf_len(sb);
    else
        /* In overflow case, valid length does not include trailing nul. */
        buflen--;
    error = uiomove_frombuf(..., buflen, ...);
}
cem marked 2 inline comments as done.
  • Fix buflen+1 logic. As a side effect, the maximal limit for pfs fill routines is one byte smaller (of 1MB).
  • Drop compound literal for struct initialization.
This revision now requires review to proceed.Nov 2 2020, 8:47 PM

This is much better than my workarounds, thank you!

This revision is now accepted and ready to land.Nov 3 2020, 1:25 PM
sys/fs/pseudofs/pseudofs_vnops.c
725 ↗(On Diff #79051)

Hm, I'm reconsidering this.

(1) Chrome tries to read exactly a page at a time, and it's a bit silly to limit each chunk to 4095 bytes.

(2) sbuf itself shouldn't be 'extending' our given size, because we do not use the SBUF_AUTOEXTEND flag. So I think sbuf will just malloc(4097) bytes. Is the 4097 -> 8192 you're thinking coming from malloc(9)?

cem marked an inline comment as not done.Nov 3 2020, 9:22 PM
cem added inline comments.
sys/fs/pseudofs/pseudofs_vnops.c
654 ↗(On Diff #79090)

This needs to return len + the number of bytes we skipped in the partial seek case above. Fixed in my local tree.

sys/fs/pseudofs/pseudofs_vnops.c
725 ↗(On Diff #79051)

Yes, my belief is that malloc() will end up using two whole pages for a 4097-byte allocation. Not the end of the world, but if we go that route I think it'd be worthwhile to add a comment.

Does SBUF_INCLUDENUL help you here?

sys/fs/pseudofs/pseudofs_vnops.c
725 ↗(On Diff #79051)

Ah, ok.

SBUF_INCLUDENUL doesn't help; it only changes how sbuf_len() behaves.

We'd probably prefer a new SBUF_BINARY mode (or something) which does not reserve a byte for trailing NUL, but the 4095 thing isn't the end of the world (nor 2 pages).

  • Fix sbuf drain length math when a partial seek occurred
  • Early terminate pseudofs auto-drain fill routines when caller's uio is fully consumed
This revision now requires review to proceed.Nov 3 2020, 10:27 PM
cem marked an inline comment as done.Nov 3 2020, 10:27 PM
sys/fs/pseudofs/pseudofs_vnops.c
725 ↗(On Diff #79051)

Hmm, SBUF_INCLUDENUL also determines whether the nul byte is included in the buffer passed to the drain function, but that's not what we want here. So the choices are to add a new mode as you suggested, overallocate, or drain 4095 bytes at a time.

sys/fs/pseudofs/pseudofs_vnops.c
725 ↗(On Diff #79051)

For now, I've gone with the 4095-at-a-time option.

This revision is now accepted and ready to land.Nov 4 2020, 6:06 PM