If you are using Linux kernel 3.4, especially on Android, and you are having troubles mounting windows or samba shares, and you are in a hurry, please skip to section 2 or the conclusion at the end. I just need to tell a little story first.
1. The Story of a Fool
That’s how it’s supposed to be: You take out your Android phone. Mount a windows share to a directory of your liking and start accessing your files from any app you like. Yes, eat that, iPhone. Welcome to the 21st century. At least that’s how it used to be on my Xperia T until I updated the firmware to a newer version.
To be more precise, you need a rooted Android phone. And an app like CifsManager. It’s pretty easy. You can enter a number of windows shares, including user name and password if necessary, and the paths you want them to be mounted to. From now on, you can mount and unmount the shares with a single click. Really neat.
Then one day, I updated the firmware of my Xperia T from 7.0.A.3.195 (Android 4.0.4) to 9.1.A.0.489 (Android 4.1). And the days of happy networking with windows were gone. CifsManager stubbornly denied mounting with an “Invalid argument” error. A very helpful error, I must say.
After hours of googling around, I found many articles, telling me that the linux kernel of the new firmware is probably missing CIFS support. If I am lucky, somebody will create a CIFS kernel module, which could be loaded with insmod. Again many hours later I realized that nobody seems to have done that for my phone. So I gave up, hoping that the issue would be fixed in another firmware.
Half a year later and two firmware versions later (9.1.A.1.140 und 9.1.A.1.145), the issue was still there. I knew that the kernel for Xperia phones is open source (Sony, you roxor!!!). Having compiled Linux kernels a couple of times, I thought it shouldn’t be that hard to compile one for my phone in order to get a CIFS kernel module. So many hours later with the help of many posts on xda developers, I finally created my own Android Linux kernel. Getting cifs.ko as a byproduct. Actually I could have complied the CIFS module into the kernel and used the whole kernel. But I didn’t want to mess around to much and decided to compile CIFS as a kernel module and just take the module by itself.
I copied cifs.ko to my phone, and gave it a try:
root@android:/system/lib/modules # insmod cifs.ko insmod: init_module 'cifs.ko' failed (Invalid argument)
Of course, another “Invalid argument” error. Would have been too easy. So after asking Dr. Google again, I found out that kernel errors can be viewed with dmesg. So hopefully there is a kernel message that will tell me what’s wrong:
255|root@android:/system/lib/modules # dmesg ... <3>[ 5268.808545] cifs: module is already loaded
?!!$!Q§%%”.. Dang. Only then, I realized that CIFS was included in my kernel all along. All those articles about CIFS missing in the kernel were leading me to the wrong conclusion. While in reality, my princess was in another castle altogether.
2. Troubleshooting CIFS
A note here, that everything that follows is not necessarily specific to Android phones. It’s in fact pure Linux stuff.
It’s actually pretty easy to check if CIFS support is included in the kernel. Check if following directory exists. I wish I would have known that a while ago:
root@android:/ # l /proc/fs/cifs -r--r--r-- root root 0 2013-10-07 19:47 DebugData -r--r--r-- root root 0 2013-10-07 19:47 LinuxExtensionsEnabled -r--r--r-- root root 0 2013-10-07 19:47 LookupCacheEnabled -r--r--r-- root root 0 2013-10-07 19:47 MultiuserMount -r--r--r-- root root 0 2013-10-07 19:47 SecurityFlags -r--r--r-- root root 0 2013-10-07 19:47 cifsFYI -r--r--r-- root root 0 2013-10-07 19:47 traceSMB
So if you have that, you are almost there. If you don’t, check if there is a kernel module for CIFS. It’s usually somewhere in /lib/modules/
Now I tried mounting from the shell (get Terminal Emulator or something for that). Here is an example:
root@android:/ # mount -o username=guest,password=guest -t cifs //10.0.0.200/Public /sdcard/shares/nas mount: Invalid argument
Yes that “Invalid argument” error was actually the same error that CifsManager was throwing at me all along. Let’s check the kernel messages with dmesg again:
<3>[ 5924.225392] CIFS VFS: Connecting to DFS root not implemented yet
Huh, what the heck is that supposed to mean? Luckily, since I already had the kernel source, I was able to search for that error in the source code. Note, that the kernel version for my phone was 3.4.0. While looking around in the source code. I found out that one can enable additional debug messages by writing 1 into /proc/fs/cifs/cifsFYI:
255|root@android:/system/lib/modules # echo 1 > /proc/fs/cifs/cifsFYI
Now I tried mounting again and checked with dmesg once more:
<7>[ 7213.456950] cifsfs.c: Devname: //10.0.0.200/Public flags: 32768 <7>[ 7213.457041] connect.c: Username: guest <7>[ 7213.457102] connect.c: file mode: 0x1ed dir mode: 0x1ed <7>[ 7213.460002] connect.c: CIFS VFS: in cifs_mount as Xid: 2 with uid: 0 <7>[ 7213.460063] connect.c: UNC: (null) ip: (null) <3>[ 7213.460093] CIFS VFS: Connecting to DFS root not implemented yet <7>[ 7213.462535] connect.c: CIFS VFS: leaving cifs_mount (xid = 2) rc = -22
Finally something useful. Especially the line containing UNC: (null) ip: (null) looked fishy. Why was there no UNC path nor IP address? So I looked further into the CIFS source code. Especially in connect.c, since all the messages originated from there. I was really surprised about what I saw there. The device name (//10.0.0.200/Public in my case) was nowhere used. I don’t know if that’s a bug in kernel 3.4.0. At least it’s a very unexpected feature. Instead one has to specify the UNC path with the mount parameter unc. After a little trial and error, I also noticed that the unc path needed to be specified with backslashes \ not slashes /. So here we go again:
root@android:/ # mount -o unc=\\\\10.0.0.200\\Public,username=guest,password=guest -t cifs none /sdcard/shares/nas
Wow. No error message. As you can see, I didn’t even specify the UNC path as device (just none). Only as mount parameter. Also note, that the backslashes need to be escaped by a backslash again, because they have a specialy meaning in the shell (\\\\ actually means \\).
Checking with mount if it was actually successful:
root@android:/ # mount ... none /storage/sdcard0/shares/nas cifs rw,relatime,sec=ntlm,unc=\\10.0.0.200\Public,username=guest,uid=0,noforceuid,gid=0,noforcegid,addr=10. 0.0.200,file_mode=0755,dir_mode=0755,nounix,serverino,rsize=61440,wsize=65536,actimeo=1 0 0
Finally. After many month I was able to connect my phone to windows shares again.
So, long story short, my problem was very specific to kernel 3.4. As I updated my phone to a new firmware, I also got a new kernel version, which didn’t accept the usual mount syntax. You need to specify the UNC path as a mount parameter and not as a device name. Like this:
mount -o unc=\\\\10.0.0.200\\Public,username=guest,password=guest -t cifs none sharedir
I guess that is not that big of a deal on full blown Linux machines, because you can also use mount.cifs. But that command is not available on Android devices.
From what I saw in the CIFS kernel sources, the “Invalid argument” error is issued by virtually every problem. So there could be 1000 possible problems. And all you get is “Invalid argument”. And that error does not necessarily mean, that CIFS is not supported (as it is stated in many posts around the Internets). Actually you get a different error if CIFS is not supported (unknown filesystem type). Most likely it is another problem. Looking at the kernel messages was really helpful.
Furthermore, I verified that a more recent kernel actually works like one would suspect:
mount -t cifs \\10.0.0.200\Public sharedir
Nevertheless, following steps should be helpful regarding any mounting problems regarding CIFS (or other filesystems):
- Verify that CIFS is supported by the kernel by checking if /proc/fs/cifs exists.
- You will get “Invalid argument” for about any Problem. You need to check the kernel messages with dmesg.
- Put the value “1” into /proc/fs/cifs/cifsFYI to get more detailed kernel messages.
See you around.
If you are running Android 4.2 or newer. And you can mount the share from the command line, but other apps won’t see any files in the mounted directory, then this might be caused by a security feature introduced in newer versions of Android where mounts are isolated in different namespaces.
A fellow user named will (see below in the comments) posted a solution for that. You can use chainfire’s supersu to get around that problem by mounting publicly:
su --mount-master -c mount -o unc='\\\\192.168.1.139\\data',username=kenneth,password=mypassword,rw,noperm,file_mode=0777,dir_mode=0777 -t cifs none /sdcard/cifs/Data
or with disabling SELinux
su -c setenforce 0 && su --mount-master -c mount -o unc='\\\\192.168.1.139\\data',username=kenneth,password=mypassword,rw,noperm,file_mode=0777,dir_mode=0777 -t cifs none /sdcard/cifs/Data
Also take a look at the chainfire How-To.
Thanks will! And also thanks to Kenneth for confirming that solution.