pnfs执行truncate失败的BUG解析

news/2024/7/7 21:03:12

 

Bug 名称

Truncate操作失败

Bug 描述

使用fstest工具,先执行create再执行truncate后,服务器会返回EIO,而不是期望的0,过一段时间之后,重复执行truncate则成功。

这是导致truncate测试用例所有失败的唯一原因。具体测试脚本在fstest/tests/truncate目录下。

Bug 重现过程

1.       在客户端挂载目录下,使用fstest创建一个文件

命令:./fstest create aaa 0644

2.       执行truncate操作

命令:./fstest truncate aaa 1234567

3.       会显示EIO

出现bug的系统日志

客户端日志:

服务器端日志:

 

Bug 分析

现象分析    

根据操作不成功的返回值EIO,很难分析出具体原因,因为EIO是经过err_map操作之后的映射值,具体错误的返回值需要在log中定位。

log分析

1.       根据客户端和服务器的错误返回值10038,得出对应的宏定义是ERR_OPENMODE;

2.       通过在服务器端日志的3903行(见上图)分析,定位出错的具体代码函数。

3.       通过步骤1和步骤2,结合阅读代码,得出结论:在函数nfs4_preprocess_stateid_op中,走如下流程:

经过判断,当前stateid是存在 对应的delegation的,然后进入check_delemode()函数,该函数代码如下:

在2295行,经过打printk,断定dp->dl_type的值为NFS4_OPEN_DELEAGATE_READ。

4.       经过阅读PNFS协议,发现在setattr()操作之前进行的open()操作,服务器会尝试授予delegation.

5.       阅读服务器端open()操作代码,发现调用nfs4_open_delegation(current_fh, open, stp)后,入口参数open,中含有op_share_access变量,经过打印输入,其值为NFS4_SHARE_ACCESS_READ。在随后进行的分配delegation操作中,会把分配给它的delegation设置为NFS4_SHARE_ACCESS_READ。当客户端下次持有这个delegation来执行setattr操作时,由于设置了修改size的标志位,导致delegation的类型判断失败,操作失败。

6.       若在shell中执行touch命令创建文件,然后在执行truncate系统调用,则不会出现同样错误,是因为touch触发的系统调用是:open("cc", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666);而测试脚本中的创建命令是open(STR(0), O_CREAT | O_EXCL, NUM(1));两者相比,创建时候的标志位设置不同,导致服务器接收到的open操作,入口参数的op_share_access不同,从而测试脚本的命令可以获得读权限的delegation,而touch命令则无法获取delegation。

7.       对于使用测试脚本创建文件,过一段时间后在执行truncate操作可以成功。

是由于客户端会每60秒执行nfs4_renew_state(struct work_struct *work)操作,此操作会检查是否存在“unreferenced”的delegation,若有则将其释放。

而truncate操作之后,会执行文件的close操作,删除对应dentry,使得open操作得到的delegation变成“unreferenced”,在nfs4_renew_state()操作中被删除。也就是说,文件被创建之后,只要客户端执行了nfs4_renew_state操作,再执行truncate操作,就可以成功。

8.由于nfs4_renew_state()操作是定期执行的,而truncate操作是随机发生的,导致之前的第一次操作失败后,间隔“不确定的时间”,再次成功。

Bug定位

执行修改文件大小的操作时候,客户端持有的delegation类型为NFS4_SHARE_ACCESS_READ。

解决方案

在客户端发送setattr()请求之前,检查修改size的标志位是否设置,若设置,则释放delegation。

在函数nfs_setattr()中,添加如下代码:

 

验证

验证通过。

代码以及文档的提交路径

 

 

 



http://www.niftyadmin.cn/n/3060760.html

相关文章

nilsimsa的大概算法

1. 有一个5个字节的window,沿着文本向右滑动,每次滑动一个字节2. 每一个window里面的5个字节,分别可以N个组成3元组。 例如igram,可以分为:igr iga igm iga igm gra grm gam ram3. 每一个三元组通过一个hash函数,算出来…

do_generic_file_read()函数

这个函数完成了文件读的主要流程 核心在于操作页高速缓存,如缺页,失效,预读等操作。 函数中goto语句不计其数, static void do_generic_file_read(struct file *filp, loff_t *ppos, read_descriptor_t *desc, read_a…

ECLIPSE、INTELLIJ IDEA格式化统一ECLIPSE CODE FORMATTER

Eclipse、Intellij idea格式化结果不一样,导致长时间都是用两个开发工具,idea开发eclipse进行格式化。但是现在这个问题可以解决了。使用Eclipse Code Formatter。 具体的插件地址:http://plugins.jetbrains.com/plugin/6546?pridea&off…

文件读写流程

在《linux内核虚拟文件系统浅析》这篇文章中,我们看到文件是如何被打开、文件的读写是如何被触发的。 对一个已打开的文件fd进行read/write系统调用时,内核中该文件所对应的file结构的f_op->read/f_op->write被调用。 本文将顺着这条路走下去&…

网站无法显示logo?

那是因为你没有配置favicon.ico,每个网站根目录都会有一个favicon.ico,因为每个服务器都会请求根目录下的它。

改变图片尺寸

// 改变图片尺寸 -(UIImage *)thumbnailWithImageWithoutScale:(UIImage *)image size:(CGSize)asize{UIImage *newimage;if (nil image) {newimage nil;}else{CGSize oldsize image.size;CGRect rect;if (asize.width/asize.height > oldsize.width/oldsize.height) {re…

Git建立远程/本地服务器和git命令的使用

Github 远程仓库 1、github.com 注册账户 2、在github上创建仓库 3、生成本地ssh key [rootlocalhost ~]# ssh-keygen -t rsa -C maiya163.com # 邮箱要与github上注册的相同 [rootlocalhost ~]# cat .ssh/id_rsa.pub ssh-rsaAAAAB3NzaC1yc2EAAAADAQABAAABAQDVThfq4brrlsPGtAkn…

磁盘格式化、磁盘挂载以及手动增加swap空间

磁盘格式化cat /etc/filesystems:查看centos7操作系统所支持的文件系统类型。centos7默认的文件系统类型为xfs。早期版本使用的是ext文件系统,6使用的是ext4,5使用的是ext3,依此类推。可以使用mount命令来查看分区的挂载情况以及文…