Question regarding CIFS cache=loose behavior.

Jeffrey Layton jlayton at redhat.com
Wed Mar 26 07:03:05 MDT 2014


On Wed, 26 Mar 2014 05:21:19 -0700
Jeffrey Layton <jlayton at redhat.com> wrote:

> On Wed, 26 Mar 2014 21:04:15 +0900
> Tetsuo Handa <penguin-kernel at I-love.SAKURA.ne.jp> wrote:
> 
> > Jeff Layton wrote:
> > > > Yes, I suggested a customer using CIFS on RHEL6 to use
> > > > cache=none or cache=strict , for that customer's system does
> > > > not work as expected due to the latter behavior when using
> > > > "tail -f" for checking for appended log.
> > > 
> > > Yeah, cache=strict should work much better for that sort of
> > > use-case.
> > > 
> > I got another problem where none of cache=none cache=strict
> > actimeo=0 helps.
> > 
> > Since "tail -f" does "repeat calling sleep() and fstat() until the
> > file size increases" -> "do read() until EOF" -> "call fstat()
> > again", "tail -f" prints "file truncated" message and prints some
> > portion of already printed lines even though the file size on the
> > Samba server never decreased. I expect that the latest fstat()
> > returns the up-to-date file size. This behavior is observed on
> > 2.6.32-431.11.2.el6.x86_64 and 3.14-rc8.
> > 
> > Steps to reproduce:
> > 
> > ---------- Start of testprog.c ----------
> > /**
> >  * stdin and stdout must refer a regular file which is shared via
> > CIFS.
> >  * An example is shown below.
> >  *
> >  * # mount -t cifs -o
> > cache=strict,actimeo=0 //127.0.0.1/path/to/export /path/to/mount
> >  * $ cc -Wall -O3 -o a.out this_file.c
> >  * $ ./a.out > /path/to/export/shared_file
> > < /path/to/mount/shared_file */
> > #include <stdio.h>
> > #include <stdlib.h>
> > #include <poll.h>
> > #include <sys/stat.h>
> > #include <unistd.h>
> > 
> > int main(int argc, char *argv[])
> > {
> > 	unsigned int delay = argc > 1 ? atoi(argv[1]) : 0;
> > 	size_t write_pos = 0;
> > 	size_t read_pos = 0;
> > 	if (ftruncate(1, 0))
> > 		return 1;
> > 	while (1) {
> > 		struct stat buf;
> > 		char c;
> > 		if (write(1, ".", 1) != 1)
> > 			return 2;
> > 		write_pos++;
> > 		if (fstat(1, &buf))
> > 			return 3;
> > 		if (buf.st_size != write_pos)
> > 			return 4;
> > 		if (read(0, &c, 1) != 1)
> > 			return 5;
> > 		if (c != '.')
> > 			return 6;
> > 		read_pos++;
> > 		if (delay)
> > 			poll(NULL, 0, delay);
> > 		if (fstat(0, &buf))
> > 			return 7;
> > 		if (buf.st_size < read_pos)
> > 			fprintf(stderr, "read(%lu) - stat(%lu) =
> > %lu\n", read_pos, buf.st_size, read_pos - buf.st_size);
> > 	}
> > }
> > ---------- End of testprog.c ----------
> > 
> > Make a CIFS mount on localhost where the Samba server process is
> > running. Compile testprog.c and run testprog, with stdin redirected
> > to a regular file which is accessed via CIFS and stdout redirected
> > to the same regular file which is accessed as a local filesystem. An
> > example is shown below.
> > 
> >   # mount -t cifs -o cache=none,actimeo=0 //127.0.0.1/home /mnt
> >   $ cc -Wall -O3 -o testprog testprog.c
> >   $ ./testprog > ~/shared_file < /mnt/shared_file
> > 
> > According to what testprog.c does, it is expected that nothing is
> > printed by testprog process because the bytes read via read() equals
> > the bytes obtained via fstat(). However, testprog process prints
> > that the bytes read via read() is larger than the bytes obtained via
> > fstat().
> > 
> > The strace on the smbd process reports that CIFS is omitting lstat()
> > request after pread() request if lstat() request was done very
> > recently. Specifying delay as the command line argument for testprog
> > process reduces the possibility of omitting lstat() request.
> 
> (cc'ing samba-technical)
> 
> ...or that samba is omitting it and is sending cached info instead of
> doing the lstat() call? I'm not sure if it does that, but I don't
> think you should draw too many conclusions about the behavior of
> cifs.ko from stracing smbd.
> 
> What may make more sense is to get network captures and analyze the
> behavior from that perspective.
> 

...or maybe it *is* cifs.ko. From cifs_inode_needs_reval:


        if (!time_in_range(jiffies, cifs_i->time,
                                cifs_i->time + cifs_sb->actimeo))
                return true;


...I think though that if cifs_i->time == jiffies and actimeo=0, then
that condition will be false. As a quick check, it might be good to add
something like this before that if statement and then rerun your test:

	if (!cifs_sb->actimeo)
		return true;

That should get rid of that particular corner case.

-- 
Jeff Layton <jlayton at redhat.com>


More information about the samba-technical mailing list