从文件系统看系统架构

晨曦之光 发布于 2012/04/10 15:06
阅读 143
收藏 1

linux实现了vfs,几乎任何一个可以交换数据的存在(我这里用一个很大的词:存在)都可以有一个vfs的代理,内存中就是一个inode结构,如果 你要操作它,那么需要一个file结构,而file结构拥有file_operations结构,该结构内存放有很多函数指针,指向一些具体的操作,这些操作将来都要和inode打交道,内核给用户一个统一的系统调用接口,然后这个系统调用的实现用来在file_operations里分发操作,这个系统 调用实际上就是一个多路复用的设施,这就是linux的vfs的全部了。
但是像没想过扩展,比如一个分层的驱动,这在linux下是完全可以实现的,实际上没有linux实现不了的,前面说过,linux都是小对象的组合,耦 合性低,扩展性炒好,很容易就可以组合成你需要的样子,比如usb驱动,块设备驱动,包括网络协议栈都是分层的驱动,但是这些东西给人的感觉很松散,(linux本身就是很松散,这才是linux,使他的杀手锏)我从来不敢奢望从网络协议栈驱动来学习怎么写一个块设备过滤器驱动,网络协议栈上可以用成熟的netfilter框架,这个框架是自成体系的,但是块设备呢?我无语...
还是不说的罢,windows的我就不说了,看看《天数夜读》吧,很详细。说说bsd吧(当然我可以说,看看源码吧,都在眼前...想不开了,寻短见了,看看这个世界吧,多美好...真是那样世界就完蛋了)
bsd提供了一个从用户接口到最底层的通用直通式通道,和linux一样,系统调用接口下面也是一个多路复用器,将请求分发到管道,套接字,文件...不同的是,bsd将各个驱动之间的关系处理得相当好,它让这些模块间联系更加紧密但是不增加耦合性,也就是说,这个通道我方那儿了,谁都可以用,只要遵守约定,这个和windows有点像,应该说windows和unix有点像才对,linux则相反,一切自己动手丰衣足食,linux简直就是高手们的玩 具,菜鸟的地狱!还是代码里见吧,搞程序只会说文解字,没用。

struct vop_vector {

  struct vop_vector *vop_default;                 //定义一个缺省的操作结构,注意类型也是vop_vector

  int (*vop_bypass)(struct vop_generic_args *ap);

  int (*vop_open)(struct vop_open_args);

  int (*vop_access)(struct vop_access_args);

  int (*vop_read)(struct vop_read_args);

  ...

};

struct vop_generic_args {     //bsd将参数也给封装了,这个是参数的“基类”

  struct vnodeop_desc *a_desc;

  ...

};

struct vnodeop_desc {         //操作描述结构

  char *vdesc_name;

  int  vdesc_flags;

  vop_bypass_t   *vdesc_call;   //bypass中具体要调用的函数

  ...

};

struct vnodeop_desc vop_read_desc {

  "vop_read",

  0,

  (vop_bypass_t *)VOP_READ_AP,//往下传递了吧,竟然调用的也是VOP_READ_AP

  ...

};

static __inline int VOP_READ(struct vnode *vp, struct uio *uio, int ioflag, struct uccred *cred)

{

   struct vop_read_args a;

   a.a_gen.a_desc = &vop_read_desc;

   a.a_vp = vp;

   a.a_uio = uio;

   a.a_ioflag = ioflag;

   a.a_cred = cred;

   return (VOP_READ_APV(vp->v_op,&a));

}

Int VOP_READ_APV(vop_vector *vop, struct vop_read_args *a)

{

   ...//如果找不到就调用default里面的例程

   while(vop != NULL && vop->vop_read == NULL && vop->vop_bypass == NULL)

       vop = vop->vop_default;

   if(vop->vop_read != NULL)

       rc = vop->vop_read(a);

   else

       rc = vop->vop_bypass(&a->a_gen);//调用bypass,给了程序存放钩子的地点

   ...

}

以 上代码一目了然,不用多说什么,一个系统调用发出以后,路经是:pread->preadv->dofileread->fo_ops->fo_read->vn_read->VOP_READ->VOP_READ_APV->vop->vop_read->nfs->read
其中dofileread,fo_ops->fo_read,vop_read是常用的几个多路复用的地点,实际上,有了参数封装,指针通信机制,任何地方都是多路复用点。bsd实现了这套机制真是方便了开发驱动的人。
很早以前听有人说c语言实现不了面向对象,看看linux和unix的代码吧,之后再重新审视面向对象的意义何在。从文件系统的实现里面我们可以看出,bsd为何要这么做,这是基于当时历史背景考虑的,因为在当时很多文件系统都不成熟,彼此的依赖性很大,所以很显然要彼此调用来完成自己没有实现的功能,但是linux就不一样了,时机成熟了。再者linux根本没有一个统一的规划,因此才会出现那种很“野”的局面,但是这些松散的小对象却奇迹般的超 越了一切。看来linux没有必要学习bsd或windows的那一套,也不可能学会,那必须要很多人经过正规的过程讨论,最后开始在统一管理下进行设计,开发,而linux没有那种环境,因此,linux就是linux,bsd就是bsd,windows就是windows,学了别人它就不纯了,所以 评价一款操作系统的好坏不要一味的从一方面比如用户习惯啊等等去谈,而应该考虑到它自身的一切东西。
最好就是不要评价,要从比较当中学习各家的长处,而不要一味指责这个或那个。
注:我刚买了一本《代码之美》,感觉特棒,看了好几章,上文就是一篇读后感吧。


原文链接:http://blog.csdn.net/dog250/article/details/5302780
加载中
返回顶部
顶部