URN Logo
UNIX Resources » Linux » China Linux Forum » Linux内核技术 » 19 » 重读2.4 --027 fs/attr.c dnotify.c
announcement 声明: 本页内容为中国Linux论坛的内容镜像,文章的版权以及其他所有的相关权利属于中国Linux论坛和相应文章的作者,如果转载,请注明文章来源及相关版权信息。
Resources
China Linux Forum(finished)
Linux Forum(finished)
FreeBSD China(finished)
linuxforum.net
  业界新闻与评论
  自由软件杂谈
  IT 人生
  Linux软件快递
  翻译作坊
  Linux图书与评论
  GNU Emacs/XEmacs
  Linux 中文环境和中文化
  Linux桌面与办公软件
  Linux 多媒体与娱乐版
  自由之窗Mozilla
  笔记本电脑上的Linux
  Gentoo
  Debian 一族
  网络管理技术
  Linux 安装与入门
  WEB服务器和FTP服务器
  域名服务器和邮件服务器
  Linux防火墙和代理服务器应用
  文件及打印服务器
  技术培训与认证
  TI专版
  Linux内核技术
  Linux 嵌入技术
  Linux设备驱动程序
  Linux 集群技术
  LINUX平台数据库
  系统和网络安全
  CPU 与 编译器
  系统计算研究所专栏
  Linux下的GUI软件开发
  C/C++编程版
  PHP 技 术
  Java&jsp技术
  Shell编程技术
  Perl 编 程
  Python 编 程
  XML/Web Service 技术
  永远的Unix
  FreeBSD世界
   
重读2.4 --027 fs/attr.c dnotify.c
重读2.4 --027 fs/attr.c dnotify.c - hyl [2007-11-13 20:56 | 11,415 byte(s)]
 
Re: 重读2.4 --027 fs/attr.c dnotify.c - zyzii [2007-11-13 21:31 | 199 byte(s)]
 
Subject: 重读2.4 --027 fs/attr.c dnotify.c
Author: hyl    Posted: 2007-11-13 20:56    Length: 11,415 byte(s)
[Original] [Print] [Top]


attr.c
2007-3-6


inode,即文件,拥有各种属性,时间/从属/size等。内核提供对这些属性改变的通知事件。同一
鑫募梢杂泻芏嗟慕套⒉崃薾otify
每个进程感兴趣的属性也可以不同。这个文件提供了几个接口,来统一对文件属性的修改进行鉴权
/实施/以及通知。
struct iattr *attr : 要修改的属性通过这个结构传递,fs.h 定义的
#define ATTR_MODE 1
#define ATTR_UID 2
设置到iattr的ia_valid,来指明要修改的属性,之后的鉴权/修改/通知都通过ia_valid来确定。
相关的代码并不复杂。简单罗列到这里
以供参考。

/*
* 就是根据attr,看看你要改什么东西,权限购不够
*/
/* 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->ia_valid;

/* If force is set do it anyway. */
if (ia_valid & ATTR_FORCE)
goto fine;

/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
(current->fsuid != inode->i_uid ||
attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
goto error;

/* Make sure caller can chgrp. */
if ((ia_valid & ATTR_GID) &&
(!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)
&&
!capable(CAP_CHOWN))
goto error;

/* Make sure a caller can chmod. */
if (ia_valid & ATTR_MODE) {
if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
goto error;
/* Also check the setgid bit! */
if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
inode->i_gid) && !capable(CAP_FSETID))
attr->ia_mode &= ~S_ISGID;
}

/* Check for setting the inode time. */
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
goto error;
}
fine:
retval = 0;
error:
return retval;
}

/*
* 根据attr的目的,设置inode的各种属性
* 要先调用inode_change_ok看看权限是否购,然后使用此函数
* 设置相应属性
*/
void inode_setattr(struct inode * inode, struct iattr * attr)
{
unsigned int ia_valid = attr->ia_valid;

if (ia_valid & ATTR_UID)
inode->i_uid = attr->ia_uid;
if (ia_valid & ATTR_GID)
inode->i_gid = attr->ia_gid;
if (ia_valid & ATTR_SIZE)
vmtruncate(inode, attr->ia_size);
if (ia_valid & ATTR_ATIME)
inode->i_atime = attr->ia_atime;
if (ia_valid & ATTR_MTIME)
inode->i_mtime = attr->ia_mtime;
if (ia_valid & ATTR_CTIME)
inode->i_ctime = attr->ia_ctime;
if (ia_valid & ATTR_MODE) {
inode->i_mode = attr->ia_mode;
if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
inode->i_mode &= ~S_ISGID;
}
mark_inode_dirty(inode);
}

/*
* 根据根该的属性,获得一个detnry notify 的mask, dn_mask
* inode->i_dnotify_mask 是进程所关心的事件,dn_mask是实际
* 发生的事件,相与即可得知是否需要通知进程
*/
static int setattr_mask(unsigned int ia_valid)
{
unsigned long dn_mask = 0;

if (ia_valid & ATTR_UID)
dn_mask |= DN_ATTRIB;
if (ia_valid & ATTR_GID)
dn_mask |= DN_ATTRIB;
if (ia_valid & ATTR_SIZE)
dn_mask |= DN_MODIFY;
/* both times implies a utime(s) call */
if ((ia_valid & (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME))
dn_mask |= DN_ATTRIB;
else if (ia_valid & ATTR_ATIME)
dn_mask |= DN_ACCESS;
else if (ia_valid & ATTR_MTIME)
dn_mask |= DN_MODIFY;
if (ia_valid & ATTR_MODE)
dn_mask |= DN_ATTRIB;
return dn_mask;
}

/*
* 根据attr 设置inode的属性,并使用信号量通知相关进程
*/
int notify_change(struct dentry * dentry, struct iattr * attr)
{
struct inode *inode = dentry->d_inode;
int error;
time_t now = CURRENT_TIME;
unsigned int ia_valid = attr->ia_valid;

if (!inode)
BUG();

attr->ia_ctime = now;
if (!(ia_valid & ATTR_ATIME_SET))
attr->ia_atime = now;
if (!(ia_valid & ATTR_MTIME_SET))
attr->ia_mtime = now;

lock_kernel();
if (inode->i_op && inode->i_op->setattr)
/*ext2 未设置此op*/
error = inode->i_op->setattr(dentry, attr);
else {
/*所以对ext2来讲执行此公共流程*/
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->d_parent->d_inode, dn_mask);
}
return error;
}

 

 

dnotify.c
2007.3.6


这个文件和此话题密切相关,顺便也解决了吧。想要监控一个文件的时候,需要首先打开这个文件
,然后通过fcntl注册,就会通过信号
接受到这个文件相关属性的通知消息。
为此,struct
file中有一个f_owner,其中记录了打开这个文件的进程,此文件的等信息。fcntl的时候就需要设
置好这个结构,notify
就是据此找到信号应该发给那个进程。


另外,需要在inode上挂一个dnotify_struct的链表,记录所有需要得到通知的file(pid记录于fi
le-〉f_owner).此文件就是提供管理
这些信息的函数。

+------+
|dentry|
+-/----+
|
| +-------------+ +-------------+
--------|dentry_notify|--|dentry_notify|
+------/------+ +-------------+
|
|
|
+------------------+
| file->f_owner.pid |
+-------------------+
实在没有什么说的,见上图和这个两个简单的函数。


/*
* 将file->f_owner 和dn 的关系建立起来
*/
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 & ~DN_MULTISHOT) == 0;

if (!turning_off && !dir_notify_enable)
return -EINVAL;
inode = filp->f_dentry->d_inode;
if (!S_ISDIR(inode->i_mode))
return -ENOTDIR;
if (!turning_off) {
dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL);
if (dn == NULL)
return -ENOMEM;
}
write_lock(&dn_lock);
prev = &inode->i_dnotify;
for (odn = *prev; odn != NULL; prev = &odn->dn_next, odn = *prev)
if (odn->dn_filp == filp)
break;
if (odn != NULL) {
if (turning_off) {
*prev = odn->dn_next;
redo_inode_mask(inode);
dn = odn;
goto out_free;
}
odn->dn_fd = fd;
odn->dn_mask |= arg;
inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
goto out_free;
}
if (turning_off)
goto out;
filp->f_owner.pid = current->pid;
filp->f_owner.uid = current->uid;
filp->f_owner.euid = current->euid;
dn->dn_magic = DNOTIFY_MAGIC;
dn->dn_mask = arg;
dn->dn_fd = fd;
dn->dn_filp = filp;
inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
dn->dn_next = inode->i_dnotify;
inode->i_dnotify = dn;
out:
write_unlock(&dn_lock);
return 0;
out_free:
kmem_cache_free(dn_cache, dn);
goto out;
}

/*
* 向所有监听此inode的进程发送信号
*/
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;

write_lock(&dn_lock);
prev = &inode->i_dnotify;
while ((dn = *prev) != NULL) {
if (dn->dn_magic != DNOTIFY_MAGIC) {
printk(KERN_ERR "__inode_dir_notify: bad magic "
"number in dnotify_struct! ");
goto out;
}
if ((dn->dn_mask & event) == 0) {
prev = &dn->dn_next;
continue;
}
fown = &dn->dn_filp->f_owner;
if (fown->pid)
send_sigio(fown, dn->dn_fd, POLL_MSG);
if (dn->dn_mask & DN_MULTISHOT)
prev = &dn->dn_next;
else {
*prev = dn->dn_next;
changed = 1;
kmem_cache_free(dn_cache, dn);
}
}
if (changed)
redo_inode_mask(inode);
out:
write_unlock(&dn_lock);
}

 
[Original] [Print] [Top]
Subject: Re: 重读2.4 --027 fs/attr.c dnotify.c
Author: zyzii    Posted: 2007-11-13 21:31    Length: 199 byte(s)
[Original] [Print] [Top]
版调的不好了啊,参考:
http://www.linuxforum.net/forum/faq_chinese.php?Cat=
----
应用程序是LINUX的软肋。
[Original] [Print] [Top]
« Previous thread
重读2.4 --028 fs/bad_inode.c
Linux内核技术
19
Next thread »
重读2.4--026 pre /fs
     

Copyright © 2007~2009 UNIX Resources Network, All Rights Reserved.      About URN | Privacy & Legal | Help | Contact us
webmaster: webmaster@unixresources.net
This page created on 2009-09-07 16:26:33, cost 0.020810842514 ms.