Overview ---------------------- When mounting a CIFS share from a Microsoft Windows 7 or Windows Server 2008 (R1 or R2) system, the number of hard links of both directories and (under certain circumstances) ordinary files is wrong (always 0), no matter what the mount options are. Mounts from Windows 2003 Server and older are set correctly. Steps to Reproduce ---------------------- 1. mount a share from a Windows 7/2008 system to /mnt (mount option [no]unix has no effect) 2. ls -la /mnt or stat /mnt Actual Results ---------------------- Directories on the share have the type "directory" (as reported by ls and stat) but a hard link count of 0. Expected Results ---------------------- The hard link count for any directory should always be at least 2. Build Date & Platform ---------------------- kernel version 3.7.1, built on January 10th, on an Ubuntu kernel 3.6.5 (custom compiled), x86_64, with gcc version 4.6.3-1ubuntu5. Additional Information ---------------------- Local processes, especially the Bash, don't bother about the link count. Accessing files and listing directories, changing into them etc. are no problem. Samba, however is probably just one example of software relying on the number of hard links for its own purposes. For example, it treats directories with a 0 hard link count as ordinary files with size 0 (Samba clients cannot "click-change" into them, but they can access them directly), and files with 0 link count are presented to the client but inaccessible. See Demonstration below. Workaround: Any combination of mount options ([no]unix, [no]serverino, ...) yields the same results concerning the hard link count. Patching the function cifs_fattr_to_inode works, although it doesn't seem to do anything different than the several other places in inode.c (e. g. cifs_all_info_to_fattr) that set cf_nlink. *** linux-3.X.X-ORIGINAL/fs/cifs/inode.c 2012-12-06 14:58:18.248221824 +0100 --- linux-3.X.X/fs/cifs/inode.c 2013-01-10 14:02:38.367733296 +0100 *************** *** 132,138 **** inode->i_mtime = fattr->cf_mtime; inode->i_ctime = fattr->cf_ctime; inode->i_rdev = fattr->cf_rdev; ! set_nlink(inode, fattr->cf_nlink); inode->i_uid = fattr->cf_uid; inode->i_gid = fattr->cf_gid; --- 132,141 ---- inode->i_mtime = fattr->cf_mtime; inode->i_ctime = fattr->cf_ctime; inode->i_rdev = fattr->cf_rdev; ! if (fattr->cf_cifsattrs & ATTR_DIRECTORY) ! set_nlink(inode, 2); ! else ! set_nlink(inode, 1); inode->i_uid = fattr->cf_uid; inode->i_gid = fattr->cf_gid; In other words, the following piece of code in the current kernel does not work, as the link count cf_nlink seems to be reset to 0 somewhere else: static void cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, struct cifs_sb_info *cifs_sb, bool adjust_tz) { ... if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; fattr->cf_dtype = DT_DIR; /* * Server can return wrong NumberOfLinks value for directories * when Unix extensions are disabled - fake it. */ fattr->cf_nlink = 2; Demonstration: The following is a demonstration with kernel version 3.6.5, however the problem is still present in the current version 3.7.1. root@log002:~# uname -r -m 3.6.5 x86_64 root@log002:~# mount.cifs -V mount.cifs version: 5.7 root@log002:~# mount.cifs //sas003/testshare /mnt/testshare -o serverino,user=administrator Password for administrator@//sas003/testshare: root@log002:~# ls -lai /mnt/testshare/ total 5 792352059440498915 drwxr-xr-x 2 root root 0 Nov 1 13:28 . 917508 drwxr-xr-x 8 root root 4096 Nov 1 13:29 .. 3 drwxr-xr-x 0 root root 0 Nov 1 13:27 dir1 4 drwxr-xr-x 0 root root 0 Nov 1 13:28 dir2 5 -rwxr-xr-x 1 root root 15 Nov 1 13:27 file1.txt 6 -rwxr-xr-x 1 root root 22 Nov 1 13:28 file2.txt root@log002:~# ls -lai /mnt/testshare/dir1 total 1 3 drwxr-xr-x 2 root root 0 Nov 1 13:27 . 792352059440498915 drwxr-xr-x 2 root root 0 Nov 1 13:28 .. 7 -rwxr-xr-x 1 root root 15 Nov 1 13:27 file_in_dir1.txt root@log002:~# stat /mnt/testshare/dir1 File: `/mnt/testshare/dir1' Size: 0 Blocks: 0 IO Block: 16384 directory Device: 13h/19d Inode: 3 Links: 2 Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2012-11-04 16:50:36.564250000 +0100 Modify: 2012-11-01 13:27:59.035250000 +0100 Change: 2012-11-01 13:27:59.035250000 +0100 Birth: - root@log002:~# This is what the Samba server (any version really) delivers to the client: root@log002:~# smbclient //log002/testthis Enter root's password: (empty) Domain=[INTERNAL] OS=[Unix] Server=[Samba 3.6.3] Server not using user level security and no password supplied. smb: \> dir . D 0 Thu Nov 1 13:28:24 2012 .. D 0 Thu Nov 1 13:29:23 2012 dir1 0 Thu Nov 1 13:27:59 2012 dir2 0 Thu Nov 1 13:28:04 2012 file1.txt A 15 Thu Nov 1 13:27:43 2012 file2.txt A 22 Thu Nov 1 13:28:32 2012 64636 blocks of size 131072. 24954 blocks available smb: \> cd dir1 smb: \dir1\> dir . D 0 Thu Nov 1 13:27:59 2012 .. D 0 Thu Nov 1 13:28:24 2012 file_in_dir1.txt A 15 Thu Nov 1 13:27:43 2012 64636 blocks of size 131072. 24954 blocks available smb: \dir1\> root@log002:~#
Me, too™ To be more precise: I can confirm the issue with 3.8.13 on the client and Windows Server 2003 R2 as well as samba on the server side, so this doesn't seem related to the Windows version really. Workaround works for me, however the real fix should likely rather care about this "somewhere else": (In reply to Dominik Schramm from comment #0) > In other words, the following piece of code in the current kernel does not > work, as the link count cf_nlink seems to be reset to 0 somewhere else:
I can confirm this is a problem as well and needs to be resolved asap. I am running: kernel: 2.6.32-358.11.1.el6.x86_64 Samba: 3.6.9-151.el6.x86_64 When mounting CIFS share from EMC NAS and sharing via Samba, directories appear as regular files. I attempted the 'workaround' above by modifying inode.c in cifs.ko but the function set_nlink did not exist so wrote my own fix to force inode to 2 on directories: inode->i_rdev = fattr->cf_rdev; if (fattr->cf_cifsattrs & ATTR_DIRECTORY) inode->i_nlink = 2; else inode->i_nlink = fattr->cf_nlink; inode->i_uid = fattr->cf_uid; inode->i_gid = fattr->cf_gid; This code fixed it for me. I imagine lots of people are having this issue.
This appears to be a samba bug. It should be testing with S_ISDIR(). Setting up i_nlink might be nice but you would have to set it correctly to account for all the subdirectories or it'll confuse other software much of which treats "0" as "undefined" and avoids optimisations. Also 2.6.32 is a completely obsolete kernel! Closing as will not fix, but if you do cook up a full patch that gets i_nlink right for the subdirectory count then go for it.
Not a samba bug actually, since the server in this case is Windows or in the case of comment #2, an EMC NAS. The CIFS protocol doesn't state that the server must return a value of at least 2 for the NumberOfLinks value on a directory like we expect with POSIX-y servers, so it's quite common for them to return a NumberOfLinks value of 0 on a directory. We have some code in more modern kernels to make the client fake up an i_nlink value when this happens. If you're using RHEL6 above, then you're welcome to open a RH support case and ask us to backport those patches to RHEL6 kernel.
The commit Jeff is refering to appears to be http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/fs/cifs?id=74d290da476f672ad756634d12aa707375d3564d . I can't see any part of it in the 3.2 stable kernel so I think there is a good case for backporting it...
Opened backport request https://bugzilla.redhat.com/show_bug.cgi?id=1554342
Test on 4.17.0-rc1. The cf_nlink is correct for the direcotry of mounted point. But when I create the son directory in the father directory. The cf_nlink of the father directory doesn't be changed. -bash-4.2# stat cifs File: ‘cifs’ Size: 20090880 Blocks: 39240 IO Block: 16384 directory Device: 2eh/46d Inode: 281474976710691 Links: 2 Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Context: system_u:object_r:cifs_t:s0 Access: 2018-05-07 03:07:52.364814200 -0400 Modify: 2018-05-07 03:07:52.364814200 -0400 Change: 2018-05-07 03:07:52.364814200 -0400 Birth: - -bash-4.2# stat cifs/sub-dir File: ‘cifs/sub-dir’ Size: 0 Blocks: 0 IO Block: 16384 directory Device: 2eh/46d Inode: 19421773393972992 Links: 2 Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Context: system_u:object_r:cifs_t:s0 Access: 2018-05-07 03:07:52.364814200 -0400 Modify: 2018-05-07 03:07:52.364814200 -0400 Change: 2018-05-07 03:07:52.364814200 -0400 Birth: - -bash-4.2# stat cifs File: ‘cifs’ Size: 20090880 Blocks: 39240 IO Block: 16384 directory Device: 2eh/46d Inode: 281474976710691 Links: 2 Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Context: system_u:object_r:cifs_t:s0 Access: 2018-05-07 03:07:52.364814200 -0400 Modify: 2018-05-07 03:07:52.364814200 -0400 Change: 2018-05-07 03:07:52.364814200 -0400