您的位置:首页 > 其它

大话存储系列15——NFS 和 CIFS 文件系统

2013-03-20 19:18 513 查看
1、NFS 文件系统

本文整理自:http://www.ibm.com/developerworks/cn/linux/l-cn-nfs/index.html?ca=drs-

Sun公司估计现在大约有超过310万个系统在运行NFS,大到大型计算机、小至PC机,其中至少有80%的系统是非Sun平台。NFS是由SUN公司发展, 并於1984年推出, NFS是一个RPC service ,它使我们能够达到档案的共享, 它的设计是为了在不同的系统间使用, 所以它的通讯协定设计与主机及作业系统无关.当使用者想用远端档案时只要用"mount"就可把remote档案系统挂接在自己的档案系统之下,使得远端的档案使用上和local机器的档案没两样。


 NFS 对于在同一网络上的多个用户间共享目录很有用途。譬如,一组致力于同一工程项目的用户可以通过使用 NFS 文件系统(通常被称作 NFS 共享)中的一个挂载为 /myproject 的共享目录来存取该工程项目的文件。要存取共享的文件,用户进入各自机器上的 /myproject 目录。这种方法既不用输入口令又不用记忆特殊命令,就仿佛该目录位于用户的本地机器上一样。

网络文件系统是FreeBSD支持的文件系统中的一种, 也被称为 NFS。 NFS允许一个系统在网络上与它人共享目录和文件。通过使用NFS,用户和程序可以象访问本地文件一样访问远端系统上的文件。

以下是NFS最显而易见的好处:

1 本地工作站使用更少的磁盘空间,因为通常的数据可以存放在一台机器上而且可以通过网络访问到。

2 用户不必在每个网络上机器里头都有一个home目录。Home目录 可以被放在NFS服务器上并且在网络上处处可用。

3 诸如软驱,CDROM,和 Zip之类的存储设备可以在网络上面被别的机器使用。这可以减少整个网络上的可移动介质设备的数量。

NFS是如何工作

  众所周知的是,NFS 的客户端在访问远端服务器文件系统时,既需要通过服务器获得文件的属性信息(元数据),还需要通过服务器获得文件的数据信息,这使得 NFS 天然地具备将文件的属性信息和数据信息分离在不同服务器上进行访问的特性,于是最后一个版本 NFS4.1/pNFS,将
Lustre/CephFS/GFS 等集群文件系统的设计思想引入到自身中,成为一个具有里程碑意义的 NFS 版本。它使得 NFS 的数据吞吐的速度和规模都得到了极大提高,为 NFS 的应用带了更为广阔的空间。

NFS 之所以备受瞩目,除了它在文件共享领域上的优异表现外,还有一个关键原因在于它在 NAS 存储系统上应用。NAS 与 DAS 和 SAN 在存储领域的竞争中,NFS 发挥了积极的作用,这更使得 NFS 越来越值得关注。
NFS 至少包括两个主要的部分:一台服务器, 以及至少一台客户机, 客户机远程地访问保存在服务器上的数据。要让这一切运转起来, 需要配置并运行几个程序。

服务器必须运行以下服务:

服务 描述 

nfsd NFS,为来自NFS客户端的 请求服务。 

mountd NFS挂载服务,处理nfsd(8)递交过来的请求。 

rpcbind 此服务允许 NFS 客户程序查询正在被 NFS 服务使用的端口。

  客户端同样运行一些进程,比如 nfsiod。 nfsiod处理来自NFS的请求。这是可选的,而且可以提高性能,对于普通和正确的操作来说并不是必须的。 参考nfsiod(8)手册获得更多信息。

按照 NFS
文件系统的设计与实现,NFS 文件系统主要分为三个部分:The Protocol(网络协议),Client Side(NFS 客户端)和 Server Side(NFS 服务器)。

NFS 客户端提供了接口,保证用户或者应用程序能像访问本地文件系统一样访问 NFS 文件系统,NFS 服务器作为数据源,为 NFS 客户端提供真实的文件系统服务,而网络协议则使得 NFS 客户端和 NFS 服务器能够高效和可靠地进行通信。NFS 网络协议使用的是 RPC(Remote
Procedure Call,远程过程调用)/XDR(External Data Representation,外部数据表示)机制,因此本文将剖析的重点放在 NFS 客户端和 NFS 服务器上

Client Side 源代码

Client Side 的头文件在 include/linux/ 下面,C 文件在 fs/nfs 下面。

dir.c/file.c/inode.c/symlink.c/unlink.c:与文件操作相关的系统调用

read.c/write.c/flushd.c:文件读写

mount_clnt.c/nfs_root.c:将 NFS 文件系统作为 root 目录的相关实现

proc.c/nfs2xdr.c/nfs3proc.c/nfs3xdr.c:网络数据交换

与文件操作相关的系统调用都在 struct file_operations,struct inode_operations 这两个数据结构里面定义。文件的读操作 nfs_file_read 和写操作 nfs_file_write 被单独提出来,因为文件读写性能将直接关系到文件系统的成败,本文在后面会重点阐述其实现。

Server Side 源代码

Server Side 的头文件在 include/linux/nfsd 下面,C 文件在 fs/nfsd 下面。

auth.c/lockd.c/export.c/nfsctl.c/nfscache.c/nfsfh.c/stats.c:导出目录的访问管理

nfssvc.c:NFS 服务 deamon 的实现

vfs.c:将 NFS 文件系统的操作转换成具体文件系统的操作

nfsproc.c/nfsxdr.c/nfs3proc.c/nfs3xdr.c:网络数据交换

导出目录的访问管理主要解决网络文件系统实现面临的几个重要问题,包括目录导出服务,外部访问的权限控制,多客户端以及客户端与服务器的文件并发操作等。

一个典型例子:rename 的调用过程

在 NFS 文件系统的文件操作中,除了 read 和 write 操作考虑到性能因素,专门使用了缓存机制外,其它的操作基本上都是同步完成的。本文以 rename 为例来进行说明,如下图所示。首先用户或者应用程序开始调用文件操作,经过系统调用 sys_rename,到达虚拟文件系统层 vfs_rename,然后交给 NFS 文件系统 nfs_rename 来处理。NFS 文件系统无法操作存储介质,它调用 NFS 客户端函数 nfs3_proc_rename
和 NFS 服务器函数 nfsd3_proc_rename 进行通信,把文件操作转发到 NFS 服务器的虚拟文件系统层 vfs_rename,最后调用具体的文件系统如 ext2 的函数 ext2_raname,完成文件重命名。



与传统文件系统相同点

在阐述 NFS 文件系统与传统桌面文件系统的相同点之前,我们首先简要回顾一下 Linux 操作系统上文件系统的体系结构。按照 Linux 文件系统剖析的划分,Linux 文件系统从上至下主要由虚拟文件系统层,特定文件系统层和页高速缓存层三部分组成,如下图所示。当然,这种划分并不是一定的,例如在执行直接
I/O 调用时,是不需要进行页高速缓存的,另外,对于块设备的读写,进行页高速缓存之后还会有通用块层和 I/O 调度层的处理。



用户或者应用程序通过统一的系统调用接口对文件系统进行操作,然后系统调用进入虚拟文件系统层,虚拟文件系统根据文件系统类型,调用特定文件系统的操作函数。对用户和应用程序来说,由于接口完全相同,因此用户感觉不到差异,应用程序也可以无缝地移植到 NFS 文件系统上。

Linux 通过一组对象对文件系统的操作,这组对象是 superblock(超级块对象),inode(索引节点对象),dentry(目录项对象)和 file(文件对象),如下图所示。所有文件系统都支持这些对象,正是因为它们,VFS
层可以对 NFS 和其它文件系统一视同仁,只管调用这些对象的数据和函数指针,把具体的文件系统数据布局和操作都留给特定的文件系统来完成。



NFS 与其它文件系统一样,向内核声明和注册自己的文件系统类型。
static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, FS_ODD_RENAME);
... ...
module_init(init_nfs_fs)
module_exit(exit_nfs_fs)

同样,NFS 也需要根据自己的文件类型设置相应的文件操作函数。如果是正规文件,需要设置 inode 操作函数,file 操作函数,以及 address_space 操作函数;如果是目录文件,需要设置 inode 操作函数,file 操作函数;如果是链接,则只需设置 inode 操作函数。
static void
nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
{
... ...
inode->i_op = &nfs_file_inode_operations;
if (S_ISREG(inode->i_mode)) {
inode->i_fop = &nfs_file_operations;
inode->i_data.a_ops = &nfs_file_aops;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &nfs_dir_inode_operations;
inode->i_fop = &nfs_dir_operations;
} else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
else
init_special_inode(inode, inode->i_mode, fattr->rdev);
... ...
}

与传统文件系统不同点

与内存文件系统,闪存文件系统和磁盘文件系统这些本地文件系统最大的不同在于,NFS 文件系统的数据是基于网络,而不是基于存储设备的,因此 NFS 文件系统在设计自己的 inode 和 superblock 数据结构,以及实现文件操作函数时,无需考虑数据布局情况。同样是因为基于网络,NFS 文件系统的权限控制和并发访问的要求比本地文件系统更高,读写的缓存机制也大大有别于本地文件系统。

superblock 和 inode

清单 1. NFS 的 superblock 定义
struct rpc_clnt * 	 client; 			 /* RPC 客户端句柄 */
struct nfs_rpc_ops * 	 rpc_ops; 		 /* RPC 客户端函数向量表 */
int 			 flags; 			 /* 标识信息 */
unsigned int 		 rsize; 			 /* 每次读请求的最小数据量 */
unsigned int 		 rpages; 			 /* 每次读请求的最小数据量(以页为单位)*/
unsigned int 		 wsize; 			 /* 每次写请求的最小数据量 */
unsigned int 		 wpages; 			 /* 每次写请求的最小数据量(以页为单位)*/
unsigned int 		 dtsize; 			 /* 每次读目录信息的最小数据量 */
unsigned int 		 bsize; 			 /* NFS 服务器端的块大小 */
unsigned int 		 acregmin; 		 /* 正规文件在缓存中驻留的最小允许时间 */
unsigned int 		 acregmax; 		 /* 正规文件在缓存中驻留的最大允许时间 */
unsigned int 		 acdirmin; 		 /* 目录文件在缓存中驻留的最小允许时间 */
unsigned int 		 acdirmax; 		 /* 目录文件在缓存中驻留的最大允许时间 */
unsigned int 		 namelen; 		 /* NFS 服务器端的主机名称最大长度 */
char * 			 hostname; 		 /* NFS 服务器端的主机名称 */
struct nfs_reqlist * 	 rw_requests; 		 /* 异步读写请求队列信息 */

清单 2. NFS 的 inode 定义
__u64 fsid;                       	 /* 根目录(导出目录)信息 */
__u64 fileid;                     	 /* 当前文件信息 */
struct nfs_fh 		 fh; 		 /* 文件句柄 */
... ...
struct list_head 	 read; 		 /* 读数据页队列 */
struct list_head 	 dirty; 		 /* 脏数据页队列 */
struct list_head 	 commit; 		 /* 提交数据页队列 */
struct list_head 	 writeback; 	 /* 写回数据页队列 */
unsigned int 		 nread, 		 /* 读数据页数量 */
ndirty, 		 /* 脏数据页数量 */
ncommit, 	 /* 提交数据页数量 */
npages; 		 /* 写回数据页数量 */
... ...

以上省略了 superblock 和 inode 定义的公共部分,列出的仅是 NFS 文件系统 superblock 和 inode 定义的私有部分,因为只有这些私有定义才能体现出文件系统的设计原则。从这些定义可以看出,私有部分数据结构里面主要包含网络连接和读写请求两个方面相关的信息。superblock 里 client 定义了 RPC 协议的客户端连接状态,rpc_ops 定义了 RPC 协议的客户端入口函数,如 nfs3_proc_read,nfs3_proc_write,nfs3_proc_create
等。inode 里 fh 是 NFS 客户端和 NFS 服务器相互传递的关键参数,4 个页队列用于进行读写缓存,随后两小节将分别予以介绍。

file handle

file handle(fh 或者 fhandle)在 NFS 客户端和 NFS 服务器之间相互传递,建立 NFS 客户端的 inode 和 NFS 服务器的 inode 的关联关系。它主要表征的是 NFS 服务器上 inode 和物理设备的信息。file handle 对于 NFS 客户端来说是透明的,NFS 客户端不需要知道它的具体内容。file handle 在 NFS 客户端的定义是 66 个字节,前两个字节组成一个无符号 short
型,表示 file handle 的大小,后 64 个字节组成数据区,存储 file handle 的内容。
#define NFS_MAXFHSIZE 		 64
struct nfs_fh {
unsigned short 		 size;
unsigned char 		 data[NFS_MAXFHSIZE];
};

file handle 在 NFS 服务器的定义由 knfsd_fh 数据结构表示,fh_size 表示 file handle 的大小,数据区 fh_base 是一个联合体,有 fh_old,fh_pad,fh_new 三种定义,最大也是 64 个字节。考虑到当前的 NFS 版本是 v3,只看 fh_new 的定义。fh_version 表示 fh_new 定义的版本,当前版本是 1。fh_auth_type 表示认证方式,0 表示不认证。fh_fsid_type 表示根目录(即导出目录)的信息存储方式,如果是
0,那么从 fh_auth 开始前 2 个字节表示根目录所在设备的 major 号,后 2 个字节表示根目录所在设备的 minor 号,随后的 4 个字节表示根目录的 inode 索引号。fh_fileid_type 表示当前文件的信息存储方式,如果是 1,那么在表示完 fh_fsid 后,紧接着 4 个字节表示当前文件的 inode 索引号,之后 4 个字节表示当前文件的 inode generation 号。
struct nfs_fhbase_new {
__u8 		 fb_version; 	 /* == 1, even => nfs_fhbase_old */
__u8 		 fb_auth_type;
__u8 		 fb_fsid_type;
__u8 		 fb_fileid_type;
__u32 		 fb_auth[1];
};

read 和 write

前面介绍文件系统体系结构的时候,将它分为了虚拟文件系统,特定文件系统和页高速缓存三个层次。NFS 文件系统使用了这三个层次的功能,它本身完成了特定文件系统的功能,同时既为虚拟文件系统提供了完整的调用接口,也用到了页高速缓存来提高读写性能。就层次划分而言,与传统桌面文件系统相比,NFS 文件系统的读写操作不再需要通用块层和 I/O 调度层,而是使用了多个列表以及相关操作来进一步缓存数据,增强读写效率。当然 NFS 文件系统也不再使用存储设备驱动,而是通过网络协议来获取和提交数据。

图 4. 读写缓存机制



2、CIFS (Common Internet File System)

通用Internet文件系统

在windows主机之间进行网络文件共享是通过使用微软公司自己的CIFS服务实现的。 

CIFS 是一个新提出的协议,它使程序可以访问远程Internet计算机上的文件并要求此计算机的服务。CIFS 使用客户/服务器模式。客户程序请求远在服务器上的服务器程序为它提供服务。服务器获得请求并返回响应。CIFS是公共的或开放的SMB协议版本,并由Microsoft使用。SMB协议现在是局域网上用于服务器文件访问和打印的协议。象SMB协议一样,CIFS在高层运行,而不象TCP/IP协议那样运行在底层。CIFS可以看做是应用程序协议如文件传输协议和超文本传输协议的一个实现。

CIFS 可以使您达到以下功能:

1.访问服务器本地文件并读写这些文件

2.与其它用户一起共享一些文件块

3.在断线时自动恢复与网络的连接

4.使用统一码(Unicode)文件名:文件名可以使用任何字符集,而不局限于为英语或西欧语言设计的字符集。

一般来说,CIFS使用户得到比FTP更好的对文件的控制。它提供潜在的更直接地服务器程序接口,这比使用HTTP协议的浏览器更好。CIFS最典型的应用是windows用户能够从“网上邻居”中找到网络中的其他主机并访问其中的共享文件夹.

CIFS 是开放的标准而且已经被作为Internet应用程序标准被提交到IETF。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: