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

📄 038_fs_dquot_c.html

📁 重读linux 2.4.2o所写的笔记
💻 HTML
📖 第 1 页 / 共 2 页
字号:
      flow: static(header);    }    /* used to insert page numbers */    div.google_header::before, div.google_footer::before {      position: absolute;      top: 0;    }    div.google_footer {      flow: static(footer);    }    /* always consider this element at the start of the doc */    div#google_footer {      flow: static(footer, start);    }    span.google_pagenumber {      content: counter(page);    }    span.google_pagecount {      content: counter(pages);    }  }  @page {    @top {      content: flow(header);    }    @bottom {      content: flow(footer);    }  }  /* end default print css */ /* custom css *//* end custom css */  /* ui edited css */    body {    font-family: Verdana;        font-size: 10.0pt;    line-height: normal;    background-color: #ffffff;  }    .documentBG {    background-color: #ffffff;  }  /* end ui edited css */</style>   </head>  <body  revision="dcbsxfpf_23czwkt8:158">      <table align=center cellpadding=0 cellspacing=0 height=5716 width=800>
  <tbody>
  <tr>
    <td height=5716 valign=top width=802>
      <pre>2007-11-29<br><br> 照理说这个模块的耦合做的真是不错的. 偌大一堆函数是static, 非static的函数也就两三个是真正的接口函数而已. 在2.4中只有<br>ext2文件系统实现了disk quota,其他的文件系统还不支持. disk quota是照着BSD接口来实现的(见注释).<br> 顺着文件看下去,<br><font size=5><b>1. 首先知道, quot分成两种,一种针对user,一种针对group<br>也就是说一种针对uid,一种针对gid. </b></font><br>#define <font color=#000099>MAXQUOTAS</font> 2<br>#define <font color=#000099>USRQUOTA</font>  0		/* element used for user quotas */<br>#define <font color=#000099>GRPQUOTA </font> 1		/* element used for group quotas */<br><font size=4><br><font size=5><b>2. quot的使能的单位是文件系统,一个super block, sb</b></font></font><br>struct <font color=#000099><b>super_block</b></font> {<br>	struct file_system_type	*s_type;<br>	struct <font color=#009900>super_operations</font>	*<font color=#000099>s_op</font>;<br>	struct <font color=#006600>dquot_operations</font>	*<font color=#000099><b>dq_op</b></font>; <font color=#3333ff>/*除了s_op,还有disk quot 的ops, dq 就是disk quot*/</font><br><br>        struct <font color=#009900>quota_mount_option</font>s <font color=#000099><b>s_dquo</b></font>t; <font color=#3333ff>/* Diskquota specific options */ quot的全局配置参数也存在sb中<br>        /*这些配置里边我们先关心那个</font>files:这个文件是存储uid/gid对应的quot值的<font color=#3333ff>:分别存在两个文件中,以gid/uid为索引*/<br></font>...........<br>}<br>option:<br>struct <font color=#000099><b>quota_mount_options</b></font><br>{<br>	unsigned int flags;			/* Flags for diskquotas on this device */<br>	struct semaphore dqio_sem;		/* lock device while I/O in progress */<br>	struct semaphore dqoff_sem;		/* serialize quota_off() and quota_on() on device */<br>	struct file *files[MAXQUOTAS];		<font color=#3333ff>/* fp's to quotafiles */ /*quot文件存储uid/gid对应的各种limit*/</font><br>	time_t inode_expire[MAXQUOTAS];		<font color=#3333ff>/* expiretime for inode-quota */</font><br>	time_t block_expire[MAXQUOTAS];		<font color=#3333ff>/* expiretime for block-quota */</font><br>	char rsquash[MAXQUOTAS];		<font color=#3333ff>/* for quotas threat root as any other user */</font><br>};<br><br>/*<br> * Definitions for disk quotas imposed on the average user<br> * (big brother finally hits Linux).<br> *<br> * The following constants define the amount of time given a user<br> * before the soft limits are treated as hard limits (usually resulting<br> * in an allocation failure). The timer is started when the user crosses<br> * their soft limit, it is reset when they go below their soft limit.<br> */<br>#define <font color=#000099><b>MAX_IQ_TIME</b></font>  604800	/* (7*24*60*60) 1 week */<br>#define <font color=#000099>MAX_DQ_TIME</font>  604800	/* (7*24*60*60) 1 week */<br>为了理解hard quot和soft quot以expiretime, 只需看看<font color=#000099><b>check_idq</b></font>或者<font color=#000099><b>check_bdq</b></font>即可.<br><br><font size=5><b>3. 在quot文件中存储的数据如下(quot文件本身没有quot的限制)</b></font><br>/*<br> * The following structure defines the format of the disk quota file<br> * (as it appears on disk) - the file is an array of these structures<br> * indexed by user or group number.<br> */<br>struct <font color=#000099><b>dqblk</b></font> {<br>	__u32 dqb_bhardlimit;	/* absolute limit on disk blks alloc */<br>	__u32 dqb_bsoftlimit;	/* preferred limit on disk blks */<br>	__u32 dqb_curblocks;	/* current block count */<br>	__u32 dqb_ihardlimit;	/* absolute limit on allocated inodes */<br>	__u32 dqb_isoftlimit;	/* preferred inode limit */<br>	__u32 dqb_curinodes;	/* current # allocated inodes */<br>	time_t dqb_btime;		/* time limit for excessive disk use */<br>	time_t dqb_itime;		/* time limit for excessive inode use */<br>};<br>参考<font color=#000099><b>read_dquot</b></font>,<font color=#000099><b>write_dquot</b></font>.<br><br><font size=5><b>4.从quot文件中读出数据后存在一个hash中,以(kdev_t,id,type)为索引</b></font><br><br><font color=#3333ff>进入hash表: dget的时候,如果是新分配的dqota就进入hash表<br>撤出hash表: dquot只在重新被使用的时候,或者quot关闭(invalid)的时候才从hash中删除.并且重用的时候仅仅是临时删除<br>马上又加进来.<br></font><br>  id: gid 或者uid, type:group quot或者user quot<br>参考函数:<br>static struct dquot *<font color=#000099><b>dqget</b></font>(struct super_block *sb, unsigned int id, short type)<br>{<br>	unsigned int hashent = hashfn(sb-&gt;s_dev, id, type);<br>	struct dquot *dquot, *empty = NULL;<br>	struct quota_mount_options *dqopt = sb_dqopt(sb);<br><br>        if (!is_enabled(dqopt, type))<br>                return(NODQUOT);<br><br>we_slept:<br>	if ((dquot = find_dquot(hashent, sb-&gt;s_dev, id, type)) == NULL) {<font color=#3333ff> //从hash查找</font><br>		if (empty == NULL) { <font color=#3333ff>//没有查到</font><br>			dquot_updating[hashent]++;<br>			empty = <font color=#000099><b>get_empty_dquot</b></font>(); //分配新的quot数据结构<br>			if (!--dquot_updating[hashent])<br>				wake_up(&amp;update_wait);<br>			goto we_slept; <font color=#3333ff>//竞争处理,一定从hash中找的的才算.</font><br>		}<font color=#3333ff><br>                //进行初始化</font><br>		dquot = empty;<br>        	dquot-&gt;dq_id = id;<br>        	dquot-&gt;dq_type = type;<br>        	dquot-&gt;dq_dev = sb-&gt;s_dev;<br>        	dquot-&gt;dq_sb = sb;<br>		/* hash it first so it can be found */<br>		<b>hash_dquot</b>(dquot); <font color=#3333ff>//挂入hash表</font><br>        	<b>read_dquot</b>(dquot); <font color=#3333ff>//从磁盘读入配置</font><br>	} else { <font color=#3333ff>//quot已经在hash的情况</font><br>		if (!dquot-&gt;dq_count++) { <font color=#3366ff>//增加其引用计数,引用计数是0代表在free list中<br>                    //参考dqput, 当引用计数是0的时候并不从hash中摘除的<br></font>			remove_free_dquot(dquot); <br>		} else<br>			dqstats.cache_hits++;<br>		wait_on_dquot(dquot);<br>		if (empty)<br>			dqput(empty);<br>	}<br><br>	while (dquot_updating[hashent])<br>		sleep_on(&amp;update_wait);<br><br>	if (!dquot-&gt;dq_sb) {	/* Has somebody invalidated entry under us? */<br>		/*<br>		 *  Do it as if the quota was invalidated before we started<br>		 */<br>		dqput(dquot);<br>		return NODQUOT;<br>	}<br>	dquot-&gt;dq_referenced++;<br>	dqstats.lookups++;<br><br>	return dquot;<br>}<br><br><font size=5><b>5. quot管理: quot的list使用策略</b></font><br>注释说的比较清楚了:<br>/*<br> * <b>Dquot List Management:</b><br> * The quota code uses three lists for dquot management: the inuse_list,<br> * free_dquots, and dquot_hash[] array. <b>A single dquot structure may be</b><br style=FONT-WEIGHT:bold><b> * on all three lists, depending on its current state.</b><br> *<br> * All dquots are placed on the inuse_list when first created, and this<br> * list is used for the sync and invalidate operations, which must look<br> * at every dquot.<br> *<br> * <b>Unused dquots (dq_count == 0) are added to the free_dquots list</b> when<br> * freed, and this list is searched whenever we need an available dquot.<br> * Dquots are removed from the list as soon as they are used again, and<br> * nr_free_dquots gives the number of dquots on the list.<br> *<br> * Dquots with a specific identity (device, type and id) are placed on<br> * one of the dquot_hash[] hash chains. The provides an efficient search<br> * mechanism to lcoate a specific dquot.<br> */<br>hash表我们已经说过了. <br><font color=#3333ff>dquot最多只分配max_dquots个(1024, typical). 然后从不释放.为所有文件系统所共享.并且一旦分配就进入<br>inuse队列.<br>当引用计数降到0的时候,进入unused队列,等待重用.此时其磁盘部分已经写入quot文件.(见dqput).等待重用的dquot<br>还在hash中,如果重新命中就马上回复使用. (而引用计数不为0,必定不再unused队列)<br><br>quot的设计是采用一定量的内存(dquot),轮换使用,映射为不同的quot file中的具体数据.<br><br>quot尽力保持高引用度的dquot存在于hash中,所以可以看到为此所做的努力:<br><b>static struct dquot *find_best_candidate_weighted(void)</b><br style=FONT-WEIGHT:bold><b>static inline struct dquot *find_best_free(void)<br></b><font color=#000000><br>说明白这些后,关于quot的分配释放/hash的管理/重用策略等都说完了,相关函数在这些知识下很容易理解.就不再一一列举.<br></font></font><font color=#3333ff><font color=#000000>static void dqput(struct dquot *dquot) : 不说了... -:)<br><br><br></font></font><font color=#3333ff><font color=#000000><font size=5><b>6. lock/unlock</b></font><br>操作dquot的时候需要lock: 读写/分配释放inode block. 还有一个per dquot的sleep队列...<br>DQ_MOD: 不难理解修改过,需要同步到quot file, 写入文件后清除此标记....<br><br><br><font size=5><b>7.inode 的quota操作</b></font><br>参考quotaops.h.<br>下面就是所有的操作接口: 初始化(找到dquota写入inode:i_dquta),释放, 分配释放block/分配释放inode,transfer(chown).<br>/*<br> * Definitions of diskquota operations.<br> */<br>struct dquot_operations dquot_operations = {<br>	dquot_initialize,		/* mandatory */ <font color=#3333ff>初始化 inode-&gt;i_dquot,简单明了..</font><br>	dquot_drop,			/* mandatory */ <font color=#3333ff>dqput(inode-&gt;i_dquot),同上...</font><br>	dquot_alloc_block,<br>	dquot_alloc_inode,<br>	dquot_free_block,<br>	dquot_free_inode,<br>	dquot_transfer   <font color=#3333ff>/*chown的时候进行....*/</font><br>};<br>然后通过quotaops.h定义的宏来使用这个接口....<br>唯一值得注意的是<br>static struct dquot *<font color=#3333ff><b>dqduplicate</b></font>(struct dquot *dquot)<br>{<br>	if (dquot == NODQUOT || !dquot-&gt;dq_sb)<br>		return NODQUOT;<br>	dquot-&gt;dq_count++;<br>	wait_on_dquot(dquot);<br>	if (!dquot-&gt;dq_sb) {<br>		dquot-&gt;dq_count--;<br>		return NODQUOT;<br>	}<br>	dquot-&gt;dq_referenced++;<br>	dqstats.lookups++;<br>	return dquot;<br>}<br>只是获取一个引用计数,同时考虑加锁的情况:参考函数 </font></font><font color=#3333ff><font color=#000000>dquot_alloc_block, dquot_alloc_inode,结合其流程,此操作不难理解的.<br><br><br></font></font><font color=#3333ff><font color=#000000><br><font size=5><b>8. Sync , quota on/off</b></font><br>其实主要的部分已经完了. 剩下的就是使能, 关闭,同步操作了.<br>同步: 看一下函数,就是写入quota<br>int <font color=#3333ff><b>sync_dquots</b></font>(kdev_t dev, short type)<br>{<br>	struct dquot *dquot, *next, *ddquot;<br>	int need_restart;<br><br>restart:<br>	next = inuse_list;<br>	need_restart = 0;<br>	while ((dquot = next) != NULL) {<br>		next = dquot-&gt;dq_next;<br>                <font color=#3333ff>/*各种有效性检查*/</font><br>		if (dev &amp;&amp; dquot-&gt;dq_dev != dev)<br>			continue;<br>                if (type != -1 &amp;&amp; dquot-&gt;dq_type != type)<br>			continue;<br>		if (!dquot-&gt;dq_sb)	/* Invalidated? */<br>			continue;<br>		<b>if (!(dquot-&gt;dq_flags &amp; (DQ_LOCKED | DQ_MOD)))</b><br style=FONT-WEIGHT:bold><b>			continue;</b><br><br>		if ((ddquot = dqduplicate(dquot)) == NODQUOT)<br>			continue;<br>		if (ddquot-&gt;dq_flags &amp; DQ_MOD)<br>			write_dquot(ddquot);<br>		dqput(ddquot);<br>		/* Set the flag for another pass. */<br>		need_restart = 1; <font color=#3333ff>//可能会睡眠,如要重新扫描</font><br>	}<br>	/*<br>	 * If anything blocked, restart the operation<br>	 * to ensure we don't miss any dquots.<br>	 */ <br>	if (need_restart)<br>		goto restart;<br><br>	dqstats.syncs++;<br>	return(0);<br>}<br>下面所有的函数都是为quota on/off准备的:<br>void <font color=#000099><b>invalidate_dquots</b></font>(kdev_t dev, short type) <font color=#3366ff>//说实话这个函数和同步差不多,只是要等待已经lock的quota而已</font><br>{                                                <font color=#3333ff>//invalid 操作必须完成(on/off),所以要等待-&gt;写入磁盘-&gt;重新初始化</font><br>	.........<br>restart:<br>	next = inuse_list;	/* Here it is better. Otherwise the restart doesn't have any sense ;-) */<br>	need_restart = 0;<br>	while ((dquot = next) != NULL) {<br>                ......<br>		<b>if (dquot-&gt;dq_flags &amp; DQ_LOCKED) {</b><br style=FONT-WEIGHT:bold><b>			__wait_on_dquot(dquot);</b><br style=FONT-WEIGHT:bold><br style=FONT-WEIGHT:bold><b>			/* Set the flag for another pass. */</b><br style=FONT-WEIGHT:bold><b>			need_restart = 1;</b><br>			/*<br>			 * Make sure it's still the same dquot.<br>			 */<br>			if (dquot-&gt;dq_dev != dev)<br>				continue;<br>			if (dquot-&gt;dq_type != type)<br>				continue;<br>			if (!dquot-&gt;dq_sb)<br>				continue;<br>		}<br>		/*<br>		 *  Because inodes needn't to be the only holders of dquot<br>		 *  the quota needn't to be written to disk. So we write it<br>		 *  ourselves before discarding the data just for sure...<br>		 */<br>		if (dquot-&gt;dq_flags &amp; DQ_MOD &amp;&amp; dquot-&gt;dq_sb)<br>		{<br>			write_dquot(dquot);<br>			need_restart = 1;	/* We slept on IO */<br>		}<br>		clear_dquot(dquot);<br>	}<br>	/*<br>	 * If anything blocked, restart the operation<br>	 * to ensure we don't miss any dquots.<br>	 */ <br>	if (need_restart)<br>		goto restart;<br>}<br><br><font color=#3333ff><br><b>add_dquot_ref</b></font> : quota on的时候, 遍历使能的quota的这个文件系统所有已经打开的文件,挂接一个dquot到inode-&gt;i_dquot<br><font color=#3333ff><br><br><br><b>remove_dquot_ref:这个函数在inode.c</b></font> quota off的时候,复杂性在于必须遍历所有inode,与上面</font></font><font color=#3333ff><font color=#000000><font color=#3333ff><b>add_dquot_ref</b></font></font></font><font color=#3333ff><font color=#000000> 有所不<br>同,并且将dqput分成两个步骤来做:<br>  remove_inode_dquot_ref : </font></font><font color=#3333ff><font color=#000000><font color=#3333ff><b>remove_dquot_ref </b>is caller, 和dqput相比,不写入文件,仅仅减少引用计数+放到一个临时<br>                           链表<br>  put_dquot_list :遍历临时链表做dqput操作.<br><br><font color=#000000>说完了这些, dquot 的on off 函数反到根本不比再说了.</font><br><font color=#000000><br><font size=5><b>9.dquota的配置函数</b></font><br><br>这个好像不用说吧............,bye (函数虽多,配置而已,重要,但是理解他们的方式不再配置本身....)<br></font><br><br></font></font></font><br><br></pre>
    </td>
  </tr>
  </tbody>
</table></body></html>

⌨️ 快捷键说明

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