2020-06-01 20:01:21

by Jakob Unterwurzacher

[permalink] [raw]
Subject: cifs vs Go: EINTR and ENOENT errors from getdents64

Hi, author of gocryptfs here, an encrypted overlay
filesystem written in Go.

A gocryptfs user reported [1] hitting EINTR errors
when gocryptfs is used on a cifs mount.

I wrote a minimal reproducer, getdents.go [2], that runs
getdents64 in a loop and I can reproduce the issue easily.
I additionally see ENOENT errors.

The errors can also be seen via the high-level Readdirnames()
function that the Go stdlib provides [6].

I am running kernel 5.6.13 and Samba 4.12.2 for this test.
I have a cifs share mounted as shown in [3], populated
with 1001 empty files using

touch $(seq 1000 2000)

. When running getdents.go [2] against this mount, good cases look
like this (output from getdents.go):

--- example 0 ---

unix.Getdents: n=4176; n=4176; n=4176; n=4176; n=4176; n=3192; n=0; err=<nil>; total 24072 bytes
unix.Getdents: n=4176; n=4176; n=4176; n=4176; n=24; n=4152; n=3192; n=0; err=<nil>; total 24072 bytes


INTR errors look like this (getdents.go output and corresponding
kernel debug messages that were enabled acc. to [4]):

--- example 1 ---

unix.Getdents: n=-1; err=interrupted system call; total 0 bytes

[168340.499471] fs/cifs/file.c: CIFS VFS: leaving cifs_closedir (xid = 24238) rc = 0
[168340.599686] fs/cifs/readdir.c: Full path: start at: 0
[168340.599696] fs/cifs/transport.c: signal is pending before sending any data
[168340.599698] smb2_add_credits: 310 callbacks suppressed
[168340.599699] fs/cifs/smb2ops.c: add 1 credits total=8192
[168340.599701] fs/cifs/smb2ops.c: query_dir_first: open failed rc=-4
[168340.599702] fs/cifs/readdir.c: initiate cifs search rc -4
[168340.599979] fs/cifs/file.c: Closedir inode = 0x0000000067f9a79c
[168340.599981] fs/cifs/file.c: CIFS VFS: in cifs_closedir as Xid: 24240 with uid: 1026
[168340.599982] fs/cifs/file.c: Freeing private data in close dir
[168340.599983] fs/cifs/file.c: CIFS VFS: leaving cifs_closedir (xid = 24240) rc = 0

--- example 2 ---

unix.Getdents: n=-1; err=interrupted system call; total 0 bytes

[168453.792894] Status code returned 0x80000006 STATUS_NO_MORE_FILES
[168453.893360] fs/cifs/transport.c: signal is pending before sending any data
[168453.893363] fs/cifs/smb2ops.c: query_dir_first: open failed rc=-4


ENOENT errors look like this:

--- example 3 ---

unix.Getdents: n=4176; n=4176; n=4176; n=4176; n=4176; n=-1; err=no such file or directory; total 20880 bytes

[168517.187072] Status code returned 0x80000006 STATUS_NO_MORE_FILES
[168517.300252] fs/cifs/transport.c: signal is pending before sending any data
[168517.300255] fs/cifs/readdir.c: fce error -2

--- example 4 ---

unix.Getdents: n=4176; n=4176; n=4176; n=1440; n=2736; n=-1; err=no such file or directory; total 16704 bytes

[168650.603145] Status code returned 0x80000006 STATUS_NO_MORE_FILES
[168650.713831] fs/cifs/transport.c: signal is pending before sending any data
[168650.713835] fs/cifs/readdir.c: fce error -2


I have the same thing written in C does not show
any problems [5].

The Go runtime uses signals heavily, could this be a
reason for the behavoir I am seeing? I can trigger
the problem more quickly when I resize the terminal
window (causing SIGWINCH). Note that the Go runtime
sets SA_RESTART on all signal handlers.

I can handle the EINTR errors by retrying, no problem.
Should I also retry when I get ENOENT?

Thanks,
Jakob


[1] https://github.com/rfjakob/gocryptfs/issues/483
[2] https://github.com/rfjakob/gocryptfs/blob/master/contrib/getdents-debug/getdents/getdents.go
[3] //127.0.0.1/samba-test on /mnt/samba-test type cifs
(rw,relatime,vers=3.1.1,cache=strict,username=jakob,uid=1026,forceuid,gid=1026,forcegid,addr=127.0.0.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mappos
ix,rsize=4194304,wsize=4194304,bsize=1048576,echo_interval=60,actimeo=1,user=jakob)
[4] https://wiki.samba.org/index.php/LinuxCIFS_troubleshooting#Enabling_Debugging
[5] https://github.com/rfjakob/gocryptfs/blob/master/contrib/getdents-debug/getdents_c/getdents.c
[6] https://github.com/golang/go/issues/39237