当前位置: 首页 > news >正文

有没有一种网站做拍卖厂的/章鱼磁力链接引擎

有没有一种网站做拍卖厂的,章鱼磁力链接引擎,公司网络平台搭建,html网页模板网站模板下载1. 概述 今天本来打算写一篇关于linux内核sys_mount()代码分析的文章,习惯性地打开google,看看是否有别人写的比较好,可以参考参考,打开第一篇发现居然是自己以前写的博客,真是囧,而且也记录在CSDN上&#…

1. 概述

今天本来打算写一篇关于linux内核sys_mount()代码分析的文章,习惯性地打开google,看看是否有别人写的比较好,可以参考参考,打开第一篇发现居然是自己以前写的博客,真是囧,而且也记录在CSDN上,本想直接行使拿来主义,但看了下内容,发觉略有不妥,于是在那篇博客的基础上进行些修改和润色。
Linux下任何块设备在使用之前,首先要对其进行格式化成特定文件系统,如mkfs.ext3等,然后再将其挂载到系统中特定目录下,于是通过该挂载点即可访问该块设备文件系统下的所有文件和目录等。如 mount -t ext3 -o option /device/hda  /home/mountdir便将设备/dev/hda挂载到了/home/mountdir下,我们今天的重点就是钻研kernel在该命令下到底做了些什么。参考的内核版本是linux2.6.36,本人博客如无作特别说明,内核的版本都是2.6.36。

2. 实现

2.1 相关数据结构

相关数据结构留到我们代码分析完成以后再写。

2.2 sys_mount()流程分析

      内核mount函数的入口为sys_mount(),你需要在fs/namespace.c的SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, char __user *, type, unsigned long, flags, void __user *, data)才能找到其实现,其源代码如下:
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,char __user *, type, unsigned long, flags, void __user *, data)
{int ret;char *kernel_type;char *kernel_dir;char *kernel_dev;unsigned long data_page;/* 以下几个函数将用户态参数拷贝至内核态,包括:** 1. kernel_type:挂载文件系统类型,如ext3** 2. kernel_dir:   挂载点路径** 3. dev_name:  设备名称** 4. data_pages: 选项信息*/ret = copy_mount_string(type, &kernel_type);if (ret < 0)goto out_type;kernel_dir = getname(dir_name);if (IS_ERR(kernel_dir)) {ret = PTR_ERR(kernel_dir);goto out_dir;}ret = copy_mount_string(dev_name, &kernel_dev);if (ret < 0)goto out_dev;ret = copy_mount_options(data, &data_page);if (ret < 0)goto out_data;/*  调用do_mount 完成主要挂载工作 */ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags,(void *) data_page);free_page(data_page);
out_data:kfree(kernel_dev);
out_dev:putname(kernel_dir);
out_dir:kfree(kernel_type);
out_type:return ret;
}

        总体上来说,该函数还算比较简单,主要就作了两件事:

1. 将用户态的参数拷贝至内核态,因为在后面需要使用这些参数(为什么需要,难道内核态不能直接使用用户态的数据吗?);
2.  调用do_mount()接手接下来的挂载工作。
/* 参数:  
** dev_name :   挂载设备名称
** dir_name :   挂载点名称
** type_page:   保存挂载的文件系统类型,如"ext3"
** flags    :   挂载标志
** data_page:   大部分情况下为NULL
*/
long do_mount(char *dev_name, char *dir_name, char *type_page,unsigned long flags, void *data_page)
{struct path path;int retval = 0;int mnt_flags = 0;/* Discard magic */if ((flags & MS_MGC_MSK) == MS_MGC_VAL)flags &= ~MS_MGC_MSK;/* Basic sanity checks */if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))return -EINVAL;if (data_page)((char *)data_page)[PAGE_SIZE - 1] = 0;/* 调用kern_path(),根据挂载点名称查找其dentry等信息** 参数:@dir_name     : 挂载点路径**     :@LOOKUP_FOLLOW: 查找标志,遇到链接继续查找**     :@path         : 查找结果保存与此结构中*/retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);if (retval)return retval;/* 安全相关,忽略*/retval = security_sb_mount(dev_name, &path,type_page, flags, data_page);if (retval)goto dput_out;/*  对于挂载标志的检查和初始化,忽略 *//* Default to relatime unless overriden */if (!(flags & MS_NOATIME))mnt_flags |= MNT_RELATIME;/* Separate the per-mountpoint flags */if (flags & MS_NOSUID)mnt_flags |= MNT_NOSUID;if (flags & MS_NODEV)mnt_flags |= MNT_NODEV;if (flags & MS_NOEXEC)mnt_flags |= MNT_NOEXEC;if (flags & MS_NOATIME)mnt_flags |= MNT_NOATIME;if (flags & MS_NODIRATIME)mnt_flags |= MNT_NODIRATIME;if (flags & MS_STRICTATIME)mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);if (flags & MS_RDONLY)mnt_flags |= MNT_READONLY;flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |MS_STRICTATIME);/* 我们不关心别的,只关注do_new_mount */if (flags & MS_REMOUNT)retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,data_page);else if (flags & MS_BIND)retval = do_loopback(&path, dev_name, flags & MS_REC);else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))retval = do_change_type(&path, flags);else if (flags & MS_MOVE)retval = do_move_mount(&path, dev_name);elseretval = do_new_mount(&path, type_page, flags, mnt_flags,dev_name, data_page);
dput_out:path_put(&path);return retval;
}

        在do_mount()函数中,作了一些标志位的检查,安全性检查等附加工作,然后根据不同的flag来调用不同的挂载函数,我们这里主要关注普通块设备的挂载,其他的以后遇到再分析吧,这这里面调用了下面两个主要的函数:

1. kern_path():该函数的主要作用是根据挂载点的路径名在内核中查找其内存目录项结构(struct dentry),保存在path中;
2. do_new_mount(),该函数接手来完成接下来的挂载工作。
/* 参数:
** @path: 保存挂载点信息,包括dentry结构等
** @type: 挂载文件系统类型,如ext3
** @flags & mnt_flags:挂载标志
** @name:设备名称
** @data: 保存额外的数据,一般是NULL
*/
static int do_new_mount(struct path *path, char *type, int flags,int mnt_flags, char *name, void *data)
{struct vfsmount *mnt;if (!type)return -EINVAL;/* we need capabilities... *//* 必须是root权限*/if (!capable(CAP_SYS_ADMIN))return -EPERM;lock_kernel();/* 调用do_kern_mount()来完成挂载第一步,主要是创建一个vfsmount结构并对其初始化** 并读设备的superblock并初始化文件系统在内存中的结构等*/mnt = do_kern_mount(type, flags, name, data);unlock_kernel();if (IS_ERR(mnt))return PTR_ERR(mnt);/* 将上面创建的vfsmount结构添加到全局结构中** 形成目录树结构*/return do_add_mount(mnt, path, mnt_flags, NULL);
}
do_new_mount()主要调用两个函数,进行具体挂载:
1. do_kern_mount():该函数主要是为新的文件系统准备一个挂载结构vfsmount,初始化,并从设备上读出超级块等信息,在内存中构建文件系统的轮廓,会在后面具体描述这一过程;
2. do_add_mount():将1中创建的vfsmount结构添加到全局结构中,以便在内存中形成一棵树结构。
让我们对这两个函数一一击破吧,先从do_kern_mount,主要的挂载工作在该函数中完成。
/* 参数: fstype: 文件系统名称,如"ext3"
**       flags : 挂载标志
**       name  : 设备名称,如"/dev/sda"
**       data  : 其他挂载数据,暂时忽略
*/
struct vfsmount *
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{/* 首先根据文件系统名称获取文件系统结构file_system_type** 内核中所有支持的文件系统的该结构通过链表保存*/struct file_system_type *type = get_fs_type(fstype);struct vfsmount *mnt;if (!type)return ERR_PTR(-ENODEV);/* 调用vfs_kern_mount()完成主要挂载*/mnt = vfs_kern_mount(type, flags, name, data);if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&!mnt->mnt_sb->s_subtype)mnt = fs_set_subtype(mnt, fstype);put_filesystem(type);return mnt;
}

该函数主要流程是:1. 调用get_fs_type()通过文件系统名查找到文件系统的struct file_system_type结构;2.通过vfs_kern_mount()来进行主要的挂载。

/* 主要挂载工作
** 参数: type : 文件系统内存结构
**     : flags: 挂载标志
**     : name : 设备名称
**     : data : 额外挂载参数,忽略
*/
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;//首先,分配一个代表挂载结构的struct vfs_mount结构mnt = alloc_vfsmnt(name);if (!mnt)goto out;if (flags & MS_KERNMOUNT)mnt->mnt_flags = MNT_INTERNAL;if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {secdata = alloc_secdata();if (!secdata)goto out_mnt;error = security_sb_copy_data(data, secdata);if (error)goto out_free_secdata;}//调用具体文件系统的get_sb方法//从name代表的设备上读出超级块信息error = type->get_sb(type, flags, name, data, mnt);if (error < 0)goto out_free_secdata;BUG_ON(!mnt->mnt_sb);WARN_ON(!mnt->mnt_sb->s_bdi);mnt->mnt_sb->s_flags |= MS_BORN;//与安全相关,暂时忽略error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);if (error)goto out_sb;/** filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE* but s_maxbytes was an unsigned long long for many releases. Throw* this warning for a little while to try and catch filesystems that* violate this rule. This warning should be either removed or* converted to a BUG() in 2.6.34.*/WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to ""negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes);//设置挂载点的dentry结构为刚读出的设备的根目录mnt->mnt_mountpoint = mnt->mnt_root;mnt->mnt_parent = mnt;up_write(&mnt->mnt_sb->s_umount);free_secdata(secdata);return mnt;
out_sb:dput(mnt->mnt_root);deactivate_locked_super(mnt->mnt_sb);
out_free_secdata:free_secdata(secdata);
out_mnt:free_vfsmnt(mnt);
out:return ERR_PTR(error);
}

        我们追踪到这里对于第一个部分的函数调用do_kern_mount()就已经基本结束,在这个相当底层的函数中,它主要调用了具体文件系统的get_sb()方法来从设备上读出超级块,这个我们会在具体文件系统剖析的时候去作深入地分析。其实就是读出超级块,作有效性检查,内存构造根目录项等工作。
        至此,我们第一部分的主要工作就完成了,在该部分的核心工作就是创建一个struct vfsmount,并读出文件系统超级块来初始化该结构。接下来就是将该结构添加到全局结构中,这就是do_add_mount()的主要工作。

int do_add_mount(struct vfsmount *newmnt, struct path *path,int mnt_flags, struct list_head *fslist)
{int err;mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);//这里为什么需要对namespace_sem加锁呢down_write(&namespace_sem);/* Something was mounted here while we slept *///如果在获取信号量的过程中别人已经进行了//挂载,那么我们进入已挂载文件系统的根目录//如此继续while (d_mountpoint(path->dentry) &&follow_down(path));err = -EINVAL;if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))goto unlock;/* Refuse the same filesystem on the same mount point *///重复挂载,毫无意义err = -EBUSY;if (path->mnt->mnt_sb == newmnt->mnt_sb &&path->mnt->mnt_root == path->dentry)goto unlock;err = -EINVAL;if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))goto unlock;newmnt->mnt_flags = mnt_flags;//主要调用graft_tree()来实现文件系统目录树结构//其中newmnt是本次创建的vfsmount结构//path是挂载点信息if ((err = graft_tree(newmnt, path)))goto unlock;if (fslist) /* add to the specified expiration list */list_add_tail(&newmnt->mnt_expire, fslist);up_write(&namespace_sem);return 0;unlock:up_write(&namespace_sem);mntput(newmnt);return err;
}

do_add_mount()主要调用了函数graft_tree()来实现linux文件系统的目录树结构。

/*参数:  mnt: 本次挂载新建的vfsmount结构
**           : path: 挂载点的结构
*/
static int graft_tree(struct vfsmount *mnt, struct path *path)
{int err;if (mnt->mnt_sb->s_flags & MS_NOUSER)return -EINVAL;if (S_ISDIR(path->dentry->d_inode->i_mode) !=S_ISDIR(mnt->mnt_root->d_inode->i_mode))return -ENOTDIR;err = -ENOENT;mutex_lock(&path->dentry->d_inode->i_mutex);if (cant_mount(path->dentry))goto out_unlock;if (!d_unlinked(path->dentry))err = attach_recursive_mnt(mnt, path, NULL);
out_unlock:mutex_unlock(&path->dentry->d_inode->i_mutex);return err;
}

该函数的处理也是首先检查挂载的有效性(如挂载点是否是目录)等,而真正的核心函数是attach_recursive_mnt()。

static int attach_recursive_mnt(struct vfsmount *source_mnt,struct path *path, struct path *parent_path)
{LIST_HEAD(tree_list);struct vfsmount *dest_mnt = path->mnt;struct dentry *dest_dentry = path->dentry;struct vfsmount *child, *p;int err;//这个与sharemount相关,暂时忽略if (IS_MNT_SHARED(dest_mnt)) {err = invent_group_ids(source_mnt, true);if (err)goto out;}err = propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list);if (err)goto out_cleanup_ids;br_write_lock(vfsmount_lock);if (IS_MNT_SHARED(dest_mnt)) {for (p = source_mnt; p; p = next_mnt(p, source_mnt))set_mnt_shared(p);}//因为传入的parent_path是NULL,所以我们//对else分支比较感兴趣if (parent_path) {detach_mnt(source_mnt, parent_path);attach_mnt(source_mnt, path);touch_mnt_namespace(parent_path->mnt->mnt_ns);} else {//这里主要是将新建的source_mnt与挂载点(dest_dentry) 挂钩//并和挂载点所在的dest_mnt建立起父子关系mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);//该函数也比较简单,不深入了commit_tree(source_mnt);}//这个是干嘛呢list_for_each_entry_safe(child, p, &tree_list, mnt_hash) {list_del_init(&child->mnt_hash);commit_tree(child);}br_write_unlock(vfsmount_lock);return 0;out_cleanup_ids:if (IS_MNT_SHARED(dest_mnt))cleanup_group_ids(source_mnt, NULL);out:return err;
}

        该函数中很多的代码可能与sharemount机制相关,关于该机制我会在另外一篇博客中专门阐述,这里就忽略了,因为参数parent_path主要为NULL,所以我们比较关注的代码分支是else,即mnt_set_mountpoint和commit_tree,其实两个函数干的事情都比较简单,主要是将当前新建的vfsmount结构与挂载点挂钩,并和挂载点所在的vfsmount形成一种父子关系结构。形成的结构图如下所示:

至此,整个的mount过程的代码分析也就差不多了,虽然个中还有不少的细节问题需要再深入地研究。最后,让我们归纳下整个的调用流程:
sys_mount()
|
----------->do_mount()
|
------------->do_new_mount()
|
----------->do_kern_mount()
|                            |
|                             -------->vfs_kern_mount()
|
------------->do_add_mount()
|
----------->graft_tree()
|
-------->attach_recursive_mnt()

转自:http://www.xuebuyuan.com/1470725.html
http://www.jmfq.cn/news/4802509.html

相关文章:

  • 做淘宝客要有网站吗/seo快速排名点击
  • 微山做网站/网站优化排名哪家性价比高
  • 山东中迅网站建设/seo程序专员
  • 东圃那里有做网站设计的/厦门seo网络优化公司
  • 苏州婚庆公司网站建设案例/百度一下你就知道了 官网
  • 陕西建设厅执业注册中心网站/代运营公司排行榜
  • 企业局域网站建设/百度竞价点击价格
  • 网站建设 指标/中国突然宣布一重磅消息
  • 北京网站建设手机app电子商务/青岛网络工程优化
  • wordpress如何增加page样式/seo搜索引擎优化实训报告
  • 乌兰浩特网站开发/百度搜索关键词排行榜
  • 公司网站设计案例/软文世界平台
  • 网站建设 域名 数据库/互联网销售
  • 修复WordPress图片上传错误/seo推广编辑
  • 成都高端网站制作/网站广告调词软件
  • 珠海九洲旅游开发公司/天津关键词优化网站
  • 网站开发用什么语言最好/四川餐饮培训学校排名
  • 广州营销型网站建设哪家好/seo网站整站优化
  • 番禺做网站的/怎么推广网页
  • 12306网站开发多少钱/常德网站建设制作
  • 在猪八戒网站如何做兼职/吉林网站seo
  • 想制作自己的网站/seo优化顾问服务
  • 上海新闻网最新新闻事件/河南seo推广
  • 诸暨网站建设公司/手机seo关键词优化
  • 热卖平台网站怎么做/青岛网站快速排名提升
  • 手机网站制作天强科技/网络广告营销方案策划
  • 建立一个网站的英文/百度竞价网站
  • 中卫网站定制开发设计/网站系统开发
  • 在线做ppt的网站有哪些问题/南宁网站制作
  • 南宁建站系统模板/竞价培训班