rsize和wsize决定了网络文件系统(NFS)一次网络交互所能够读写的数据块的大小,rsize和wsize的大小对网络文件系统(NFS)的性能有重要影响。rsize和wsize的大小是在用户配置的基础上客户端和服务器端共同协商的结果。

本文面向NFS的开发者和维护者,主要介绍rsize和wsize在客户端和服务器之间协商的流程,同时介绍rsize和wsize的设置的方法。文章以V3的实现为主线,顺便提及V4,代码基于Linux-pnfs-2.6.32。

(1)      用户挂载

用户在挂载NFS文件系统的时候,可以用挂载选项指定rsize和wsize的大小,如下:

mount -t nfs -o vers=3,xxxx,rsize=????,wsize=????

Linux mount 命令将由系统调用下发到内核的vfs层,由vfs_kern_mount执行挂载操作。Vfs_kern_mount将调用具体文件系统的get_sb方法创建并初始化super block。对于NFS文件系统来说,这个方法便是Nfs_get_sb/Nfs4_get_sb,这两个函数定义在nfs模块代码的super.c文件当中。

(2)      Nfs_get_sb/nfs4_get_sb

这里主要介绍nfs_get_sb,nfs4_get_sb可以以此为参照。Nfs_get_sb的部分函数代码如下:

2142 static int nfs_get_sb(structfile_system_type *fs_type,

2143         int flags, const char *dev_name, void*raw_data, struct vfsmount *mnt)

2144 {//其中raw_data包含了用户挂载时的挂载参数

2145         struct nfs_server *server = NULL;

2146         struct super_block *s;

2147         struct nfs_parsed_mount_data *data;//内核挂载参数

2148         struct nfs_fh *mntfh;

2149         struct dentry *mntroot;

2150         int (*compare_super)(structsuper_block *, void *) = nfs_compare_super;

2151         struct nfs_sb_mountdata sb_mntdata = {

2152                 .mntflags = flags,

2153         };

2154         int error = -ENOMEM;

2155

2156         data = nfs_alloc_parsed_mount_data(3);//分配并且初始化内核挂载参数,此时data中的rsize和wsize分别被初始化为NFS_MAX_FILE_IO_SIZE(4U * 1048576U = 4MB);

2157         mntfh = kzalloc(sizeof(*mntfh),GFP_KERNEL);

2158         if (data == NULL || mntfh == NULL)

2159                 goto out_free_fh;

2160

2161        security_init_mnt_opts(&data->lsm_opts);

2162

2163         /* Validate the mount data */

2164         error = nfs_validate_mount_data(raw_data,data, mntfh, dev_name);//利用raw_data和dev_name设置内核挂载参数,这时data当中rsize和wsize被设置为用户挂载时指定的大小。

2165         if (error < 0)

2166                 goto out;

2167

2168 #ifdef CONFIG_NFS_V4

2169         if (data->version == 4) {

2170                 error = nfs4_try_mount(flags,dev_name, data, mnt);

2171                kfree(data->client_address);

2172                 goto out;

2173         }

2174 #endif  /* CONFIG_NFS_V4 */

2175

2176         /* Get a volume representation */

2177         server = nfs_create_server(data,mntfh);//创建server,server中保存了和服务器交互的参数,在这个函数中客户端将和服务器协商rsize和wsize的大小。

2178         if (IS_ERR(server)) {

2179                 error = PTR_ERR(server);

2180                 goto out;

2181    }

}

(3)      客户端协商过程

在nfs_create_server/nfs4_create_server中,首先会调用nfs_init_server对server进行初始化,其中会利用用户设置的data中的rsize和wsize对server中的rsize和wsize进行赋值;然后会调用nfs_probe_fsinfo过程,nfs_probe_fsinfo过程会通过远程过程调用获取服务器所允许的读写粒度的相关信息,最终决定系统所允许的rsize和wsize的大小。nfs_probe_fsinfo函数的部分代码如下:

927 static int nfs_probe_fsinfo(struct nfs_server*server, struct nfs_fh *mntfh, struct nfs_fattr *fatt     r)

928 {

929         struct nfs_fsinfo fsinfo;

930         struct nfs_client *clp = server->nfs_client;

931         int error;

932

933         dprintk("-->nfs_probe_fsinfo()\n");

934

935         if(clp->rpc_ops->set_capabilities != NULL) {

936                 error =clp->rpc_ops->set_capabilities(server, mntfh);

937                 if (error < 0)

938                         goto out_error;

939         }

940

941         fsinfo.fattr = fattr;

942         nfs_fattr_init(fattr);

943         error =clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);//通过远程过程调用获取服务器导出文件系统信息,其中包括所允许的读写粒度的相关信息。

944         if (error < 0)

945                 goto out_error;

946

947         nfs_server_set_fsinfo(server,&fsinfo);//协商决定最终的rsize和wsize

}

其中nfs_server_set_fsinfo函数的部分代码如下:

869 staticvoid nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo*fsinfo)

870 {

871        unsigned long max_rpc_payload;

872

873        /* Work out a lot of parameters */

874        if (server->rsize == 0)//如果用户没有对rsize进行设置

875                 server->rsize =nfs_block_size(fsinfo->rtpref, NULL);//rtpref->(perfer.优先)读操作的传输粒度

876        if (server->wsize == 0) 如果用户没有对wsize进行设置

877                 server->wsize =nfs_block_size(fsinfo->wtpref, NULL);//wtpref->(perfer.优先)写操作的传输粒度

878

879        if (fsinfo->rtmax >= 512 && server->rsize >fsinfo->rtmax)//rtmax->最大读操作的传输粒度

880                 server->rsize =nfs_block_size(fsinfo->rtmax, NULL);

881        if (fsinfo->wtmax >= 512 && server->wsize >fsinfo->wtmax) //wtmax->最大读操作的传输粒度

882                server->wsize =nfs_block_size(fsinfo->wtmax, NULL);

883

884        max_rpc_payload = nfs_block_size(rpc_max_payload(server->client),NULL); //Rpc_max_payload 对于传输协议tcp和udp来说不一样。1、对于tcp来说rpc_max_payload就是一个分片大小,#define RPC_MAX_FRAGMENT_SIZE ((1U << 31) -1);2、对于udp来说rpc_max_payload是一个IP包减去IP、UDP、RPC头之后的大小,(1U <<16) - (MAX_HEADER << 3)。

885        if (server->rsize > max_rpc_payload)

886                 server->rsize =max_rpc_payload;

887        if (server->rsize > NFS_MAX_FILE_IO_SIZE)// NFS_MAX_FILE_IO_SIZE(4U * 1048576U = 4MB)

888                 server->rsize =NFS_MAX_FILE_IO_SIZE;

889        server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >>PAGE_CACHE_SHIFT;

890

891        server->backing_dev_info.name = "nfs";

892        server->backing_dev_info.ra_pages = server->rpages *NFS_MAX_READAHEAD;

893

894        if (server->wsize > max_rpc_payload)

895                 server->wsize =max_rpc_payload;

896        if (server->wsize > NFS_MAX_FILE_IO_SIZE)

897                 server->wsize =NFS_MAX_FILE_IO_SIZE;

}

(4)      服务器传递的参数

这里不过多阐述远程过程调用的问题,仅关注对于远程过程调用fsinfo,服务器给客户端传输了什么参数。首先看v3服务器端的处理函数nfsd3_proc_fsinfo。

545 nfsd3_proc_fsinfo(struct svc_rqst *rqstp, struct nfsd_fhandle    *argp,

546                                           struct nfsd3_fsinfores *resp)

547 {

548         __be32 nfserr;

549         u32    max_blocksize = svc_max_payload(rqstp);

550

551         dprintk("nfsd: FSINFO(3)   %s\n",

552                                SVCFH_fmt(&argp->fh));

553

554         resp->f_rtmax  = max_blocksize;

555         resp->f_rtpref = max_blocksize;

556         resp->f_rtmult = PAGE_SIZE;

557         resp->f_wtmax  = max_blocksize;

558         resp->f_wtpref = max_blocksize;

559         resp->f_wtmult = PAGE_SIZE;

560         resp->f_dtpref = PAGE_SIZE;

}

V4的代码中fsinfo通过getattr实现,通过服务器端的编码函数nfsd4_encode_fattr来看一下服务器给客户端传回了什么参数。

2146 __be32

2147 nfsd4_encode_fattr(struct svc_fh*fhp, struct svc_export *exp,

2148                 struct dentry *dentry, __be32*buffer, int *countp, u32 *bmval,

2149                 struct svc_rqst *rqstp, intignore_crossmnt)

{

2516         if (bmval0 & FATTR4_WORD0_MAXREAD){

2517                 if ((buflen -= 8) < 0)

2518                         goto out_resource;

2519                 WRITE64((u64)svc_max_payload(rqstp));//客户端解码出来的数值,将决定了客户端rtpref和rtmax的值,详细参见解码函数

2520         }

2521         if (bmval0 &FATTR4_WORD0_MAXWRITE) {

2522                 if ((buflen -= 8) < 0)

2523                         goto out_resource;

2524                 WRITE64((u64)svc_max_payload(rqstp)); //客户端解码出来的数值,将决定了客户端rtpref和rtmax的值,详细参见解码函数

}

既然参见了解码函数,那么把客户端解码函数相关部分代码也贴一贴吧。

Decode_fsinfo{

4366         fsinfo->rtmult = fsinfo->wtmult= 512;  /* ??? */

4367

4368         if ((status = decode_attr_lease_time(xdr,bitmap, &fsinfo->lease_time)) != 0)

4369                 goto xdr_error;

4370         if ((status =decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0)

4371                 goto xdr_error;

4372        if ((status =decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0)

4373                 goto xdr_error;

4374         fsinfo->rtpref = fsinfo->dtpref =fsinfo->rtmax;

4375         if ((status =decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)

4376                 goto xdr_error;

4377         fsinfo->wtpref = fsinfo->wtmax;

}

综上可以看出服务器端rtperf、rtmax、wtperf、wtmax,都是由函数svc_max_payload决定的,函数代码如下:

1299 u32 svc_max_payload(const structsvc_rqst *rqstp)

1300 {// xcl_max_payload 和sv_max_payload的较小者决定了函数的返回值,其中sv_max_payload是rpc服务所允许的最大传输粒度,也就是nfsd服务所允许的最大粒度。

1301         u32 max =rqstp->rq_xprt->xpt_class->xcl_max_payload;

1302

1303         if(rqstp->rq_server->sv_max_payload < max)

1304                 max =rqstp->rq_server->sv_max_payload;

1305         return max;

1306 }

1307EXPORT_SYMBOL_GPL(svc_max_payload);

其中xcl_max_payload在tcp和udp当中的定义如下。

1212 static struct svc_xprt_classsvc_tcp_class = {

1213         .xcl_name = "tcp",

1214         .xcl_owner = THIS_MODULE,

1215         .xcl_ops = &svc_tcp_ops,

1216         .xcl_max_payload =RPCSVC_MAXPAYLOAD_TCP,//(1 *1024 *1024U) =1M

1217 };

685 static struct svc_xprt_classsvc_udp_class = {

686        .xcl_name = "udp",

687        .xcl_owner = THIS_MODULE,

688        .xcl_ops = &svc_udp_ops,

689        .xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP,// (32*1024u) =32k

690 };

(5)  Nfsd服务所允许的最大传输粒度

Nfsd模块加载之后,用户就可以通过proc虚拟文件系统接口对nfsd服务所允许的最大传输粒度进行设置了,命令为echo xxxx > /proc/fs/nfsd/max_block_size ,这个虚拟接口在nfsd模块中影响到服务启动时的一个参数nfsd_max_blksize,这个参数最终会影响到Nfsd服务所允许的最大传输粒度。

Nfsd服务启动函数的相关部分代码如下:

Nfsd_create_serv {

321         if (nfsd_max_blksize == 0) {//如果用户没有通过proc接口设置这个参数

322                 /* choose a suitable default*/

323                 struct sysinfo i;

324                 si_meminfo(&i);

325                 /* Aim for 1/4096 of memoryper thread

326                  * This gives 1MB on 4Gigmachines

327                  * But only uses 32K on 128Mmachines.

328                  * Bottom out at 8K on 32M andsmaller.

329                  * Of course, this is only adefault.

330                  */

331                 nfsd_max_blksize =NFSSVC_MAXBLKSIZE;// (1*1024*1024u) =1M

332                 i.totalram <<=PAGE_SHIFT - 12;//i.totalram是系统总共的内存大小,所以如果用户不加以设置,服务器系统的内存的大小也会影响到rsize/wsize

333                 while (nfsd_max_blksize >i.totalram &&

334                        nfsd_max_blksize >=8*1024*2)//最小是8k哦

335                         nfsd_max_blksize /= 2;

336         }

337

338         nfsd_serv =svc_create_pooled(&nfsd_program, nfsd_max_blksize,

339                                      nfsd_last_thread, nfsd, THIS_MODULE); //nfsd_max_blksize作为参数传给了服务创建函数

}

435 struct svc_serv *

436 svc_create_pooled(struct svc_program*prog, unsigned int bufsize,

437                  void (*shutdown)(structsvc_serv *serv),

438                   svc_thread_fn func, structmodule *mod)

439 {//nfsd_max_blksize 被传递给了bufsize

440        struct svc_serv *serv;

441        unsigned int npools = svc_pool_map_get();

442

443        serv = __svc_create(prog, bufsize,npools, shutdown);

444

445        if (serv != NULL) {

446                 serv->sv_function = func;

447                 serv->sv_module = mod;

448        }

449

450        return serv;

451 }

360 static struct svc_serv *

361 __svc_create(struct svc_program *prog,unsigned int bufsize, int npools,

362              void (*shutdown)(struct svc_serv*serv))

363 {

364        struct svc_serv *serv;

365        unsigned int vers;

366        unsigned int xdrsize;

367        unsigned int i;

368

369        if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))

370                 return NULL;

371        serv->sv_name      =prog->pg_name;

372        serv->sv_program   = prog;

373        serv->sv_nrthreads = 1;

374        serv->sv_stats     =prog->pg_stats;

375        if (bufsize > RPCSVC_MAXPAYLOAD)

376                 bufsize = RPCSVC_MAXPAYLOAD;

377        serv->sv_max_payload =bufsize? bufsize : 4096;

378        serv->sv_max_mesg  = roundup(serv->sv_max_payload +PAGE_SIZE, PAGE_SIZE);

379        serv->sv_shutdown  = shutdown;

380        xdrsize = 0;

}

流程介绍结束,最后总结一下,rsize/wsize是由用户、系统网络状况、内存共同决定的,是不是呢?

转载于:https://www.cnblogs.com/wajika/p/6424204.html

NFS客户端、服务器协商读写粒度(rsize、wsize)流程 【转】相关推荐

  1. linux nfs 读写性能,linux – NFS客户端具有不平衡的读写速度

    我有一台NetApp作为我的nfs服务器,两台 Linux服务器作为nfs客户端.问题是,两台服务器中较新的服务器在同时对nfs服务器进行读写操作时,读写速度会有很大差异.另外,读取和写入对于这个新服 ...

  2. nfs服务器随机读写性能,NFS服务详细分析

    1. NFS服务介绍 1.1什么是NFS服务 NFS(Network File System)即网络文件系统,它允许网络中的计算机之间通过TCP/IP网络共享资源.在NFS的应用中,本地NFS的客户端 ...

  3. linux 安装nfs 客户端,在CentOS 7上安装NFS服务器和客户端

    NFS服务器和客户端安装在CentOS 7上 版本1.0 作者:Srijan Kishore 在Twitter上关注howtoing 最后编辑 16 / Dec / 2014 本指南介绍如何在Cent ...

  4. 服务器所属文件变成nobody,NFS(expirtfs命令,NFS客户端创建新文件所属组和所属主都为nobody)(示例代码)...

    一.exportfs命令 nfs进程不能随便从新启动,如果不得已要重启,必须把客户端的挂载目录卸载,然后在从新启动. 这时候就可以用exportfs命令 -a             全部挂载或者全部 ...

  5. 服务器简历共享文件,通过 NFS 实现服务器目录共享

    项目需求 在一些项目开发中,往往有这种需求,就是项目的一些静态资源都是直接存放在项目服务外的目录中.比如 APP 程序包的上传和下载,一般后台服务上传包,服务直接把包上传到当前系统资源目录,但多个上传 ...

  6. filezilla 共享多个目录_Linux下搭建NFS文件共享服务器

    NFS配置文件权限参数说明 (/etc/exports) 1.rw:表示可读写权限. 2.ro:表示只读权限. 3.sync:请求或写入数据时,数据同步写入到NFS Server的硬盘后才返回.(优点 ...

  7. Ubuntu16.04搭建ftp/tftp/nfs/ssh服务器

    目前的方向是嵌入式方向,和板子打交道时必备的.这时候就需要烧写各种镜像.经常使用tftp和nfs服务,最近对ssh服务比较好奇,后续会继续补充. 目录 目录 FTP服务 FTP服务介绍 FTP服务器 ...

  8. Linux 下搭建NFS网络服务器 Win7 下访问挂载

    1. Ubuntu 安装 NFS 服务. apt-get install nfs-kernel-server 2. 修改 NFS 配置文件 #vi /etc/exports 在最后一行添加: /srv ...

  9. 华为服务器网卡激活配置文件,客户端服务器网络配置文件

    客户端服务器网络配置文件 内容精选 换一换 在进行应用开发时,要准备的开发和运行环境如表1所示.进行应用开发时,需要同时准备代码的运行调测的环境,用于验证应用程序运行正常.如果使用Linux环境调测程 ...

最新文章

  1. 真不知写什么了,也就是很久没有做什么了
  2. App in Scala
  3. python带通配符的字符串匹配_Bash技巧:实例介绍数个参数扩展表达式以处理字符串变量...
  4. /deep/使用方式方式;/deep/无效; ::v-deep和>>>使用;
  5. 蛋疼的strtok函数
  6. 深度神经网络面临的挑战与解决方案
  7. Spring Cloud:服务消费(Ribbon)【Dalston版】
  8. 01-Axure9入门培训
  9. 软件设计师考试感想随笔
  10. 微信api接口调用-微信群管理
  11. VMware中安装win7虚拟机后共享问题的解决
  12. android webview下载附件几种方法
  13. 电脑没有声音,显示“未插入耳机或扬声器”,检测不到Realtek高清晰音频管理器...
  14. git push :unable to write sha1 filename ./bojects/xxxx:权限不够
  15. 【linux内核分析与应用-陈莉君】设备驱动概述
  16. 服务器经常被攻击怎么办
  17. 关于微信开放平台授权事件接收Url的配置以及参数接收
  18. 删除的备忘录怎么恢复
  19. 让微信 8.0 「裂开」「炸弹」的特效代码来了
  20. HTC手机傻瓜式安装Google Play服务

热门文章

  1. Boost:使用find_if()算法来检测两个向量交叉的点
  2. DCMTK:生成一个C ++标头,为DICOM标签定义符号名
  3. VTK:Utilities之ArrayWriter
  4. VTK:Qt之BorderWidgetQt
  5. VTK:图片之ImageStack
  6. OpenCV使用模板与遮罩匹配的实例(附完整代码)
  7. Qt Creator连接QNX设备
  8. C语言实现最大堆max_heap(附完整源码)
  9. C++结构与联合有和区别?
  10. 22 Python IO、打印到屏幕、读取键盘输入、打开和关闭文件、文件定位、重命名和删除文件、Python里的目录、文件,目录相关的方法