Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 18 Sep 1995 20:26:10 -0700 (MST)
From:      Terry Lambert <terry@lambert.org>
To:        davidg@root.com
Cc:        terry@lambert.org, julian@freefall.freebsd.org, hackers@freefall.freebsd.org
Subject:   Re: why is this not a bug in namei?
Message-ID:  <199509190326.UAA09176@phaeton.artisoft.com>
In-Reply-To: <199509182328.QAA03738@corbin.Root.COM> from "David Greenman" at Sep 18, 95 04:28:56 pm

next in thread | previous in thread | raw e-mail | index | archive | help
> >The patches happen to modify vfs_syscalls.c for single entry/exit for all
> >functions at the same time, something that was required for buffer
> >allocation bookkeeping and wants to be done for kernel multithreading and
> >SMP kernel reentrancy in any case.
> 
>    There are some cases where a single entry point is useful, but I personally
> hate the spaghetti of goto's that I've seen with your code.

That would be three of them, max, in a single function, right?

According to a Bell Labs study, human beings are capable of keeping 5 to
9 items in short term memory simultaneously.  That would be why phone
numbers are 7 digits.

I'm not even taxing the low end of the study participants.

On the other hand, if I want block profiling without having to rewrite
the compiler, then I have to add a block start on function entry and
one on every function exit.  If there is one function exit, then I
have to add one.

This "anti-goto-political-correctness-bullshit" has to go.  Anyone who
thinks a for loop generates prettier assembly than an label/if/goto
had better read more compiler output.

At least with a goto instead of a break, I have an explicitly defined
location where my instruction pointer will end up.  This beats trying
to find where a break exits a loop all to hell.

> It goes a long way toward obscuring the code flow and makes it difficult
> to read.

I supposed changing code that looks like:

	if( error = func()) {
		[cleanup]
		return( error);
	}

Into:

	error = func();
	if( error) {
		[cleanup]
		return( error);
	}

Has a function other than to make gcc quit whining about assignments
in if statements (and to make the FreeBSD vs. 4.4BSD diffs larger)?

It doesn't seem to make it easier to read.

> It's especially bad when you have 3 or more exit labels.

I would say 3 was the max.  Not 2, like you imply.  In some cases, I'd
allow 4 if I were playing "kernel Emily Post".  3 is the bare minimum
for two allocations for things like the rename() system call.  You
have erros to recover from at 0, 1, and 2 outstanding allocations.

A goto is a tool for handling an exceptional conditions.  And that's
where goto's are use in my code.

The alternative is negative comparison code blocks, ie:

	if( !(error = foo()) {
		[real code]
	} else {
		[error code]
	}

Or the use of stack state variables to determine state unwind at
function exit.


> I fail to see the requirement for any of this in an SMP kernel,

Code reentrancy and lock state maintenance.  It's important to block
reentrancy to critical sections, like free-list/hash/cache management,
where a single global dataum is being manipulated.  The system clock
is actually one such datum that *isn't* guarded in the current code.

Single entry/exit buys you the ability to ensure lock state, for
instance, in UFS.  I can know what the state is going into and coming
out of a function.

Actually, namei() is terminally screwed in this regard because it has
so much crap packed into a single function pair that it uses to avoid
recursion (at the same time limiting symbolic link expansion to a
total of 1024 characters for non-terminal path components, making them
less transparent).

It then calls VOP_LOOKUP(), which further obfuscates the code path
beyond all recognition by doing nine or ten things itself based on
the arguments.

Now I don't have any problem getting my brain around hairy code like
that, but you have to admit that it's a hell of a lot more obfuscated
than a routine that has three or less gotos in it.  You have to admit
also that a couple of 3/6 cycle jumps, assuming a poor optimizer doesn't
reorder the code and return multiple times anyway, is not a big performance
penalty compared to the other absolute crap that is going on in other code.


The biggest obfuscation I have perpetrated is the SYSINIT() divorce that
arose because no one has ever written a smart linker for Intel boxes,
and the trade it makes is well worth the exchange.

Properly managed, one does not have to recompile a kernel in order to
option things in and out of it -- only to relink it.  And that can be
done at runtime, with a little more effort, avoid the need to recompile
a kernel at all.

> and the need for this to have "buffer allocation bookeeping" is dubious.

The "buffer allocation bookeeping" is the knowledge in the routine that
a buffer has or has not been allocated by way of a call to namei().  It's
a hell of a lot better to logically seperate the FS from path parsing
issues, like whether or not the guy who called me called namei() with
certain flags, so I can know if I have to free his preallocated buffers
because he's too damn lazy to do it himself.

It's not like it's even saving a function call, all it's doing is
obfuscating the damn file system interface to the point that nullfs
and unionfs and portalfs operate incorrectly, and NFS has all sorts
of duplicate crap code that belongs in namei() pulled in because it
has to play the buffer game too.

Now if I'm going to potentially free something, doesn't it behoove me
to make sure I've actually allocated it -- to do "buffer allocation
bookkeeping" -- before just returning from the middle of a function
or unconditionally freeing it?

					Regards,
					Terry Lambert
					terry@lambert.org
---
Any opinions in this posting are my own and not those of my present
or previous employers.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199509190326.UAA09176>