Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 5 Aug 2008 11:09:00 -0400 (EDT)
From:      Rick Macklem <rmacklem@uoguelph.ca>
To:        Kostik Belousov <kostikbel@gmail.com>
Cc:        freebsd-fs@freebsd.org
Subject:   Re: doing vfs_hash_get when vnode locked
Message-ID:  <Pine.GSO.4.63.0808051052350.27663@muncher.cs.uoguelph.ca>
In-Reply-To: <20080805083229.GB97161@deviant.kiev.zoral.com.ua>
References:  <Pine.GSO.4.63.0808041657200.3482@muncher.cs.uoguelph.ca> <20080805083229.GB97161@deviant.kiev.zoral.com.ua>

next in thread | previous in thread | raw e-mail | index | archive | help


On Tue, 5 Aug 2008, Kostik Belousov wrote:

> On Mon, Aug 04, 2008 at 05:04:58PM -0400, Rick Macklem wrote:
>> There's a place in my nfsv4 client where I need to vfs_hash_get() when
>> another blocked thread may be holding a lock on the vnode. (It's during
>> a recovery case where the other threads are blocked, so there isn't a
>> race problem, as far as I understand it.)
>>
>> For FreeBSD7, all I did was call vfs_hash_get() with flags == 0 and it
>> gave me what I wanted (the vnode for the file handle with a reference
>> count, but no lock).
>>
>> For FreeBSD-CURRENT/8, this no longer works, because vfs_hash_get() calls
>> vget(), which calls _vn_lock() and _vn_lock() now complains if the lock
>> type field of "flags" is 0. I came up with a really ugly workaround, by
>> setting the flags arg. to LK_EXCLOTHER for vfs_hash_get() and then
>> providing my own VOP_LOCK1() which just VI_UNLOCK()s and returns 0 for
>> this case (doing the same as vop_stdlock() for other cases). Yuck!!
>>
>> Is it possible to re-enable the case of _vn_lock() getting a locktype
>> field == 0 (or defining one that says "just return 0 unless VI_DOOMED"),
>> so I don't need the dirty hack?
>
> I do not quite understand what you really need there. The non-locked
> vnode may be reclaimed at any moment, so the check for !VI_DOOMED
> returns no useful information.
>
I need a referenced vnode (v_usecount incremented, which I thought would
avoid it being recycled) when another blocked thread in the kernel has
the vnode locked. (This thread is doing recovery while the other blocked
thread is waiting for that recovery to complete.)

For FreeBSD7, I call vfs_hash_get(mntp, hash, 0, td, &nvp, mycmpfh, nfhp)
for this case. It:
- calls vget() with (0 | LK_INTERLOCK) for flags
   - it calls vn_lock() with the flags as above
     - _vn_lock() simply checks for VI_DOOMED and then, otherwise,
       returns 0 because (flags & LK_TYPE_MASK) == 0
   - vget then calls v_upgrade_usecount(), incrementing the use count
    (so it won't be recycled, as I understand it)
--> and I get the vnode with an incremented usecount that I need. When
     this thread is done with it, it simply vrele(vp)'s it.

For FreeBSD-CURRENT, this panics because there is now a check at the
beginning of _vn_lock() requiring an non-zero LK_TYPE_MASK field.
(I worked around it by using LK_EXCLOTHER instead of 0 as the argument to
  vfs_hash_get() and then implemented by own nfs_lock1() VOP, that handles
  the bogus case of the LK_TYPE_MASK being set to LK_EXCLOTHER by just
  returning 0 after VI_UNLOCK(vp) if LK_INTERLOCK is set. For all other
  cases, it calls _lockmgr_args() just like vop_stdlock().)

Did this help or just muddy the waters? rick



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