site_archiver@lists.apple.com Delivered-To: darwin-kernel@lists.apple.com
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 (Darwin-kernel@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/darwin-kernel/site_archiver%40lists.a... This email sent to site_archiver@lists.apple.com