⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 036_fs_dcache_c.html

📁 重读linux 2.4.2o所写的笔记
💻 HTML
📖 第 1 页 / 共 3 页
字号:
      (NFS</FONT><BR>
      <FONT color=#3333ff>&nbsp;* timeouts or autofs deletes).</FONT><BR>
      <FONT color=#3333ff>&nbsp;*/</FONT><BR>
      static __inline__ void <FONT color=#006600><B>d_drop</B></FONT>(struct
      dentry * dentry)<BR>
      {<BR>
      &nbsp;&nbsp;&nbsp; spin_lock(&amp;dcache_lock);<BR>
      &nbsp;&nbsp;&nbsp; list_del(&amp;dentry-&gt;d_hash);<BR>
      &nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;dentry-&gt;d_hash);<BR>
      &nbsp;&nbsp;&nbsp; spin_unlock(&amp;dcache_lock);<BR>
      }<BR>
      <BR>
      然后删除一个文件时,对detnry的影响是d_delete, 注意delete总是试图只reset inode,
      使其变为negetive的dentry,除非还有其他object还在引用这个文件:<BR>
      <FONT color=#3333ff>/*</FONT><BR>
      <FONT color=#3333ff>&nbsp;* When a file is deleted, we have two
      options:</FONT><BR>
      <FONT color=#3333ff>&nbsp;* - <B>turn this dentry into a negative</B>
      dentry</FONT><BR>
      <FONT color=#3333ff>&nbsp;* - <B>unhash this dentry and free
      it.</B></FONT><BR>
      <FONT color=#3333ff>&nbsp;*</FONT><BR>
      <FONT color=#3333ff>&nbsp;* Usually, we want to just turn this
      into</FONT><BR>
      <FONT color=#3333ff>&nbsp;* a negative dentry, but if anybody else
      is</FONT><BR>
      <FONT color=#3333ff>&nbsp;* currently using the dentry or the
      inode</FONT><BR>
      <FONT color=#3333ff>&nbsp;* we can't do that and we fall back on
      removing</FONT><BR>
      <FONT color=#3333ff>&nbsp;* it from the hash queues and waiting
      for</FONT><BR>
      <FONT color=#3333ff>&nbsp;* it to be deleted later when it has no
      users</FONT><BR>
      <FONT color=#3333ff>&nbsp;*/</FONT><BR>
      void <FONT color=#006600><B>d_delete</B></FONT>(struct dentry * dentry)<BR>
      {<BR>
      &nbsp;&nbsp;&nbsp; /*<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;* Are we the only user?<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;*/<BR>
      &nbsp;&nbsp;&nbsp; spin_lock(&amp;dcache_lock);<BR>
      &nbsp;&nbsp;&nbsp; if (atomic_read(&amp;dentry-&gt;d_count) == 1) {<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; dentry_iput(dentry);<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<BR>
      &nbsp;&nbsp;&nbsp; }<BR>
      &nbsp;&nbsp;&nbsp; spin_unlock(&amp;dcache_lock);<BR>
      <BR>
      &nbsp;&nbsp;&nbsp; /*<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;* If not, just drop the dentry and let dput<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;* pick up the tab..<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;*/<BR>
      &nbsp;&nbsp;&nbsp; d_drop(dentry);<BR>
      }<BR>
      为了清楚到底如何分配和释放一个dentry,还是简单看看文件删除,目录删除,和shrink dcache 的主要流程吧:<BR>
      sys_unlink -&gt;vfs_unlink <B>-&gt; </B>dir-&gt;i_op-&gt;unlink<B> +
      d_delete +dput</B><BR>
      sys_rmdir-&gt;vfs_rmdir -&gt; dir-&gt;i_op-&gt;rmdir + <B>d_unhash
      </B>(<FONT color=#009900><B>d_drop</B></FONT>+shrink_dcache_parent) +<B>
      d_delete+</B><FONT color=#000000><B>dput</B></FONT><BR>
      kswapd || bdflush -&gt; ...
      --&gt;shrink_dcache_memory-&gt;prune_dcache-&gt;(d_drop +inode put+
      d_free)<BR>
      首先第一个问题是:<BR>
      为啥删除的文件的dentry留在目录树中?
      呵呵,快呗,起码我从内存就知道,这个文件已经被删除.(不过首先被prune,unlink的时候会被转移到unused 链表,呵呵).
      曾经在哪里见过说unused队列中的dentry中还保留有inode.....起码是不太对头的. (大家讨论).<BR>
      <BR>
      在分析dput前,看看一个lock free的原子操作,有助理解dcache的实现:<FONT color=#cc0000 size=4>(lock
      free 的算法)</FONT><BR>
      int <FONT color=#006600><B>atomic_dec_and_lock</B></FONT>(atomic_t
      *atomic, spinlock_t *lock)<BR>
      {<BR>
      &nbsp;&nbsp;&nbsp; int counter;<BR>
      &nbsp;&nbsp;&nbsp; int newcount;<BR>
      <BR>
      repeat:<BR>
      &nbsp;&nbsp;&nbsp; counter = atomic_read(atomic);<BR>
      &nbsp;&nbsp;&nbsp; newcount = counter-1;<BR>
      <BR>
      &nbsp;&nbsp;&nbsp; if (!newcount)
      <FONT color=#3333ff>/*如果是最后一个引用则需要加锁*/</FONT><BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto slow_path;<BR>
      &nbsp;&nbsp;&nbsp; <FONT color=#3333ff>/*不是最后一个引用采用的是lock free
      的算法!!!!*/</FONT><BR>
      &nbsp;&nbsp;&nbsp; asm volatile("lock; cmpxchgl %1,%2"<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; :"=a" (newcount)<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; :"r" (newcount), "m"
      (atomic-&gt;counter), "0" (counter));<BR>
      <BR>
      &nbsp;&nbsp;&nbsp; /* If the above failed, "eax" will have changed */<BR>
      &nbsp;&nbsp;&nbsp; if (newcount != counter)<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto repeat;<BR>
      &nbsp;&nbsp;&nbsp; return 0;
      <FONT color=#3333ff>/*不是最后一个引用返回0*/</FONT><BR>
      <BR>
      slow_path:<BR>
      &nbsp;&nbsp;&nbsp; spin_lock(lock);<BR>
      &nbsp;&nbsp;&nbsp; if (atomic_dec_and_test(atomic))<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return 1;<FONT color=#000099>
      /*最后一个引用返回1*/</FONT><BR>
      &nbsp;&nbsp;&nbsp; spin_unlock(lock);<BR>
      &nbsp;&nbsp;&nbsp; return 0;<BR>
      }<BR>
      <BR>
      <BR>
      /*<BR>
      &nbsp;* This is dput<BR>
      &nbsp;*<BR>
      &nbsp;* This is complicated by the fact that we do not want to put<BR>
      &nbsp;* dentries that are no longer on any hash chain on the unused<BR>
      &nbsp;* list: we'd much rather just get rid of them immediately.<BR>
      &nbsp;*<BR>
      &nbsp;* However, that implies that we have to traverse the dentry<BR>
      &nbsp;* tree upwards to the parents which might _also_ now be<BR>
      &nbsp;* scheduled for deletion (it may have been only waiting for<BR>
      &nbsp;* its last child to go away).<BR>
      &nbsp;*<BR>
      &nbsp;* This tail recursion is done by hand as we don't want to depend<BR>
      &nbsp;* on the compiler to always get this right (gcc generally doesn't).<BR>
      &nbsp;* Real recursion would eat up our stack space.<BR>
      &nbsp;*/<BR>
      <BR>
      /*<BR>
      &nbsp;* dput - release a dentry<BR>
      &nbsp;* @dentry: dentry to release<BR>
      &nbsp;*<BR>
      &nbsp;* Release a dentry. This will drop the usage count and if
      appropriate<BR>
      &nbsp;* call the dentry unlink method as well as removing it from the
      queues and<BR>
      &nbsp;* releasing its resources. If the parent dentries were scheduled for
      release<BR>
      &nbsp;* they too may now get deleted.<BR>
      &nbsp;*<BR>
      &nbsp;* no dcache lock, please.<BR>
      &nbsp;*/<BR>
      <BR>
      void dput(struct dentry *dentry)<BR>
      {<BR>
      &nbsp;&nbsp;&nbsp; if (!dentry)<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<BR>
      <BR>
      repeat:<BR>
      &nbsp;&nbsp;&nbsp; if (!atomic_dec_and_lock(&amp;dentry-&gt;d_count,
      &amp;dcache_lock))<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<FONT color=#3333ff>
      /*不是最后一个引用则无事可做, 看来到unused list的dentry连引用计数都是0*/</FONT><BR>
      <BR>
      &nbsp;&nbsp;&nbsp; /* dput on a free dentry? */<BR>
      &nbsp;&nbsp;&nbsp; if (!list_empty(&amp;dentry-&gt;d_lru)) /*bug check*/<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; BUG();<BR>
      &nbsp;&nbsp;&nbsp; /*<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;* AV: -&gt;d_delete() is _NOT_ allowed to block
      now.<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;*/<BR>
      &nbsp;&nbsp;&nbsp; if (dentry-&gt;d_op &amp;&amp;
      dentry-&gt;d_op-&gt;d_delete) { <FONT color=#3333ff>/*自己实现d
      delete的文件系统不多,ext2就没有的*/</FONT><BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if
      (dentry-&gt;d_op-&gt;d_delete(dentry))<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto unhash_it;<BR>
      &nbsp;&nbsp;&nbsp; }<BR>
      &nbsp;&nbsp;&nbsp; /* Unreachable? Get rid of it */<BR>
      &nbsp;&nbsp;&nbsp; if (list_empty(&amp;dentry-&gt;d_hash))
      <FONT color=#3333ff>/*已经unhash?
      ,delete的时候还用别的obj或者过程在用,不过现在没有了*/</FONT><BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto kill_it;<BR>
      &nbsp;&nbsp;&nbsp; list_add(&amp;dentry-&gt;d_lru,
      &amp;dentry_unused);<FONT color=#3333ff> /*普通的删除就放到unused队列中*/</FONT><BR>
      &nbsp;&nbsp;&nbsp; dentry_stat.nr_unused++;<BR>
      &nbsp;&nbsp;&nbsp; /*<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;* Update the timestamp<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;*/<BR>
      &nbsp;&nbsp;&nbsp; dentry-&gt;d_reftime = jiffies;<BR>
      &nbsp;&nbsp;&nbsp; spin_unlock(&amp;dcache_lock);<BR>
      &nbsp;&nbsp;&nbsp; return;<BR>
      <BR>
      unhash_it:<BR>
      &nbsp;&nbsp;&nbsp; list_del_init(&amp;dentry-&gt;d_hash);<BR>
      <BR>
      kill_it: {<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; struct dentry *parent;<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; list_del(&amp;dentry-&gt;d_child);<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* drops the lock, at that point
      nobody can reach this dentry */<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; dentry_iput(dentry);<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<FONT color=#3333ff> parent =
      dentry-&gt;d_parent</FONT>; <FONT color=#3333ff>/*对parent
      dentry尝试进行dput操作*/</FONT><BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; d_free(dentry);<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (dentry == parent)<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; dentry = parent;<BR>
      &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto repeat;<BR>
      &nbsp;&nbsp;&nbsp; }<BR>
      }<BR>
      <BR>
      为了理解dput为啥需要"递归"到父节点进行操作,又为啥看到unhash的删除方式(而不是make negative),我们考虑这样一个操作流程:<BR>
      假设有一个目录:&nbsp; home/usrx, 内有文件 home/usrx/myfile<BR>
      操作流程为(fix me,这样容许不?):<BR>
      0) open myfile<BR>
      1) rm -r home/usrx<BR>
      2) close myfile<BR>
      <BR>
      当rm home/usrx的时候由于myfile有步骤0)的引用,所以 d_delete不能negative这个dentry, 只是unhash他,
      其父节点home/usrx亦同.<BR>
      然后当close myfile的时候进行 dput,就有必要"递归"到父节点了.
      (在这种情况下直接free掉myfile的dentry也是有道理的,父节点都没有了,呵呵,不用留着快速查找deleted的文件了).<BR>
      <BR>
      static inline void dentry_iput(struct dentry * dentry) 就不多说了.<BR>
      <BR>
      <DIV style=TEXT-ALIGN:center>
        <FONT size=4><B>shrink and prune</B></FONT><BR>
      </DIV>
      <BR>
      void shrink_dcache_memory(int priority, unsigned int gfp_mask) 就不多费口舌了.<BR>
      /**<BR>
      &nbsp;* prune_dcache - shrink the dcache<BR>
      &nbsp;* @count: number of entries to try and free<BR>
      &nbsp;*<BR>
      &nbsp;* Shrink the dcache. This is done when we need<BR>
      &nbsp;* more memory, or simply when we need to unmount<BR>
      &nbsp;* something (at which point we need to unuse<BR>
      &nbsp;* all dentries).<BR>
      &nbsp;*<BR>
      &nbsp;* This function may fail to free any resources if<BR>
      &nbsp;* all the dentries are in use.<BR>
      &nbsp;*/<BR>
      &nbsp;<BR>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -