Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1147723
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2279
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: LINUX

2020-10-05 23:29:06

参考<<深入分析Linux内核源码>>
fs/pipe.c 
管道文件系统pipefs
pipefs是一种简单的、虚拟的文件系统类型,因为它没有对应的物理设备,因此其安装时不需要块设备

#define fs_initcall(fn)__define_initcall("5",fn,5)
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
<linux 2.6.28 kernel之__initcal机制和module_init详解>
fs/pipe.c
static struct file_system_type pipe_fs_type = {
.name = "pipefs",
.get_sb = pipefs_get_sb,
.kill_sb = kill_anon_super,
};

include/linux/init.h
 
/* Don't use these in modules, but some people do... */
#define core_initcall(fn)module_init(fn)
#define postcore_initcall(fn)module_init(fn)
#define arch_initcall(fn)module_init(fn)
#define subsys_initcall(fn)module_init(fn)
#define fs_initcall(fn)module_init(fn)
#define device_initcall(fn)module_init(fn)
#define late_initcall(fn)module_init(fn)
 //////////////////////////////////
fs_initcall(init_pipe_fs);
module_exit(exit_pipe_fs);
 
 
static int __init init_pipe_fs(void)
{
int err = register_filesystem(&pipe_fs_type);

if (!err) {
                        //在通过register_filesystem()成功地注册了该文件系统后,应该通过kern_mount()来安装 
//
#define kern_mount(type) kern_mount_data(type, NULL)                  // fs.h 
pipe_mnt = kern_mount(&pipe_fs_type);
if (IS_ERR(pipe_mnt)) {
err = PTR_ERR(pipe_mnt);
unregister_filesystem(&pipe_fs_type);
//当安装出现错误时,则调用unregister_filesystem()把pipe_fs_type从file_systems链表中拆除。 
}
                                          //pipefs文件系统已被注册,并成为内核中的一个模块,从此我们就可以使用它了。
                                          //Pipefs文件系统的入口点就是pipe()系统调用,其内核实现函数为sys_pipe(),
                                         //而真正的工作是调用do_pipe()函数来完成的,其代码在/fs/pipe.c中 
}
return err;
}
//////////////////////////
static void __exit exit_pipe_fs(void)
{
unregister_filesystem(&pipe_fs_type);
mntput(pipe_mnt);
}
/////////////////////////
static struct file_system_type pipe_fs_type = {
.name= "pipefs",
.get_sb= pipefs_get_sb,
.kill_sb= kill_anon_super,
}; 
/*
 * pipefs should _never_ be mounted by userland - too much of security hassle,
 * no real gain from having the whole whorehouse mounted. So we don't need
 * any operations on the root directory. However, we need a non-trivial
 * d_name - pipe: will go nicely and kill the special-casing in procfs.
 */
该文件系统不能从用户空间进行安装,并且在整个系统范围内只有一个超级块 
static int pipefs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
struct vfsmount *mnt)
{
return get_sb_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC, mnt);
} 
/*
 * Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that
 * will never be mountable)
 */
int get_sb_pseudo(struct file_system_type *fs_type, char *name,
const struct super_operations *ops, unsigned long magic,
struct vfsmount *mnt)
{
struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
struct dentry *dentry;
struct inode *root;
struct qstr d_name = {.name = name, .len = strlen(name)};

if (IS_ERR(s))
return PTR_ERR(s);

s->s_flags = MS_NOUSER;
s->s_maxbytes = ~0ULL;
s->s_blocksize = PAGE_SIZE;
s->s_blocksize_bits = PAGE_SHIFT;
s->s_magic = magic;
s->s_op = ops ? ops : &simple_super_operations;
s->s_time_gran = 1;
root = new_inode(s);
if (!root)
goto Enomem;
/*
* since this is the first inode, make it number 1. New inodes created
* after this must take care not to collide with it (by passing
* max_reserved of 1 to iunique).
*/
root->i_ino = 1;
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
root->i_uid = root->i_gid = 0;
root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
dentry = d_alloc(NULL, &d_name);
if (!dentry) {
iput(root);
goto Enomem;
}
dentry->d_sb = s;
dentry->d_parent = dentry;
d_instantiate(dentry, root);
s->s_root = dentry;
s->s_flags |= MS_ACTIVE;
return simple_set_mnt(mnt, s);

Enomem:
up_write(&s->s_umount);
deactivate_super(s);
return -ENOMEM;
}
 fs/super.c
void kill_anon_super(struct super_block *sb)
{
int slot = MINOR(sb->s_dev);

generic_shutdown_super(sb);
spin_lock(&unnamed_dev_lock);
ida_remove(&unnamed_dev_ida, slot);
spin_unlock(&unnamed_dev_lock);
} 
/**
 *generic_shutdown_super-common helper for ->kill_sb()
 *@sb: superblock to kill
 *
 *generic_shutdown_super() does all fs-independent work on superblock
 *shutdown.  Typical ->kill_sb() should pick all fs-specific objects
 *that need destruction out of superblock, call generic_shutdown_super()
 *and release aforementioned objects.  Note: dentries and inodes _are_
 *taken care of and do not need specific handling.
 *
 *Upon calling this function, the filesystem may no longer alter or
 *rearrange the set of dentries belonging to this super_block, nor may it
 *change the attachments of dentries to inodes.
 */
 fs/super.c
void generic_shutdown_super(struct super_block *sb)
{
const struct super_operations *sop = sb->s_op;

if (sb->s_root) {
shrink_dcache_for_umount(sb);
fsync_super(sb);
lock_super(sb);
sb->s_flags &= ~MS_ACTIVE;
/* bad name - it should be evict_inodes() */
invalidate_inodes(sb);
lock_kernel();

if (sop->write_super && sb->s_dirt)
sop->write_super(sb);
if (sop->put_super)
sop->put_super(sb);

/* Forget any remaining inodes */
if (invalidate_inodes(sb)) {
printk("VFS: Busy inodes after unmount of %s. "
  "Self-destruct in 5 seconds.  Have a nice day...\n",
  sb->s_id);
}

unlock_kernel();
unlock_super(sb);
}
spin_lock(&sb_lock);
/* should be initialized for __put_super_and_need_restart() */
list_del_init(&sb->s_list);
list_del(&sb->s_instances);
spin_unlock(&sb_lock);
up_write(&sb->s_umount);
}
 
//#define kern_mount(type) kern_mount_data(type, NULL)                  // fs.h 
//kern_mount()类似于do_mount(),用来安装pipefs文件系统
surper.c
 
struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
{
return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
}

fs/filesystems.c 
/**
 *register_filesystem - register a new filesystem
 *@fs: the file system structure
 *
 *Adds the file system passed to the list of file systems the kernel
 *is aware of for mount and other syscalls. Returns 0 on success,
 *or a negative errno code on an error.
 *
 *The &struct file_system_type that is passed is linked into the kernel 
 *structures and must not be freed until the file system has been
 *unregistered.
 */
 
int register_filesystem(struct file_system_type * fs)
{
int res = 0;
struct file_system_type ** p;

BUG_ON(strchr(fs->name, '.'));
if (fs->next)
return -EBUSY;
INIT_LIST_HEAD(&fs->fs_supers);
write_lock(&file_systems_lock);
p = find_filesystem(fs->name, strlen(fs->name));
if (*p)
res = -EBUSY;
else
*p = fs;
write_unlock(&file_systems_lock);
return res;
}
//register_filesystem()函数把pipe_fs_type链接到file_systems链表,因此,你可以通过读/proc/filesystems(可能/proc被/sysfs替代了)找到“pipefs”入口点,在那里,“nodev”标志表示没有设置FS_REQUIRES_DEV标志,即该文件系统没有对应的物理设备  
 ///////////////////////////////////////////////////////////////////系统调用
///////////////////////////
fs/pipe.c
//////// 
////////pipefs文件系统已被注册,并成为内核中的一个模块,从此我们就可以使用它了。Pipefs文件系统的入口点就是pipe()系统调用其内核实现函数为sys_pipe(),而真正的工作是调用do_pipe()函数来完成的,其代码在/fs/pipe.c中
SYSCALL_DEFINE1(pipe, int __user *, fildes)
{
return sys_pipe2(fildes, 0);
}
/*
 * sys_pipe() is the normal C calling standard for creating
 * a pipe. It's not the way Unix traditionally does this, though.
 */
SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags)
{
int fd[2];
int error;

error = do_pipe_flags(fd, flags);
if (!error) {
if (copy_to_user(fildes, fd, sizeof(fd))) {
sys_close(fd[0]);
sys_close(fd[1]);
error = -EFAULT;
}
}
return error;
}
 
int do_pipe(int *fd)
{
return do_pipe_flags(fd, 0);
}
int do_pipe_flags(int *fd, int flags)
{
/*进程对每个已打开文件的操作是通过file结构进行的。一个管道实际上就是一个存在于内存的文件,对这个文件的操作要通过两个已打开的文件进行,f1、f2分别代表该管道的两端,读端和写端。*/ 
struct file *fw, *fr;
int error;
int fdw, fdr;

if (flags & ~(O_CLOEXEC | O_NONBLOCK))
return -EINVAL;

fw = create_write_pipe(flags);
if (IS_ERR(fw))
return PTR_ERR(fw);
fr = create_read_pipe(fw, flags);
error = PTR_ERR(fr);
if (IS_ERR(fr))
goto err_write_pipe;

error = get_unused_fd_flags(flags);
if (error < 0)
goto err_read_pipe;
fdr = error;

error = get_unused_fd_flags(flags);
if (error < 0)
goto err_fdr;
fdw = error;

error = audit_fd_pair(fdr, fdw);
if (error < 0)
goto err_fdw;

fd_install(fdr, fr);
fd_install(fdw, fw);
fd[0] = fdr;
fd[1] = fdw;

return 0;

 err_fdw:
put_unused_fd(fdw);
 err_fdr:
put_unused_fd(fdr);
 err_read_pipe:
path_put(&fr->f_path);
put_filp(fr);
 err_write_pipe:
free_write_pipe(fw);
return error;
}
struct file *create_write_pipe(int flags)
{
int err;
struct inode *inode;
struct file *f;
struct dentry *dentry;
struct qstr name = { .name = "" };

err = -ENFILE;
inode = get_pipe_inode();/*每个文件都有一个inode结构。由于管道文件在管道创建之前并不存在,因此,在创建管道时临时创建                                                                             一个inode结构。*/
if (!inode)
goto err;

err = -ENOMEM;
                                                                        /* File结构中有个指针f_dentry指向所打开文件的目录项dentry结构,
                                                                        而dentry 中有个指针指向相应的inode结构。
                                                                       所以,调用d_alloc()分配一个目录项是为了把file结构与inode结构联系起来。*/ 
dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name);
if (!dentry)
goto err_inode;

dentry->d_op = &pipefs_dentry_operations;
/*
* We dont want to publish this dentry into global dentry hash table.
* We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
* This permits a working /proc/$pid/fd/XXX on pipes
*/
dentry->d_flags &= ~DCACHE_UNHASHED;
d_instantiate(dentry, inode);

err = -ENFILE;
f = alloc_file(pipe_mnt, dentry, FMODE_WRITE, &write_pipefifo_fops);
if (!f)
goto err_dentry;
f->f_mapping = inode->i_mapping;

f->f_flags = O_WRONLY | (flags & O_NONBLOCK);
f->f_version = 0;

return f;

 err_dentry:
free_pipe_info(inode);
dput(dentry);
return ERR_PTR(err);

 err_inode:
free_pipe_info(inode);
iput(inode);
 err:
return ERR_PTR(err);
}
 
 
////////////////////////////////////////////////////////////////////// 
/*
 * The file_operations structs are not static because they
 * are also used in linux/fs/fifo.c to do operations on FIFOs.
 *
 * Pipes reuse fifos' file_operations structs.
 */
fs/pipe.c 
const struct file_operations read_pipefifo_fops = {
.llseek= no_llseek,
.read= do_sync_read,
.aio_read= pipe_read,
.write= bad_pipe_w,
.poll= pipe_poll,
.unlocked_ioctl= pipe_ioctl,
.open= pipe_read_open,
.release= pipe_read_release,
.fasync= pipe_read_fasync,
};

const struct file_operations write_pipefifo_fops = {
.llseek= no_llseek,
.read= bad_pipe_r,
.write= do_sync_write,
.aio_write= pipe_write,
.poll= pipe_poll,
.unlocked_ioctl= pipe_ioctl,
.open= pipe_write_open,
.release= pipe_write_release,
.fasync= pipe_write_fasync,
};

const struct file_operations rdwr_pipefifo_fops = {
.llseek= no_llseek,
.read= do_sync_read,
.aio_read= pipe_read,
.write= do_sync_write,
.aio_write= pipe_write,
.poll= pipe_poll,
.unlocked_ioctl= pipe_ioctl,
.open= pipe_rdwr_open,
.release= pipe_rdwr_release,
.fasync= pipe_rdwr_fasync,
}; 
尽管代表着管道两端的两个已打开文件一个只能读,一个只能写。但是,另一方面,这两个逻辑上已打开的文件指向同一个inode,即用作管道的缓冲区,显然,这个缓冲区既支持读也支持写。这进一步说明了file inodedentry之间的不同和联系。





阅读(1143) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~