Re: vnode_put(...): iocount < 1 revisited
Re: vnode_put(...): iocount < 1 revisited
- Subject: Re: vnode_put(...): iocount < 1 revisited
- From: Ken Hornstein <email@hidden>
- Date: Tue, 26 Jul 2011 11:17:27 -0400
>I have a question about the protocol for dropping iocount on the vnode in
>the following scenario with my file system driver.
The short answer is "you only call vnode_put() on a vnode if you've
called vnode_get() on the vnode _within the same vnop_".
The normal guarantee is that when your vnop functions are called you have
an iocount on that vnode. The kernel takes care of this for you, and takes
care of dropping the iocount after it's done with it. The obvious exception
to this is vnop_lookup(); in this case since you're either creating or looking
up a vnode, it's your responsibility to make sure it has an iocount on it.
I suspect what you're thinking is, "Oh, I called vnode_get() in lookup(), so
I need to call vnode_put() when I discover that it doesn't really exist
in getattr()". That's where you're going wrong. Think of these as two
completely different functions; you return a vnode with an iocount out
of lookup(), and you should make sure that when you return from getattr()
you have the same iocount as when you left, because you don't know what
the kernel is going to do with that vnode when you're done with it.
>I discovered that the vn_lookup() in my driver was essentially a
>cache_lookup() and returning success since the file was still in the name
>cache. The getattr() call was doing a stat to the network file system and
>since the file was deleted already, it was returning ENOENT. My fix was to
>purge name cache when stat fails and call vnode_put() so that the vnode can
>be reclaimed. However, I hit the "iocount <= 1" panic. The panic went away
>when I removed vnode_put(), however, I do not understand where the last
>iocount is dropped in this scenario. I tried looking in the kernel code,
>but I was not able to figure this out.
Here's the other problem that you'd run into eventually; this file
doesn't exist, right? Well, just dropping the iocount to 0 doesn't get
rid of the vnode; it _lets_ it be recycled, but it won't be recycled
unless there is memory pressure or you tell it to be recycled. If
someone were to create another file with the same name and you created
another vnode, you'd have two vnodes pointing to the same named file,
which is Extremely Bad.
What you want to do is tell the kernel to get rid of that vnode; you can
do that with vnode_recycle(). This will reclaim the vnode when the iocount
goes to 0, purge the name cache, free any cached data ... etc etc, in other
words, it gets rid of the vnode (as soon as it can).
Hm, while I personally call vnode_recycle() when a file is gone, I see
other filesystems use vnode_rele() (they also purge the name cache).
Those are under slightly different circumstances, though ... they do
that when they get notification from the fileserver that there is no
longer any status update for it, so vnode_rele() makes more sense
there. My personal preference is to use vnode_recycle() when you know
for sure that it's gone, but I'd be interested in what others think.
As for the code path that calls vnode_put(), well, I guess you'd have to
set up two-kernel debugging to be sure, but I see a vnode_put() in
the open() path (open1(), actually, in bsd/vfs/vfs_syscalls.c), so I'd
hazard a guess that's where it is being released.
Ah, I think I see what's happening: in bsd/vfs/vfs_vnops.c, in
vn_open_auth(), if namei() succeeds but vnode_authorize() fails, first
vnode_put() is called (which is what is tripping you up), and then if
the error from vnode_authorize is ENOENT it starts the whole sequence
over again. So I think my advice to you is correct: call vnode_recycle()
when you realize the file doesn't exist; as soon as vnode_put() is called
the vnode will be reclaimed and purged from the name cache. During
the second go-around you should get a ENOENT from namei() and all will
be well.
--Ken
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden