オペレーティングシステムの大規模な実験進展(6)---Linuxカーネルファイルシステムと設備の操作フロー分析
31189 ワード
変換先:http://www.whitecell.org/list.php?id=45
WSS(Whitecell Security Systems)は、非営利民間技術組織であり、様々なシステムセキュリティ技術の研究に力を入れている.伝統的なhacker精神を堅持し、技術の精製を追求する.
WSSホームページ:http://www.whitecell.org/
WSSフォーラム:http://www.whitecell.org/forums/
linux kernel ,
ext3 open , :
1、 , struct file struct dentry
struct inode ?
2、 VFS(Virtual File System) struct file
, ? ?
3、linux UNIX VFS(Virtual File System) struct vnode
, ?
4、 (super block) ?
5、 struct file ?
6、 ? ? ?
: , ,
, , 。
。 ,
, 。 ,
, 。
linux kernel , , filp_open()
kernel api , 。
filp_open() , do_filp_open() ,
open_namei() fd struct nameidata 。
nameidata_to_filp() struct file 。
static struct file *do_filp_open(int dfd, const char *filename, int flags,
int mode)
{
int namei_flags, error;
struct nameidata nd;
namei_flags = flags;
if ((namei_flags+1) & O_ACCMODE)
namei_flags++;
//
// path_lookup_xxx()
// struct nameidata 。
// , 。
// nameidata 。
//
error = open_namei(dfd, filename, namei_flags, mode, &nd);
if (!error)
//
// struct file 。
// 。
//
return nameidata_to_filp(&nd, flags);
return ERR_PTR(error);
}
struct nameidata struct file。
struct file __dentry_open() ,
nameidata->dentry, struct nameidata
, struct dentry 。
struct file *nameidata_to_filp(struct nameidata *nd, int flags)
{
struct file *filp;
/* Pick up the filp from the open intent */
filp = nd->intent.open.file;
/* Has the filesystem initialised the file for us? */
if (filp->f_dentry == NULL)
//
// struct file ,
// , struct file 。
//
filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL);
else
path_release(nd);
return filp;
}
struct file 。 ,
struct file struct dentry,struct inode,struct vfsmount
。 struct dentry struct inode
, struct dentry 。 struct inode
, ext3
。 , 。 ?
。
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
int flags, struct file *f,
int (*open)(struct inode *, struct file *))
{
struct inode *inode;
int error;
//
//
//
f->f_flags = flags;
f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK |
FMODE_PREAD | FMODE_PWRITE;
//
// struct dentry struct inode
//
inode = dentry->d_inode;
//
// (inode) ,
// cleanup_file
//
if (f->f_mode & FMODE_WRITE) {
error = get_write_access(inode);
if (error)
goto cleanup_file;
}
//
// vfsmount,dentry,inode
// struct file 。
//
f->f_mapping = inode->i_mapping;
f->f_dentry = dentry;
f->f_vfsmnt = mnt;
f->f_pos = 0;
//
// : struct inode struct file_operations
// struct file->f_op。 struct file
// inode->file_operations 。 struct
// file , open
// struct file , inode->i_fop ,struct file
// , , task_struct files_struct
// struct file 。 struct file
// , , 。;)
//
f->f_op = fops_get(inode->i_fop);
file_move(f, &inode->i_sb->s_files);
//
// : struct file->f_op->open ,
// struct inode->i_fop->open 。 , struct
// inode , , struct
// file_operations struct inode_operations。 open
// file_operations , 。 struct inode
// i_fop ,
// ext3_file_operations 。
// def_chr_fops 。
//
if (!open && f->f_op)
open = f->f_op->open;
if (open) {
error = open(inode, f);
if (error)
goto cleanup_all;
}
//
// 。
//
f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
/* NB: we're sure to have correct a_ops only after f_op->open */
if (f->f_flags & O_DIRECT) {
if (!f->f_mapping->a_ops ||
((!f->f_mapping->a_ops->direct_IO) &&
(!f->f_mapping->a_ops->get_xip_page))) {
fput(f);
f = ERR_PTR(-EINVAL);
} }
return f;
//
// , 。 struct file
// , 。
//
cleanup_all:
fops_put(f->f_op);
if (f->f_mode & FMODE_WRITE)
put_write_access(inode);
file_kill(f);
f->f_dentry = NULL;
f->f_vfsmnt = NULL;
cleanup_file:
put_filp(f);
dput(dentry);
mntput(mnt);
return ERR_PTR(error);
}
struct file f_op struct inode->i_fop
。 , register_xxx “ ”
“ ” , struct file 。
, *nix ,
inode, file system device driver
struct inode , file_operations ,
file system device driver ?
device driver ?
ext3 , ext3_read_inode() 。
, ? ext3 open
, ,
, 。
void ext3_read_inode(struct inode * inode)
{
struct ext3_iloc iloc;
struct ext3_inode *raw_inode;
struct ext3_inode_info *ei = EXT3_I(inode);
struct buffer_head *bh;
int block;
//
// , 。
//
#ifdef CONFIG_EXT3_FS_POSIX_ACL
ei->i_acl = EXT3_ACL_NOT_CACHED;
ei->i_default_acl = EXT3_ACL_NOT_CACHED;
#endif
ei->i_block_alloc_info = NULL;
//
// : __ext3_get_inode_loc
// I/O struct inode
// in core 。
// , 0 I/O
// , buffer_head 。
//
if (__ext3_get_inode_loc(inode, &iloc, 0))
//
// inode ,
// 。
//
goto bad_inode;
......
......
//
// , / / 。
//
if (S_ISREG(inode->i_mode)) {
//
// , ext3_file_xxx
// : ext3_file_operations ,
// open generic_file_open() ,
// , ,
// ext3 ,open
// , 。 ?
// 。
//
inode->i_op = &ext3_file_inode_operations;
inode->i_fop = &ext3_file_operations;
ext3_set_aops(inode);
} else if (S_ISDIR(inode->i_mode)) {
//
// , , ext3_dir_xxx
//
inode->i_op = &ext3_dir_inode_operations;
inode->i_fop = &ext3_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
//
// , , ext3_symlink_xxx
//
if (ext3_inode_is_fast_symlink(inode))
inode->i_op = &ext3_fast_symlink_inode_operations;
else {
inode->i_op = &ext3_symlink_inode_operations;
ext3_set_aops(inode);
}
} else {
//
// ,
// : inode->i_op 。
// inode->i_fop init_special_inode()
//
//
inode->i_op = &ext3_special_inode_operations;
if (raw_inode->i_block[0])
init_special_inode(inode, inode->i_mode,
old_decode_dev(le32_to_cpu(raw_inode->i_block[0])));
else
init_special_inode(inode, inode->i_mode,
new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
}
......
......
}
,
。
, ,
“ ”,“ ”,“FIFO”,“SOCKET” ,
“FIFO”,“SOCK” , “ ” ,
, 。
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
inode->i_mode = mode;
//
// , def_chr_fops
// inode->i_rdev
//
if (S_ISCHR(mode)) {
inode->i_fop = &def_chr_fops;
inode->i_rdev = rdev;
//
// , def_blk_fops
// inode->i_rdev
//
} else if (S_ISBLK(mode)) {
inode->i_fop = &def_blk_fops;
inode->i_rdev = rdev;
//
// FIFO, def_fifo_fops
//
} else if (S_ISFIFO(mode))
inode->i_fop = &def_fifo_fops;
//
// SOCKET, def_sock_fops
//
else if (S_ISSOCK(mode))
inode->i_fop = &bad_sock_fops;
//
// , 。
//
else
printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o)
",
mode);
}
, “ ”
, file_operations open ,
chrdev_open() 。 struct file->f_op
? chrdev_open() 。
const struct file_operations def_chr_fops = {
.open = chrdev_open,
};
struct file->f_op
。 ,
。
int chrdev_open(struct inode * inode, struct file * filp)
{
struct cdev *p;
struct cdev *new = NULL;
int ret = 0;
spin_lock(&cdev_lock);
//
//
//
p = inode->i_cdev;
if (!p) {
struct kobject *kobj;
int idx;
spin_unlock(&cdev_lock);
//
// ,
//
kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
if (!kobj)
return -ENXIO;
new = container_of(kobj, struct cdev, kobj);
spin_lock(&cdev_lock);
//
//
//
p = inode->i_cdev;
if (!p) {
inode->i_cdev = p = new;
inode->i_cindex = idx;
list_add(&inode->i_devices, &p->list);
new = NULL;
//
// cdev_get()
//
//
} else if (!cdev_get(p))
ret = -ENXIO;
//
// , cdev_get()
// , 。
//
} else if (!cdev_get(p))
ret = -ENXIO;
spin_unlock(&cdev_lock);
cdev_put(new);
//
// , 。
//
if (ret)
return ret;
//
// : cdev->file_operations
// struct file->f_op
// 。
//
filp->f_op = fops_get(p->ops);
//
// struct file->f_op ,
// , 。 :
// , ,
// , 。
//
if (!filp->f_op) {
cdev_put(p);
return -ENXIO;
}
//
// open ,
//
//
if (filp->f_op->open) {
lock_kernel();
ret = filp->f_op->open(inode,filp);
unlock_kernel();
}
if (ret)
cdev_put(p);
return ret;
}
,
, open ,
ext3, ext3 , ,
。
。 , ,
ext3_read_inode() ,
? ? ext3 open
? , open_namei() 。
struct nameidata
, , 。
, path_look_xxx() 。
int open_namei(int dfd, const char *pathname, int flag,
int mode, struct nameidata *nd)
{
int acc_mode, error;
struct path path;
struct dentry *dir;
int count = 0;
//
// , 。
//
......
//
// , path_lookup_open()
//
if (!(flag & O_CREAT)) {
//
// inode, dentry nameidata 。
//
error = path_lookup_open(dfd, pathname, lookup_flags(flag),
nd, flag);
if (error)
return error;
goto ok;
}
/*
* Create - we need to know the parent.
*/
//
// path_lookup_create()
//
error = path_lookup_create(dfd,pathname,LOOKUP_PARENT,nd,flag,mode);
if (error)
return error;
......
}
path_lookup_open() path_lookup_create()
__path_lookup_intent_open() ,
。 struct nameidata do_path_lookup()
。
static int __path_lookup_intent_open(int dfd, const char *name,
unsigned int lookup_flags, struct nameidata *nd,
int open_flags, int create_mode)
{
//
// struct file
//
struct file *filp = get_empty_filp();
int err;
if (filp == NULL)
return -ENFILE;
//
// struct nameidata
//
nd->intent.open.file = filp;
nd->intent.open.flags = open_flags;
//
// , path_lookup_open()
// path_lookup_create()
//
nd->intent.open.create_mode = create_mode;
//
// do_path_lookup() struct nameidata
//
err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd);
if (IS_ERR(nd->intent.open.file)) {
if (err == 0) {
err = PTR_ERR(nd->intent.open.file);
path_release(nd);
}
} else if (err != 0)
release_open_intent(nd);
return err;
}
"/" AT_FDCWD struct vfsmount
struct dentry struct nameidata ,
。 link_path_walk() 。
static int fastcall do_path_lookup(int dfd, const char *name,
unsigned int flags, struct nameidata *nd)
{
int retval = 0;
int fput_needed;
struct file *file;
//
// struct file
//
struct fs_struct *fs = current->fs;
nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags;
nd->depth = 0;
//
// fs_struct->altrootmnt fs_struct->altroot
// struct vfsmount struct dentry
//
if (*name=='/') {
read_lock(&fs->lock);
if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
nd->mnt = mntget(fs->altrootmnt);
nd->dentry = dget(fs->altroot);
read_unlock(&fs->lock);
if (__emul_lookup_dentry(name,nd))
goto out; /* found in altroot */
read_lock(&fs->lock);
}
nd->mnt = mntget(fs->rootmnt);
nd->dentry = dget(fs->root);
read_unlock(&fs->lock);
//
// AT_FDCWD fs_struct->pwdmnt
// fs_struct->pwd struct vfsmount struct dentry
// ? FIXME
//
} else if (dfd == AT_FDCWD) {
read_lock(&fs->lock);
nd->mnt = mntget(fs->pwdmnt);
nd->dentry = dget(fs->pwd);
read_unlock(&fs->lock);
//
// fget_light() struct file
// struct file->f_vfsmnt struct vfsmount ,
// struct dentry struct file->f_dentry
//
} else {
//
// : struct dentry
//
struct dentry *dentry;
file = fget_light(dfd, &fput_needed);
retval = -EBADF;
if (!file)
goto out_fail;
//
// struct file
//
dentry = file->f_dentry;
retval = -ENOTDIR;
if (!S_ISDIR(dentry->d_inode->i_mode))
goto fput_fail;
retval = file_permission(file, MAY_EXEC);
if (retval)
goto fput_fail;
nd->mnt = mntget(file->f_vfsmnt);
nd->dentry = dget(dentry);
fput_light(file, fput_needed);
}
current->total_link_count = 0;
//
// : , 。
// , __link_path_walk()
// 。
//
retval = link_path_walk(name, nd);
out:
if (likely(retval == 0)) {
if (unlikely(!audit_dummy_context() && nd && nd->dentry &&
nd->dentry->d_inode))
audit_inode(name, nd->dentry->d_inode);
}
out_fail:
return retval;
fput_fail:
fput_light(file, fput_needed);
goto out_fail;
}
link_path_walk() __link_path_walk(),
, do_lookup() ,do_lookup()
inode 。 ,
, , 。
static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
{
struct path next;
struct inode *inode;
int err;
unsigned int lookup_flags = nd->flags;
//
// , 。
//
//
// ,
// do_lookup()
// inode 。
// /dir/temp/readme.txt
// do_lookup() inode
// readme.txt 。
//
for(;;) {
.......
//
// inode
//
err = do_lookup(nd, &this, &next);
if (err)
break;
......
last_with_slashes:
lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
last_component:
/* Clear LOOKUP_CONTINUE iff it was previously unset */
nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;
.......
//
// LOOKUP_CONTINUE , 。
//
err = do_lookup(nd, &this, &next);
if (err)
break;
......
}
path_release(nd);
return_err:
return err;
}
struct dentry ,
struct dentry 。 , real_lookup()
inode 。 struct dentry struct inode
。
static int do_lookup(struct nameidata *nd, struct qstr *name,
struct path *path)
{
struct vfsmount *mnt = nd->mnt;
//
// hlist struct dentry ,hlist
// inode HASH 。
//
struct dentry *dentry = __d_lookup(nd->dentry, name);
//
// real_lookup()
//
//
if (!dentry)
goto need_lookup;
if (dentry->d_op && dentry->d_op->d_revalidate)
goto need_revalidate;
done:
//
// , struct path
//
path->mnt = mnt;
path->dentry = dentry;
__follow_mount(path);
return 0;
need_lookup:
//
// , inode
//
dentry = real_lookup(nd->dentry, name, nd);
if (IS_ERR(dentry))
goto fail;
goto done;
need_revalidate:
dentry = do_revalidate(dentry, nd);
//
// 。 struct dentry
// real_lookup()
//
if (!dentry)
goto need_lookup;
if (IS_ERR(dentry))
goto fail;
goto done;
fail:
return PTR_ERR(dentry);
}
real_lookup() , ext3 inode
。 lookup ext3_lookup() 。
struct inode_operations ext3_dir_inode_operations = {
//
// ,
//
......
.lookup = ext3_lookup,
......
};
inode, struct dentry
, parent->d_inode->i_op->lookup ext3_lookup()
inode。
static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, struct nameidata *nd)
{
struct dentry * result;
//
// , 。
//
//
// inode。
// , inode 。
//
struct inode *dir = parent->d_inode;
......
//
// 。
//
result = d_lookup(parent, name);
if (!result) {
//
// , struct dentry
// : struct dentry,
// dentry 。
//
struct dentry * dentry = d_alloc(parent, name);
result = ERR_PTR(-ENOMEM);
if (dentry) {
//
// ext3_lookup() ,
// ext3_dir_inode_operations
//
//
result = dir->i_op->lookup(dir, dentry, nd);
if (result)
dput(dentry);
else
result = dentry;
}
mutex_unlock(&dir->i_mutex);
return result;
}
.......
}
。 , dentry
ext3_dir_entry_2 dentry , inode number,
iget() struct inode , inode dentry
。
static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
{
struct inode * inode;
struct ext3_dir_entry_2 * de;
struct buffer_head * bh;
if (dentry->d_name.len > EXT3_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
//
// dentry buffer_head
// : dentry , d_parent
// d_inode , 。
// de inode number。
//
bh = ext3_find_entry(dentry, &de);
//
// : inode NULL
//
inode = NULL;
if (bh) {
unsigned long ino = le32_to_cpu(de->inode);
brelse (bh);
//
// (super block)
//
if (!ext3_valid_inum(dir->i_sb, ino)) {
ext3_error(dir->i_sb, "ext3_lookup",
"bad inode number: %lu", ino);
inode = NULL;
} else
//
// iget() struct inode
// (super block)
//
inode = iget(dir->i_sb, ino);
if (!inode)
return ERR_PTR(-EACCES);
}
//
// inode dentry 。
//
return d_splice_alias(inode, dentry);
}
iget() , (super block)
。
struct super_block {
//
// ,
//
......
//
// 。 mount
// 。
//
struct file_system_type *s_type;
//
// (super block)
//
struct super_operations *s_op;
......
};
ext3 (super block)
static struct super_operations ext3_sops = {
//
// ,
//
......
//
// : ext3_read_inode()
//
.read_inode = ext3_read_inode,
......
};
! , ,
(super block) read_inode , ext3_sops
ext3_read_inode() 。
static inline struct inode *iget(struct super_block *sb, unsigned long ino)
{
struct inode *inode = iget_locked(sb, ino);
if (inode && (inode->i_state & I_NEW)) {
//
// ext3_read_inode()
//
sb->s_op->read_inode(inode);
unlock_new_inode(inode);
}
return inode;
}
ext3_read_inode() ,
open_namei() iget() , iget()
(super block) ext3_sops
ext3_read_inode() inode。
struct inode->i_fop ( ext3_file_operations )
open generic_file_open() 。 inode
open_namei()->iget() , inode
, inode /
。 generic_file_open() ,
。 ,
open struct inode->i_fop->open ,
open 。 __dentry_open()
。 ,
, (super block) ext3_sops
? , mount
。
mount ,
, register_filesyste()。
struct file_system_type {
//
// , :ext3
//
const char *name;
int fs_flags;
//
// (super block) 。 mount
// , inode 。
//
int (*get_sb) (struct file_system_type *, int,
const char *, void *, struct vfsmount *);
void (*kill_sb) (struct super_block *);
//
//
//
struct module *owner;
//
//
//
struct file_system_type * next;
struct list_head fs_supers;
struct lock_class_key s_lock_key;
struct lock_class_key s_umount_key;
};
ext3 。
static struct file_system_type ext3_fs_type = {
.owner = THIS_MODULE,
.name = "ext3",
//
// ext3_get_sb()
//
.get_sb = ext3_get_sb,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
register_filesystem( &ext3_fs_type ); 。
, mount
。 , vfs_kern_mount() ,
mount ,
file_system_type , ext3 ext3_fs_type。
type->get_sb ext3_get_sb() 。
struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
struct vfsmount *mnt;
char *secdata = NULL;
int error;
if (!type)
return ERR_PTR(-ENODEV);
error = -ENOMEM;
//
// vfsmount 。
//
mnt = alloc_vfsmnt(name);
if (!mnt)
goto out;
if (data) {
secdata = alloc_secdata();
if (!secdata)
goto out_mnt;
error = security_sb_copy_data(type, data, secdata);
if (error)
goto out_free_secdata;
}
//
// : (super block)
// ext3 , ext3_get_sb,
// file_system_type 。
//
error = type->get_sb(type, flags, name, data, mnt);
if (error < 0)
goto out_free_secdata;
error = security_sb_kern_mount(mnt->mnt_sb, secdata);
if (error)
goto out_sb;
//
// dentry
//
mnt->mnt_mountpoint = mnt->mnt_root;
//
// vfsmount parent
// parent mount
//
mnt->mnt_parent = mnt;
up_write(&mnt->mnt_sb->s_umount);
free_secdata(secdata);
return mnt;
//
//
//
out_sb:
dput(mnt->mnt_root);
up_write(&mnt->mnt_sb->s_umount);
deactivate_super(mnt->mnt_sb);
out_free_secdata:
free_secdata(secdata);
out_mnt:
free_vfsmnt(mnt);
out:
return ERR_PTR(error);
}
ext3_get_sb() , get_sb_bdev()
, get_sb_bdev() ext3_get_sb()
, ext3_fill_super ,
。
static int ext3_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
//
// : ext3_fill_super() 。
//
return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super, mnt);
}
ext3_fill_super() ,
(super block) 。 ext3
(super block) ext3_sops 。 iget()
(super block) 。
static int ext3_fill_super (struct super_block *sb, void *data, int silent)
{
//
// , 。
//
//
//
//
sb->s_op = &ext3_sops;
sb->s_export_op = &ext3_export_ops;
sb->s_xattr = ext3_xattr_handlers;
#ifdef CONFIG_QUOTA
sb->s_qcop = &ext3_qctl_operations;
sb->dq_op = &ext3_quota_operations;
#endif
INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
sb->s_root = NULL;
//
// iget() inode。
//
root = iget(sb, EXT3_ROOT_INO);
//
// inode (super block)
// s_root struct dentry 。
//
sb->s_root = d_alloc_root(root);
//
// dentry 。
//
if (!sb->s_root) {
printk(KERN_ERR "EXT3-fs: get root inode failed
");
iput(root);
goto failed_mount4;
}
//
// inode
// 。
//
if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
dput(sb->s_root);
sb->s_root = NULL;
printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck
");
goto failed_mount4;
}
}
, 。 。
sys_open , filp_open()->do_filp_open()
, do_filp_open() , open_namei() struct
nameidata , __path_lookup_intent_open()
struct nameidata->intent.open , do_path_lookup() ,
struct nameidata->mnt struct nameidata->dentry
_link_path_walk() , do_lookup()
struct inode。do_lookup() inode
hlist inode, real_lookup() ,
struct dentry , struct inode->i_op->lookup()
, ext3_lookup() , struct dentry
inode number iget() struct inode。( ,
struct dentry , struct dentry
, ) iget() struct inode
(super block) ext3_read_inode() inode
, in core struct inode /
struct inode->i_op struct inode->i_fop 。
。
ext3_file_operations / , 。
, , 。
struct inode,struct dentry, struct nameidata 。
open_namei() nameidata
nameidata_to_filp() , struct dentry
__dentry_open() , struct file ,
struct inode->i_fop struct file->f_op ( , inode
, )。
, 。 / /
ext3_file_xxx ext3_dir_xxx 。
init_special_inode ,
chrdev_open() struct file 。
(super block) register_filesystem() ,
mount vfs_kern_mount() ext3_fill_super()
。 , 。 struct
inode 。 / ,struct
inode_operations (inode) / ( )/ / ,struct
file_operations / / / (readdir)/
。
:linux kernel source 2.6.19.1
/usr/fs/ext3/inode.c
/usr/fs/ext3/namei.c
/usr/fs/ext3/super.c
/usr/fs/ext3/file.c
/usr/fs/ext3/dir.c
/usr/fs/block_dev.c
/usr/fs/open.c
/usr/fs/dcache.h
/usr/fs/inode.c
/usr/fs/namei.c
/usr/fs/super.c
/inlucde/linux/mount.h
WSS(Whitecell Security Systems)は、非営利民間技術組織であり、様々なシステムセキュリティ技術の研究に力を入れている.伝統的なhacker精神を堅持し、技術の精製を追求する.
WSSホームページ:http://www.whitecell.org/
WSSフォーラム:http://www.whitecell.org/forums/