Bug#483507: mount.cifs: brl option does not produce documented semantics for fcntl(F_SETLK)
On Thu 2008-05-29 01:12:23 -0400, Daniel Kahn Gillmor wrote: Attached is the test program that displays this behavior. It should fail with write lock failed: Permission denied when used on a file on a CIFS mount, and it has succeeded quietly on every other filesystem i've tried. In particular, the test program even succeeds (with the exception of NFSv3) on non-cifs filesystems mounted with the mand option, and with files whose mode was set with chmod g+s,g-x, which i believe is the documented way to turn on mandatory locking [0]. here's it working on a tmpfs mounted with mand: [0 [EMAIL PROTECTED] ~]$ grep mnt /proc/mounts /root/foo /mnt tmpfs rw,mand 0 0 [0 [EMAIL PROTECTED] ~]$ echo -n a /mnt/foo [0 [EMAIL PROTECTED] ~]$ chmod g+s,g-x /mnt/foo [0 [EMAIL PROTECTED] ~]$ ls -la /mnt/foo -rw-r-Sr-- 1 dkg dkg 1 2008-05-29 15:56 /mnt/foo [0 [EMAIL PROTECTED] ~]$ ~/src/cmrg/test/testlocking/testlocking /mnt/foo [0 [EMAIL PROTECTED] ~]$ and here's an ext3 fs mounted with mand: [0 [EMAIL PROTECTED] ~]$ grep mnt /proc/mounts /dev/mapper/squeak0-tester /mnt ext3 rw,mand,data=ordered 0 0 [0 [EMAIL PROTECTED] ~]$ echo -n a /mnt/foo [0 [EMAIL PROTECTED] ~]$ chmod g+s,g-x /mnt/foo [0 [EMAIL PROTECTED] ~]$ ls -la /mnt/foo -rw-r-Sr-- 1 dkg dkg 1 2008-05-29 15:59 /mnt/foo [0 [EMAIL PROTECTED] ~]$ ~/src/cmrg/test/testlocking/testlocking /mnt/foo [0 [EMAIL PROTECTED] ~]$ and vfat (i couldn't set the group setuid bit on vfat, but the test program still worked): [0 [EMAIL PROTECTED] ~]$ grep mnt /proc/mounts /dev/mapper/squeak0-tester /mnt vfat rw,mand,uid=1000,gid=1000,fmask=0033,dmask=0022,codepage=cp437,iocharset=iso8859-1 0 0 [0 [EMAIL PROTECTED] ~]$ echo -n a /mnt/foo [0 [EMAIL PROTECTED] ~]$ chmod g+s,g-x /mnt/foo chmod: changing permissions of `/mnt/foo': Operation not permitted [1 [EMAIL PROTECTED] ~]$ ~/src/cmrg/test/testlocking/testlocking /mnt/foo [0 [EMAIL PROTECTED] ~]$ and xfs with mand: [0 [EMAIL PROTECTED] ~]$ grep mnt /proc/mounts /dev/mapper/squeak0-tester /mnt xfs rw,mand,ikeep,noquota 0 0 [0 [EMAIL PROTECTED] ~]$ echo -n a /mnt/foo [0 [EMAIL PROTECTED] ~]$ chmod g+s,g-x /mnt/foo [0 [EMAIL PROTECTED] ~]$ ls -la /mnt/foo -rw-r-Sr-- 1 dkg dkg 1 2008-05-29 16:07 /mnt/foo [0 [EMAIL PROTECTED] ~]$ ~/src/cmrg/test/testlocking/testlocking /mnt/foo [0 [EMAIL PROTECTED] ~]$ However, on NFSv3 (exported from an up-to-date etch nfs-kernel-server with (rw,subtree_check), and mounted with all kinds of different options (with and without mand), my little test program continually fails *at the read lock* stage if the file is mode g+s,g-x: [0 [EMAIL PROTECTED] ~]$ grep mnt /proc/mounts bob:/srv/dmz /mnt nfs rw,vers=3,rsize=32768,wsize=32768,hard,nointr,proto=tcp,timeo=600,retrans=2,sec=sys,addr=192.168.2.99 0 0 [0 [EMAIL PROTECTED] ~]$ ls -la /mnt/foo -rw-r--r-- 1 dkg dkg 1 2008-05-29 17:04 /mnt/foo [0 [EMAIL PROTECTED] ~]$ ~/src/cmrg/test/testlocking/testlocking /mnt/foo [0 [EMAIL PROTECTED] ~]$ chmod g+x /mnt/foo [0 [EMAIL PROTECTED] ~]$ ~/src/cmrg/test/testlocking/testlocking /mnt/foo [0 [EMAIL PROTECTED] ~]$ chmod g+s /mnt/foo [0 [EMAIL PROTECTED] ~]$ ~/src/cmrg/test/testlocking/testlocking /mnt/foo [0 [EMAIL PROTECTED] ~]$ chmod g-x /mnt/foo [0 [EMAIL PROTECTED] ~]$ ~/src/cmrg/test/testlocking/testlocking /mnt/foo read lock failed: No locks available [1 [EMAIL PROTECTED] ~]$ so, interestingly, the nfs client appears to think that the mode bits alone are sufficient to indicate mandatory (as opposed to advisory) locking, and it apparently knows that NFSv3 is incapable of providing mandatory locks. At any rate, the behavior of cifs with the brl option is clearly divergent from the behavior of the other filesystems. --dkg [0] from fcntl(2): To make use of mandatory locks, mandatory locking must be enabled both on the file system that contains the file to be locked, and on the file itself. Mandatory locking is enabled on a file system using the -o mand option to mount(8), or the MS_MANDLOCK flag for mount(2). Manda- tory locking is enabled on a file by disabling group execute permission on the file and enabling the set-group-ID permission bit (see chmod(1) and chmod(2)). pgpUoci7qyTPA.pgp Description: PGP signature
Bug#483507: mount.cifs: brl option does not produce documented semantics for fcntl(F_SETLK)
Package: smbfs Version: 1:3.0.28a-3 Severity: normal -BEGIN PGP SIGNED MESSAGE- Hash: SHA1 In http://bugs.debian.org/483502, i wrote: locking a certain range of a file with a read lock and then locking the same range with a write lock gives an error when a CIFS share is mounted with brl. This doesn't make much sense to me, but i'm willing to accept it as intended for now. After doing more reading, it still doesn't make sense: the filesystem is behaving with non-POSIX semantics, which causes breakage in other packages (for example, see http://bugs.debian.org/483216). In particular, the semantics specified by fcntl(2) for setting a lock state: A single process can hold only one type of lock on a file region; if a new lock is applied to an already-locked region, then the existing lock is converted to the new lock type. (this appears to be true for both advisory *and* mandatory locks) However, when accessing a CIFS share mounted with with brl (standard CIFS-style server-side byte-range locking), converting a read lock to a write lock gives a permission denied error. The same error does *not* occur when using the CIFS share mounted with nobrl, or when attempting the same series of operations against a tmpfs (whether or not the tmpfs is mounted with -o mand). Shouldn't mount.cifs do its best to mimic the expected semantics of fcntl(F_SETLK) using the underlying CIFS semantics? If CIFS has no explicit lock upgrade/downgrade operations, as long as the protocol is capable of dropping a lock and acquiring a new one, these two primitives used in sequence could be used to emulate a lock upgrade/downgrade. Attached is the test program that displays this behavior. It should fail with write lock failed: Permission denied when used on a file on a CIFS mount, and it has succeeded quietly on every other filesystem i've tried. the latest version of the source can be found at http://cmrg.fifthhorseman.net/browser/trunk/test/testlocking/testlocking.c Thanks for maintaining samba in debian! Regards, --dkg - -- System Information: Debian Release: lenny/sid APT prefers testing APT policy: (500, 'testing'), (200, 'unstable'), (101, 'experimental') Architecture: i386 (i686) Kernel: Linux 2.6.24-1-686 (SMP w/1 CPU core) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/bash Versions of packages smbfs depends on: ii libc62.7-10 GNU C Library: Shared libraries ii netbase 4.32Basic TCP/IP networking system ii samba-common 1:3.0.28a-3 Samba common files used by both th smbfs recommends no packages. - -- no debconf information -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.6 (GNU/Linux) iQIVAwUBSD47NszS7ZTSFznpAQIv4A/+O3ofw/kIzXJuvtertKI2nPqcsiOT27Fl Pf7f1Mp+qhEeVrbZ6ESZA1SSuHBeT7JKYurrsw/z7y2D6nuapqqR6DXihj9QdbIi gZoHZhVH1tCDeuAv9pR8avV8QHXcE8BSu0vZQuaMI/zLbkxln4qbDCtOPvAmowfr vBIKsE9Zb/hYdFCkdYP2lYGXVfTlZo26JMNKsrA+jezLk1xBPmT/UtpvD1L//19+ CNlPfTqsqAksFAqLD6TLUVgLeNv1MiMGEj9sOGiGuDXvixeCcGleemQkmbKm/ihl viXBHYh2M9ZZtKU3I2R0tnKrwCnL1ZsU/QQb70/d3fKhJeoQrsd9jgnS0jeArLLy RwTSWnvj1WcxId0+JT4nL6gvRNLs64fyI6QzZ/6eLHrPBQtRxEf055I2UvjO81tE n9YA0nfIxeyeGc1+XqnE4FUmY0LEhuJT48PbsrHP5WT4XCb3mIhKg42EJ+r6WQIn G8I0TzMZsDxXZ6vYnd4BfNKhpf0qSn2CoEcj1Jtg4lovLltc5j0VWji4iuXaLiJ3 o5rao7F0yk12iomSE2XE7gIwU7YUOHGzcqx011cDNmv/z2Vdr8tFCB8Svh7Y6VMA 0LcDH8LLVGSlXneP5frzUimBS1A6ogu8ocYxhIp4ww60Lqq1TOOIebj2m/znaaj4 CWuXI6GnK+w= =y3y4 -END PGP SIGNATURE- /* grep open(2) for O_LARGEFILE to explain this: */ #define _FILE_OFFSET_BITS 64 #include sys/types.h #include sys/stat.h #include unistd.h #include fcntl.h #include stdio.h /* Author: Daniel Kahn Gillmor [EMAIL PROTECTED] Date: 2008-05-28 This is a demonstration program for testing http://bugs.debian.org/483216 */ int main(int argc, char* argv[]) { struct flock flock; int fd; flock.l_whence=SEEK_SET; /* open file, get file descriptor */ fd = open(argv[1], O_RDWR|O_CREAT, 0644); fcntl(fd, F_SETFD, FD_CLOEXEC | fcntl(fd, F_GETFD)); /* get read lock: */ flock.l_type=F_RDLCK; flock.l_start=0; flock.l_len = 1; if (0 != fcntl(fd, F_SETLK64, flock)) { perror(read lock failed); return 1; } /* get write lock for same range: */ flock.l_type=F_WRLCK; if (0 != fcntl(fd, F_SETLK64, flock)) { /* fails here when used on CIFS share mounted without nobrl option */ perror(write lock failed); return 1; } return 0; }