Bug 1044438

Summary: cifs: Unable to append to an existing file in cache=none mode.
Product: Red Hat Enterprise Linux 6 Reporter: Sachin Prabhu <sprabhu>
Component: kernelAssignee: Sachin Prabhu <sprabhu>
kernel sub component: CIFS QA Contact: Chao Ye <cye>
Status: CLOSED ERRATA Docs Contact:
Severity: medium    
Priority: unspecified CC: b.bellec, ccui, cye, eguan, jradhakr, rwheeler, steved
Version: 6.6   
Target Milestone: rc   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: kernel-2.6.32-465.el6 Doc Type: Bug Fix
Doc Text:
Cause: Incorrect calculation of offset in cifs_iovec_write() Consequence: This bug results in incorrect offsets being calculated for file appends writes in cache modes strict and none. Fix: Backport of upstream commit 3af9d8f227a31e25b3110ef175d105798fc147a6 which fixes this issue. Result: Append writes should work correctly.
Story Points: ---
Clone Of: Environment:
Last Closed: 2014-10-14 05:44:55 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1172231, 1268411    
Attachments:
Description Flags
Proposed patch none

Description Sachin Prabhu 2013-12-18 10:25:56 UTC
A friend pointed out a report on an online forum about the inability to append to a file in RHEL 6.5 in cache=none and cache=strict mode.
https://linuxfr.org/forums/linux-redhat/posts/bug-de-redirection-shell-sur-cifs-apres-upgrade-vers-centos-6-5

To reproduce:
1) Mount using cache=strict or cache=none mode. (Default is cache=loose)
2) create a new file t2, append a line to it and finally read it.
# echo 1 > /mnt/t2; echo 2 >>/mnt/t2; cat /mnt/t2

Expected:
1
2

instead we see a single line:
2

Comment 1 Sachin Prabhu 2013-12-18 10:27:29 UTC
In the summar above, I've made a mistake mentioning cache=strict mode. On testing, cache=strict mode seems to work fine. The problem only seems to affect cache=none mode.

Sachin Prabhu

Comment 2 Sachin Prabhu 2013-12-18 11:07:46 UTC
The bug is in the offset calculation in cifs_iovec_write() which means it affects both cache=strict and cache=none as in the original report in the forum.

This bug is already fixed upstream
3af9d8f227a31e25b3110ef175d105798fc147a6
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=3af9d8f227a31e25b3110ef175d105798fc147a6

I will backport this patch and also try and get it released as an async errata.

Sachin Prabhu

Comment 3 Benjamin Bellec 2013-12-18 11:19:30 UTC
Thank you for working on this, I'm the reporter on this bug on the french forum (thanks to your friend to pointed this to you).

Anyway, I also get different result if write on a NetApp CIFS share (SMB1 I guess) or on Win 7 CIFS share (SMB2/3 I guess). But may be both cases are solved by the patch you provide.
Here is my test (sorry if it's not really readable):

==========================================================
==========================================================

CIFS on Windows 7 SP1 (x86-64)
command executed on kernel 2.6.32-431.1.2.0.1.el6.x86_64 (CentOS 6.5)

[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=none //win7/transfert /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=loose //win7/transfert /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino //win7/transfert /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=strict //win7/transfert /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]#

==========================================================
==========================================================

CIFS on Windows 7 SP1 (x86-64)
command executed on kernel 2.6.32-358.23.2.el6.x86_64 (CentOS 6.4)

[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=none //win7/transfert /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=loose //win7/transfert /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino //win7/transfert /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=strict //win7/transfert /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]#


==========================================================
==========================================================

CIFS on NetApp FAS2040 (8.0.2P1)
command executed on kernel 2.6.32-431.1.2.0.1.el6.x86_64 (CentOS 6.5)

[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=none //netapp/vol_cifs$ /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=loose //netapp/vol_cifs$ /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino //netapp/vol_cifs$ /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=strict //netapp/vol_cifs$ /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
happy_birthday
[root@localhost ~]#


==========================================================
==========================================================

CIFS on NetApp FAS2040 (8.0.2P1)
command executed on kernel 2.6.32-358.23.2.el6.x86_64 (CentOS 6.4)

[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=none //netapp/vol_cifs$ /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=loose //netapp/vol_cifs$ /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino //netapp/vol_cifs$ /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]# mount -t cifs -o rw,username=myuser,password=mypwd,nosuid,nodev,noserverino,cache=strict //netapp/vol_cifs$ /mnt/transfert/ && sleep 2 && echo good_morning >> /mnt/transfert/cifs.log && sleep 2 && sync && echo happy_birthday >> /mnt/transfert/cifs.log && sync && cat /mnt/transfert/cifs.log && rm -f /mnt/transfert/cifs.log && umount /mnt/transfert/
good_morning
happy_birthday
[root@localhost ~]#

Comment 4 Benjamin Bellec 2013-12-18 11:29:29 UTC
In fact, to sum up:
- win7 share : cache strict works, cache none doesn't
- netapp share : cache strict doesn't works, cache none doesn't too

Comment 5 Sachin Prabhu 2013-12-18 11:31:45 UTC
Hello Benjamin,

Thanks for the bug report. 

The issue affects both cache=none and cache=strict. However it affects cache=strict mode only in cases where it doesn't hold the exclusive oplock. 

The exclusive oplock is provided by the server when the file is opened and tells the client that it has exclusive access to the file. In such an event, it is allowed to cache writes in the pagecache to the file and flushes these changes back only when the server requests the oplock back from the client or if the client closes the file.
In case it doesn't hold the oplock, the client is expected to write the file data back to the server in which cases it uses cifs_iovec_write() which contains the bug.

So it depends on whether the server has provided you an oplock or not for you to hit the bug. Different servers have different behaviours when it comes to granting clients oplocks for files.

I have a patch ready which fixes this issue and I shall upload it shortly after testing locally.

Sachin Prabhu

PS: The cifs module in RHEL 6.5 only supports SMB1. For SMB2/SMB3, you should use RHEL 7(which is in beta at the moment).

Comment 6 Benjamin Bellec 2013-12-18 11:39:43 UTC
Thank you for the clarification and the patch backport.

Comment 7 Sachin Prabhu 2013-12-18 11:41:47 UTC
Created attachment 838276 [details]
Proposed patch

[RHEL6 PATCH] [bz1044438] cifs: fix offset handling in cifs_iovec_write

A recent backport to the cifs module  for RHEL 6.5 introduced a
function cifs_iovec_write() which is used by cache=none and
cache=strict modes. This function contained a bug which incorrectly
calculated the offsets resulting in an inability to do append
writes in these cache modes. This was fixed upstream but unfortunately
the fix wasn't backported together with the patches which introduced
those cache modes to RHEL 6.5.

The default cache mode in RHEL 6.5 is cache=loose which shouldn't be
affected by this issue.

Upstream commit: 3af9d8f227a31e25b3110ef175d105798fc147a6
--
In the recent update of the cifs_iovec_write code to use async writes,
the handling of the file position was broken. That patch added a local
"offset" variable to handle the offset, and then only updated the
original "*poffset" before exiting.

Unfortunately, it copied off the original offset from the beginning,
instead of doing so after generic_write_checks had been called. Fix
this by moving the initialization of "offset" after that in the
function.

Signed-off-by: Jeff Layton <jlayton>
Signed-off-by: Steve French <sfrench.com>
(cherry picked from commit 3af9d8f227a31e25b3110ef175d105798fc147a6)
--

Signed-off-by: Sachin Prabhu <sprabhu>

Comment 9 RHEL Program Management 2014-03-26 00:14:23 UTC
This request was evaluated by Red Hat Product Management for
inclusion in a Red Hat Enterprise Linux release.  Product
Management has requested further review of this request by
Red Hat Engineering, for potential inclusion in a Red Hat
Enterprise Linux release for currently deployed products.
This request is not yet committed for inclusion in a release.

Comment 10 Rafael Aquini 2014-05-14 12:34:10 UTC
Patch(es) available on kernel-2.6.32-465.el6

Comment 13 Chao Ye 2014-07-03 08:14:27 UTC
Reproduced on 431.el6:
=====================================================
[root@hp-dl388g8-18 ~]# mount.cifs //hp-dl388g8-15.rhts.eng.nay.redhat.com/cifs /mnt/testarea/client -o cache=none
Password: 
[root@hp-dl388g8-18 ~]# echo 1 > /mnt/testarea/client/1
[root@hp-dl388g8-18 ~]# echo 2 >> /mnt/testarea/client/1
[root@hp-dl388g8-18 ~]# cat /mnt/testarea/client/1
2
[root@hp-dl388g8-18 ~]# uname -a
Linux hp-dl388g8-18.rhts.eng.nay.redhat.com 2.6.32-431.el6.x86_64 #1 SMP Sun Nov 10 22:19:54 EST 2013 x86_64 x86_64 x86_64 GNU/Linux
[root@hp-dl388g8-18 ~]# cat /proc/mounts | grep cifs
//hp-dl388g8-15.rhts.eng.nay.redhat.com/cifs/ /mnt/testarea/client cifs rw,relatime,sec=ntlm,cache=none,unc=\\hp-dl388g8-15.rhts.eng.nay.redhat.com\cifs,username=root,uid=0,noforceuid,gid=0,noforcegid,addr=10.66.86.185,unix,posixpaths,serverino,acl,rsize=1048576,wsize=65536,actimeo=1 0 0

Verified on 488.el6:
=====================================================
[root@ibm-hs21-01 ~]# mount.cifs //ibm-x3550m4-02.rhts.eng.nay.redhat.com/cifs /mnt/testarea/client -o cache=none
Password: 
[root@ibm-hs21-01 ~]# echo 1 > /mnt/testarea/client/1
[root@ibm-hs21-01 ~]# echo 2 >> /mnt/testarea/client/1
[root@ibm-hs21-01 ~]# cat /mnt/testarea/client/1
1
2
[root@ibm-hs21-01 ~]# uname -a
Linux ibm-hs21-01.rhts.eng.nay.redhat.com 2.6.32-488.el6.x86_64 #1 SMP Wed Jun 25 21:13:56 EDT 2014 x86_64 x86_64 x86_64 GNU/Linux
[root@ibm-hs21-01 ~]# cat /proc/mounts | grep cifs
//ibm-x3550m4-02.rhts.eng.nay.redhat.com/cifs/ /mnt/testarea/client cifs rw,relatime,sec=ntlm,cache=none,unc=\134\134ibm-x3550m4-02.rhts.eng.nay.redhat.com\134cifs,username=root,uid=0,noforceuid,gid=0,noforcegid,addr=10.66.87.55,unix,posixpaths,serverino,acl,rsize=1048576,wsize=65536,actimeo=1 0 0

Move to VERIFIED.

Comment 14 errata-xmlrpc 2014-10-14 05:44:55 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

http://rhn.redhat.com/errata/RHSA-2014-1392.html

Comment 15 Dave Wysochanski 2016-06-24 18:02:41 UTC
*** Bug 1268292 has been marked as a duplicate of this bug. ***