文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>027_fs_attr.c_dnotify.c

027_fs_attr.c_dnotify.c

时间:2009-03-27  来源:hylpro

attr.c 
2007-3-6
 inode,即文件,拥有各种属性,时间/从属/size等。内核提供对这些属性改变的通知事件。同一个文件可以有很多的进程注册了notify
每个进程感兴趣的属性也可以不同。这个文件提供了几个接口,来统一对文件属性的修改进行鉴权/实施/以及通知。
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记录于file-〉f_owner).此文件就是提供管理这些信息的函数。

实在没有什么说的,见上图和这个两个简单的函数。
/*
* 将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!\n");
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);
}
 
 
 
相关阅读 更多 +
排行榜 更多 +
房间毁灭模拟器最新版

房间毁灭模拟器最新版

休闲益智 下载
街头追逐者最新版

街头追逐者最新版

休闲益智 下载
弓箭手2内置作弊菜单

弓箭手2内置作弊菜单

休闲益智 下载