Fortran OPEN 调用在 NFSv3 和 NFSv4 上有所不同

Posted

技术标签:

【中文标题】Fortran OPEN 调用在 NFSv3 和 NFSv4 上有所不同【英文标题】:Fortran OPEN-call differs on NFSv3 vs NFSv4 【发布时间】:2015-02-24 13:01:55 【问题描述】:

我试图了解为什么您可以在 NFSv3 上以读写模式对您只有读取权限的文件执行 OPEN 调用与在 NFSv4 上执行相同操作之间的区别OPEN 调用将失败。

让我解释一下,下面是一个简单的 fortran 程序,它以读写模式打开给定的文件(程序的参数),

PROGRAM test_open

 IMPLICIT NONE

 ! Parameters

 INTEGER,            PARAMETER :: lunin = 10
 CHARACTER(LEN=100) :: fname

 ! Local

 INTEGER :: i,ierr,siteid,nstation
 REAL :: lat, lon, asl
 CHARACTER(len=15) :: name

 !----------------------------------------------------------------
 !
 ! Open input file
 !

 CALL getarg(1,fname)

 OPEN(lunin,file=fname,STATUS='OLD',iosTAT=ierr)

 IF ( ierr /= 0 ) THEN
    WRITE(6,*)'Could not open ',TRIM(fname),ierr
    STOP
 ENDIF

 WRITE(6,*)'Opened OK'

 CLOSE(lunin)


END PROGRAM test_open

将以上内容保存在test_open.f90中并编译,

gfortran -o fortran test_open.f90 

现在,使用 NFSv3 在挂载点上执行以下操作,

strace -eopen ./fortran file-with-only-read-permissions 

您应该会看到以下几行(以及许多其他输出),

> open("file-with-only-read-permissions", O_RDWR)  = -1 EACCES (Permission denied)
> open("file-with-only-read-permissions", O_RDONLY) = 3

因此,我们可以清楚地看到我们在尝试在“O_RDWR”中打开(打开读写)时收到“EACCES(权限被拒绝)”,但是在我们看到另一个打开的 O_RDONLY 之后(以只读方式打开)并且成功。

在 NFSv4 共享上的文件上运行相同的程序,我们得到以下结果,

strace -eopen ./fortran file-with-only-read-permissions-on-nfsv4-share 
> open("file-with-only-read-permissions-on-nfsv4-share", O_RDWR)  = -1 EPERM (Operation not permitted) 

因此,在尝试以“O_RDWR”(打开读写)打开文件时,我们得到一个“EPERM(不允许操作)”,仅此而已(即应用程序失败)。

使用小型测试程序在 C 中进行相同的测试,在两种情况下都将无法打开文件(也就是说,在获得“EACCES”后,它不会尝试以“只读模式”打开文件“在 NFSv3 上)。

所以问题,

我假设上述行为是由于在 fortran 中实现了 OPEN 调用,并且如果 fortran 在尝试打开文件时收到“EACCES(权限被拒绝)”,它将自动尝试打开只读文件 (O_RDONLY)。这个假设正确吗?

我还假设在尝试打开文件时获得“EPERM(不允许操作)”时,fortran 没有这种“回退方法”。这个假设是正确的,还是我错过了什么?

C 似乎没有在“EACCES”或“EPERM”中实现“回退方法”。这对我来说似乎是正确的,因为这不会留下任何混淆的余地。如果您尝试以您无权执行的方式打开文件,则程序应该失败 - 我的意见。

我知道“权限被拒绝”和“操作不允许”之间有明显的区别。而且我猜想在 kerberos 上安装 NFSv4 时,有理由获得“Permission denied”而不是“Operation not allowed”,但是关于这个领域的一些澄清会很好。

当然,在 open-call (ACTION=READ) 中添加适当的标志可以解决问题。我只是对我的假设以及它们是否正确感到好奇。

【问题讨论】:

【参考方案1】:

回答你的问题,按顺序:

当遇到 EACCES(或 EROFS)时,gfortran 将尝试以只读模式重新打开文件,这是正确的。

EPERM 没有以这种方式处理也是正确的,libgfortran 源代码树中根本没有提到它。

正如您所说,这是一个见仁见智的问题。 Gfortran 很久以前就决定这样做了,它似乎很适合用户。

我不明白为什么 NFS v4 在这种情况下会返回 EPERM。这似乎至少与我可以访问的 open(2) Linux 联机帮助页中的文档不一致,其中仅在指定 O_NOATIME 时才提到它(libgfortran 没有这样做)。至少,这种行为似乎不可移植。

【讨论】:

感谢您彻底的解释。我仍然不得不说,gfortran 的这种行为是有问题的,如果不是,它是不一致的。如果 gfortran 想要这种回退行为,我认为它应该在“所有情况下”回退当打开文件出现问题时” - 我的两分钱 =) 我已经为此问题提交了gcc.gnu.org/bugzilla/show_bug.cgi?id=65203。

以上是关于Fortran OPEN 调用在 NFSv3 和 NFSv4 上有所不同的主要内容,如果未能解决你的问题,请参考以下文章

Python调用Fortran的三种形式

fortran如何在一个module中调用其他module的变量?

在 Fortran90 中从文本文件中跳过一行

如何在fortran中读取和连接文件

FORTRAN里怎样把数值类型(整数,浮点数)转换为字符串

NFSv3 NFSv3针对防火墙端口开通策略 生产环境实践