免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1722 | 回复: 0
打印 上一主题 下一主题

RCU-based dcache lookup [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-12-29 17:49 |只看该作者 |倒序浏览

                dentry lookup now uses RCU based locking model, i.e adding/removing
dentry to/from dentry cache can happen cocurrently with lookup code.
Before, dcache_lock was used to protect the hashtable (dentry cache)
for lookup, adding and removing. Because lookup is the most common
operation, contention for the dcache_lock was very high. So optimizing
this common path is desired even the code is much harder to understand
after optimization.
dput
1. If dentry->d_count == 1, the caller is the last user. The
might_sleep() indicates that dput can't be called in interrupt context
when the caller is the last user.
This dentry may be the last user of the inode, kernel needs to flush out
the dirty pages in page cache of this inode, clean_inode needs to wait
before continuing on.
dput->d_kill->dentry_iput->iput->iput_final->generic_drop_inode->
generic_forget_inode->clean_inode
2. If this is the last user, we need to acquire the dcache_lock first
and then decrease the dentry->d_count to 0.
3. Then we need to acquire the per-dentry d_lock, we still need to test
the d_count of this dentry. Since the __d_lookup is not dcache_lock
protected now, it can find the dentry and increase the d_count before
dput gets the d_lock. If this is the case, dput just releases the lock
and returns, since the dentry is in use now.
4. d_delete is called to determine whether to directly remove the dentry
from the hashtable and free the dentry. Usually if a dentry becomes
unused (d_count == 0), it will still be kept in the dcache hashtable (it
will be moved to the per-sb lru list, if kernel decides to shrink the
dentry cache, it will try to free the unused dentries).
5. If this dentry is not in the hashtable (d_unhashed), just kill it
now. i.e for some network fs, it will cache some info in local cache,
these info need to be revalidated periodically. During lookup, if fs
provides d_revalidate operation, we need to call d_revalidate to
whether the dentry is valid. If the dentry is not valid at that time,
d_revalidate needs call d_drop to remove the dentry from dcache
hashtable.
6. If the dentry is still in the hashtable, just move it to the per-sb
LRU list for unused dentries. These unused dentries are still in the
dcache, later lookup can still find them. Only when the available memory
is low and kernel starts reclaiming memory from all kinds of caches,
including dcache, unused dentries will be freed.
If the dentry is not on the LRU list, move it to the per-sb LRU list and
set DCACHE_REFERENCED in d_flags. When freeing dentries, we will start
from the end of the LRU list, trying to free the ones which are not used
for a long time.
The correct way to maintain the time order in LRU list is
(which was implemented in 2.4):
When we find a dentry in __d_lookup and increase it d_count, we should
remove the dentry from the LRU list if it is still on it, and put the
dentry back to the LRU list if its d_count == 0 in dput.
But since the __d_lookup is not dcache_lock protected now, we can't
modify the LRU list in the lookup code.
So the time order seems not correct on the LRU list now, f.e if the last
user dput the dentry, the dentry will be put on the LRU list. Later if
it is touched by other users in __d_lookup, it will not be removed from
the LRU list (is it a big problem?)
To really free a dentry, you must:
1. spin_lock(&dcache_lock), spin_lock(&dentry->d_lock);
2. ensure dentry->d_count == 0
3. __d_drop(dentry)
   set DCACHE_UNHASHED flag in dentry->d_flags and remove dentry from
   dcache hashtable
4. d_kill -> d_free -> call_rcu -> d_callback
Since in __d_lookup, hash chain walking is not protected by
dcache_lock, __d_lookup can still find the dentry you are trying to
free. So you need to set the DCACHE_UNHASHED flag, __d_lookup will try
to acquire the dentry->d_lock and test this bit. It will not return
unhashed dentry to the caller.
And we can't free the dentry to the kmem_cache immediately, __d_lookup
may still point to the dentry. We must wait for a grace period past,
till there is no reference to the dentry, can we free the dentry to
the kmem_cache.
d_kill:
called with dcache_lock, dentry->d_lock held and will release these two
locks after finished. The dentry has already removed from the dcache
hashtable and the lru list (d_hash, d_lrun, done in __d_drop).
1. remove the dentry from its parent list (d_child)
2. dentry_iput
    release the dentry's inode
    a. remove from the inode.i_dentry list (d_alias), this needs the
       dcache_lock
    b. release d_lock, dcache_lock, since the iput() may sleep, also at
       this point, no one can find the dentry. The dentry is unhashed, only
       __d_lookup can hold a reference to this dentry just before this entry
       is removed from the hashtable. But since DCACHE_UNHASHED is set,
       __d_lookup will not return this dentry to the caller.
3. d_free: to free the dentry after a grace period
references:
1. Linux-2.6.32 fs/dcache.c, Documentation/filesystems/dentry-locking.txt
2. http://lse.sourceforge.net/locking/dcache/dcache.html
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/100604/showart_2134608.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP