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

📄 027_fs_attr_c_dnotify_c.html

📁 重读linux 2.4.2o所写的笔记
💻 HTML
字号:
  <html lang="zh-CN" xmlns:gdoc="">  <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <style type="text/css">/* default css */table {  font-size: 1em;  line-height: inherit;}div, address, ol, ul, li, option, select {   margin-top: 0px;  margin-bottom: 0px;}p {  margin: 0px;}body {        margin: 0px;          padding: 0px;    font-family: Verdana, sans-serif;  font-size: 10pt;  background-color: #ffffff;}h6 { font-size: 10pt }h5 { font-size: 11pt }h4 { font-size: 12pt }h3 { font-size: 13pt }h2 { font-size: 14pt }h1 { font-size: 16pt }blockquote {padding: 10px; border: 1px #DDD dashed }a img {border: 0}div.google_header, div.google_footer {  position: relative;  margin-top: 1em;  margin-bottom: 1em;}/* end default css */  /* default print css */    @media print {    body {       padding: 0;       margin: 0;     }    div.google_header, div.google_footer {      display: block;      min-height: 0;      border: none;    }    div.google_header {      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_10c6h497:6">      <div align=center>
  <table align=center border=0 cellpadding=0 cellspacing=0 height=5716 width=802>
    <tbody>
    <tr>
      <td height=5716 valign=top width=802>
        <div align=center>
          <pre><b><font color=#ff00ff><font size=4>attr.c</font>       <br></font>                    </b>2007-3-6                 </pre>
        </div>
        <pre>  inode,即文件,<span lang=zh-cn>拥有各种属性,时间/从属/size等。内核提供对这些属性改变的通知事件。同一个文件可以有很多的进程注册了notify<br>每个进程感兴趣的属性也可以不同。这个文件提供了几个接口,来统一对文件属性的修改进行鉴权/实施/以及通知。<br>   </span>struct iattr *attr : 要修改的属性通过这个结构传递,fs.h 定义的<br>             #define ATTR_MODE 1<br>             #define ATTR_UID  2<br>设置到iattr的ia_valid,来指明要修改的属性,之后的鉴权/修改/通知都通过ia_valid来确定。 相关的代码并不复杂。简单罗列到这里<br>以供参考。<br></pre>
        <pre><font color=#0000ff>/*<br>  * 就是根据attr,看看你要改什么东西,权限购不够<br>  */</font>
/* POSIX UID/GID verification for setting inode attributes. */
int inode_change_ok(struct inode *inode, struct iattr *attr)
{
	int retval = -EPERM;
	unsigned int ia_valid = attr-&gt;ia_valid;</pre>
        <pre>	<font color=#0000ff>/* If force is set do it anyway. */</font>
	if (ia_valid &amp; ATTR_FORCE)
		goto fine;</pre>
        <pre>	/* Make sure a caller can chown. */<br>	if ((ia_valid &amp; ATTR_UID) &amp;&amp;<br>	    (current-&gt;fsuid != inode-&gt;i_uid ||<br>	     attr-&gt;ia_uid != inode-&gt;i_uid) &amp;&amp; !capable(CAP_CHOWN))<br>		goto error;</pre>
        <pre>	/* Make sure caller can chgrp. */<br>	if ((ia_valid &amp; ATTR_GID) &amp;&amp;<br>	    (!in_group_p(attr-&gt;ia_gid) &amp;&amp; attr-&gt;ia_gid != inode-&gt;i_gid) &amp;&amp;<br>	    !capable(CAP_CHOWN))<br>		goto error;</pre>
        <pre>	/* Make sure a caller can chmod. */<br>	if (ia_valid &amp; ATTR_MODE) {<br>		if ((current-&gt;fsuid != inode-&gt;i_uid) &amp;&amp; !capable(CAP_FOWNER))<br>			goto error;<br>		/* Also check the setgid bit! */<br>		if (!in_group_p((ia_valid &amp; ATTR_GID) ? attr-&gt;ia_gid :<br>				inode-&gt;i_gid) &amp;&amp; !capable(CAP_FSETID))<br>			attr-&gt;ia_mode &amp;= ~S_ISGID;<br>	}</pre>
        <pre>	/* Check for setting the inode time. */<br>	if (ia_valid &amp; (ATTR_MTIME_SET | ATTR_ATIME_SET)) {<br>		if (current-&gt;fsuid != inode-&gt;i_uid &amp;&amp; !capable(CAP_FOWNER))<br>			goto error;<br>	}<br>fine:<br>	retval = 0;<br>error:<br>	return retval;<br>}</pre>
        <pre><font color=#0000ff>/*<br>  * 根据attr的目的,设置inode的各种属性<br>  *  要先调用inode_change_ok看看权限是否购,然后使用此函数<br>  *  设置相应属性<br>  */</font>
void inode_setattr(struct inode * inode, struct iattr * attr)
{
	unsigned int ia_valid = attr-&gt;ia_valid;</pre>
        <pre>	if (ia_valid &amp; ATTR_UID)<br>		inode-&gt;i_uid = attr-&gt;ia_uid;<br>	if (ia_valid &amp; ATTR_GID)<br>		inode-&gt;i_gid = attr-&gt;ia_gid;<br>	if (ia_valid &amp; ATTR_SIZE)<br>		vmtruncate(inode, attr-&gt;ia_size);<br>	if (ia_valid &amp; ATTR_ATIME)<br>		inode-&gt;i_atime = attr-&gt;ia_atime;<br>	if (ia_valid &amp; ATTR_MTIME)<br>		inode-&gt;i_mtime = attr-&gt;ia_mtime;<br>	if (ia_valid &amp; ATTR_CTIME)<br>		inode-&gt;i_ctime = attr-&gt;ia_ctime;<br>	if (ia_valid &amp; ATTR_MODE) {<br>		inode-&gt;i_mode = attr-&gt;ia_mode;<br>		if (!in_group_p(inode-&gt;i_gid) &amp;&amp; !capable(CAP_FSETID))<br>			inode-&gt;i_mode &amp;= ~S_ISGID;<br>	}<br>	mark_inode_dirty(inode);<br>}</pre>
        <pre><font color=#0000ff>/*<br>  * 根据根该的属性,获得一个detnry notify 的mask, dn_mask<br>  * inode-&gt;i_dnotify_mask 是进程所关心的事件,dn_mask是实际<br>  * 发生的事件,相与即可得知是否需要通知进程<br>  */</font>
static int setattr_mask(unsigned int ia_valid)
{
	unsigned long dn_mask = 0;</pre>
        <pre>	if (ia_valid &amp; ATTR_UID)<br>		dn_mask |= DN_ATTRIB;<br>	if (ia_valid &amp; ATTR_GID)<br>		dn_mask |= DN_ATTRIB;<br>	if (ia_valid &amp; ATTR_SIZE)<br>		dn_mask |= DN_MODIFY;<br>	/* both times implies a utime(s) call */<br>	if ((ia_valid &amp; (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME))<br>		dn_mask |= DN_ATTRIB;<br>	else if (ia_valid &amp; ATTR_ATIME)<br>		dn_mask |= DN_ACCESS;<br>	else if (ia_valid &amp; ATTR_MTIME)<br>		dn_mask |= DN_MODIFY;<br>	if (ia_valid &amp; ATTR_MODE)<br>		dn_mask |= DN_ATTRIB;<br>	return dn_mask;<br>}</pre>
        <pre><font color=#0000ff>/*<br> * 根据attr 设置inode的属性,并使用信号量通知相关进程<br> */</font>
int notify_change(struct dentry * dentry, struct iattr * attr)
{
	struct inode *inode = dentry-&gt;d_inode;
	int error;
	time_t now = CURRENT_TIME;
	unsigned int ia_valid = attr-&gt;ia_valid;</pre>
        <pre>	if (!inode)<br>		BUG();</pre>
        <pre>	attr-&gt;ia_ctime = now;<br>	if (!(ia_valid &amp; ATTR_ATIME_SET))<br>		attr-&gt;ia_atime = now;<br>	if (!(ia_valid &amp; ATTR_MTIME_SET))<br>		attr-&gt;ia_mtime = now;</pre>
        <pre>	lock_kernel();<br>	if (inode-&gt;i_op &amp;&amp; inode-&gt;i_op-&gt;setattr) <br>		<font color=#0000ff>/*ext2 未设置此op*/</font>
		error = inode-&gt;i_op-&gt;setattr(dentry, attr);
	else {
		<font color=#0000ff>/*所以对ext2来讲执行此公共流程*/</font>
		error = inode_change_ok(inode, attr);
		if (!error)
			inode_setattr(inode, attr);
	}
	unlock_kernel();
	if (!error) {
		unsigned long dn_mask = setattr_mask(ia_valid);
		if (dn_mask)
			inode_dir_notify(dentry-&gt;d_parent-&gt;d_inode, dn_mask);
	}
	return error;
}</pre>
        <pre> </pre>
        <pre> </pre>
        <div align=center>
          <pre><font color=#ff00ff size=4>dnotify.c<br>       2007.3.6</font></pre>
        </div>
        <div align=left>
          <pre>   这个文件和此话题密切相关,顺便也解决了吧。想要监控一个文件的时候,需要首先打开这个文件,然后通过fcntl注册,就会通过信号<br>接受到这个文件相关属性的通知消息。<br>  为此,struct file中有一个f_owner,其中记录了打开这个文件的进程,此文件的等信息。fcntl的时候就需要设置好这个结构,notify<br>就是据此找到信号应该发给那个进程。<br>  <br>  另外,需要在inode上挂一个dnotify_struct的链表,记录所有需要得到通知的file(pid记录于file-〉f_owner).此文件就是提供管理<br>这些信息的函数。<br>                                                      <br>  +------+                                            <br>  |inode |                                            <br>  +-/----+                                            <br>    |                                                 <br>    |       +-------------+  +-------------+          <br>    --------|dentry_notify|--|dentry_notify|          <br>            +------/------+  +-------------+          <br>                   |                                  <br>                   |                                  <br>                   |                                  <br>            +------\------------+                     <br>            | file-&gt;f_owner.pid |                     <br>            +-------------------+                     <br>   实在没有什么说的,见上图和这个两个简单的函数。                                                      </pre>
          <pre><font color=#0000ff>/*<br>  *  将file-&gt;f_owner 和dn 的关系建立起来<br>  */</font>
int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
{
	struct dnotify_struct *dn = NULL;
	struct dnotify_struct *odn;
	struct dnotify_struct **prev;
	struct inode *inode;
	int turning_off = (arg &amp; ~DN_MULTISHOT) == 0;</pre>
          <pre>	if (!turning_off &amp;&amp; !dir_notify_enable)<br>		return -EINVAL;<br>	inode = filp-&gt;f_dentry-&gt;d_inode;<br>	if (!S_ISDIR(inode-&gt;i_mode))<br>		return -ENOTDIR;<br>	if (!turning_off) {<br>		dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL);<br>		if (dn == NULL)<br>			return -ENOMEM;<br>	}<br>	write_lock(&amp;dn_lock);<br>	prev = &amp;inode-&gt;i_dnotify;<br>	for (odn = *prev; odn != NULL; prev = &amp;odn-&gt;dn_next, odn = *prev)<br>		if (odn-&gt;dn_filp == filp)<br>			break;<br>	if (odn != NULL) {<br>		if (turning_off) {<br>			*prev = odn-&gt;dn_next;<br>			redo_inode_mask(inode);<br>			dn = odn;<br>			goto out_free;<br>		}<br>		odn-&gt;dn_fd = fd;<br>		odn-&gt;dn_mask |= arg;<br>		inode-&gt;i_dnotify_mask |=<font color=#0000ff> arg &amp; ~DN_MULTISHOT</font>;<br>		goto out_free;<br>	}<br>	if (turning_off)<br>		goto out;<br>	<font color=#0000ff>filp-&gt;f_owner.pid = current-&gt;pid;<br>	filp-&gt;f_owner.uid = current-&gt;uid;<br>	filp-&gt;f_owner.euid = current-&gt;euid;<br>	dn-&gt;dn_magic = DNOTIFY_MAGIC;<br>	dn-&gt;dn_mask = arg;<br>	dn-&gt;dn_fd = fd;<br>	dn-&gt;dn_filp = filp;<br>	inode-&gt;i_dnotify_mask |= arg &amp; ~DN_MULTISHOT;</font>
	dn-&gt;dn_next = inode-&gt;i_dnotify;
	inode-&gt;i_dnotify = dn;
out:
	write_unlock(&amp;dn_lock);
	return 0;
out_free:
	kmem_cache_free(dn_cache, dn);
	goto out;
}</pre>
          <pre><font color=#0000ff>/*<br>  * 向所有监听此inode的进程发送信号<br>  */</font>
void __inode_dir_notify(struct inode *inode, unsigned long event)
{
	struct dnotify_struct *	dn;
	struct dnotify_struct **prev;
	struct fown_struct *	fown;
	int			changed = 0;</pre>
          <pre>	write_lock(&amp;dn_lock);<br>	prev = &amp;inode-&gt;i_dnotify;<br>	while ((dn = *prev) != NULL) {<br>		if (dn-&gt;dn_magic != DNOTIFY_MAGIC) {<br>		        printk(KERN_ERR "__inode_dir_notify: bad magic "<br>				"number in dnotify_struct!\n");<br>		        goto out;<br>		}<br>		if ((dn-&gt;dn_mask &amp; event) == 0) {<br>			prev = &amp;dn-&gt;dn_next;<br>			continue;<br>		}<br>		fown = &amp;dn-&gt;dn_filp-&gt;f_owner;<br>		if (fown-&gt;pid)<br>		        send_sigio(fown, dn-&gt;dn_fd, POLL_MSG);<br>		<font color=#0000ff>if (dn-&gt;dn_mask &amp; DN_MULTISHOT)<br>			prev = &amp;dn-&gt;dn_next;<br>		else {<br>			*prev = dn-&gt;dn_next;<br>			changed = 1;<br>			kmem_cache_free(dn_cache, dn);<br>		}</font>
	}
	if (changed)
		redo_inode_mask(inode);
out:
	write_unlock(&amp;dn_lock);
}</pre>
          <pre> </pre>
        </div>
        <pre> </pre>
        <pre>  <br></pre>
      </td>
    </tr>
    </tbody>
  </table>
</div></body></html>

⌨️ 快捷键说明

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