Thank you, Roger, for your comments.

You're right that the test Oracle XE applies is badly broken. See details inline your comment below.

This has not been reported to Oracle as Debian Linux is not a supported platform for running their Database product. (I will make a try reporting this.)

Though I understand that dev/shm is an implementation detail, it was user for ages and would using bind mount would simplify Debian users' life when they intend to use Oracle Database.

I'm attaching a patch[1] I have tested that makes this behaviour configurable in /etc/default/tmpfs leaving symlink as the default value. I hope that this can be intergated in Wheezy.

[1]: 20121209_lib_init_mount-functions_configurable_devshm_bindmount.patch

On 2012-11-30 00:09, Roger Leigh wrote:
On Thu, Nov 29, 2012 at 11:04:25PM +0000, Roger Leigh wrote:
On Thu, Nov 29, 2012 at 10:14:51PM +0000, Roger Leigh wrote:
On Sun, Nov 25, 2012 at 11:45:48PM +0100, Jozsef Marton wrote:
How is Oracle testing for the presence of /dev/shm?  Their check is
obviously broken, but it would be helpful to know what exactly they
are doing.  strace would be useful here.

strace showed the following check and result reagrdless of being /dev/shm a bind mount or symlink to /run/shm. So until this, everything is working with the new configuration.
stat("/dev/shm", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=60, ...}) = 0


Later on, after passing checks of /dev/shm, the following pattern comes up in strace:

shmget(IPC_PRIVATE, 4194304, 0660)      = 425984
shmat(425984, 0, 0x8000 /* SHM_??? */)  = -1 EACCES (Permission denied)
shmctl(425984, IPC_RMID, 0)             = 0
shmget(IPC_PRIVATE, 4096, IPC_CREAT|IPC_EXCL|0660) = 458752
shmat(458752, 0, 0)                     = ?
open("/dev/shm/ora_XE_458752_0", O_RDWR|O_CREAT|O_SYNC, 0660) = 9
ftruncate(9, 4194304)                   = 0
close(9)                                = 0
open("/dev/shm/ora_XE_458752_1", O_RDWR|O_CREAT|O_SYNC, 0660) = 9
ftruncate(9, 4194304)                   = 0
close(9)                                = 0
shmdt(0x7f8070a24000)                   = 0


They use the O_SYNC flag with open which is not available for shm_open. Maybe it is not even necessary on tmpfs, but this would lead far from our current issue.


The thing which most broken is between the stat and the first shmget call, and is as follows:

To see the available shm size, Oracle check for the output of
/bin/df -k /dev/shm.

Being /dev/shm a symlink to /run/shm, the following is returned as df is smart enough to follow symlink: read(9, "Filesystem 1K-blocks Used Available Use% Mounted on\ntmpfs 1572864 0 1572864 0% /run/shm\n", 4096) = 112

Being /dev/shm a bind mount os /run/shm, the following is returned:
read(9, "Filesystem 1K-blocks Used Available Use% Mounted on\ntmpfs 1572864 0 1572864 0% /dev/shm\n", 4096) = 112


Note that df resolve the symlink before producing its output, and this fools Oracle XE. By writing a wrapper around /bin/df to handle "/bin/df -k /dev/shm" call on exception path without resolving symlink, everything is fine again, Oracle is working properly.

For peoples searching for this Oracle error on Debian Wheezy, I'm also attaching a wrapper[2] for df that can also be used to circumvent this problem. NOTE that this wrapper is not meant to be included in Debian. I wrote it only to proof my concept that df output fooled Oracle XE.
To use this, first
# mv /bin/df /bin/df.real
then save the attached df script as /bin/df, then
# chown root:root df
# chmod 755 /bin/df

[2]: df_wrapper_to_handle_-k_devshm_exceptionally.sh

Best regards,
Jozsef
--- lib_init_mount-functions.sh.orig	2012-07-01 15:30:00.000000000 +0200
+++ lib_init_mount-functions.sh	2012-12-09 16:37:58.241399349 +0100
@@ -353,7 +353,10 @@ run_migrate ()
 	# them yet.  If the user explicitly mounted a filesystem here,
 	# it will be cleaned out, but this would happen later on when
 	# bootclean runs in any case.
-	if [ ! -L "$OLD" ] && [ -d "$OLD" ] ; then
+	# If SHM is forced to be bind mounted to /run/shm in /etc/default/tmpfs
+	# /dev/shm is not removed, so later bind mount will be initiated.
+	if [ ! -L "$OLD" ] && [ -d "$OLD" ] && 
+           ( [ "$OLD" != "/dev/shm" ] || [ "${SHM_BINDMOUNT_TO_DEV_SHM:-no}" != "yes" ] )  ; then
 		rm -fr "$OLD" 2>/dev/null || true
 	fi
 
--- etc_default_tmpfs.orig	2012-08-11 19:30:40.000000000 +0200
+++ etc_default_tmpfs	2012-12-09 16:56:41.693108624 +0100
@@ -31,3 +31,12 @@
 # Mount tmpfs on /tmp if there is less than the limit size (in kiB) on
 # the root filesystem (overriding RAMTMP).
 #TMP_OVERFLOW_LIMIT=1024
+
+
+# Mount /dev/shm as a bind mount of /run/shm instead of symlinking to it.
+# Badly broken software (eg. see Debian Bug #694379) might depend on
+# being shared memory mounted to the hardcoded path /dev/shm.
+# Default: no
+# Set to yes to force bind mount.
+#SHM_BINDMOUNT_TO_DEV_SHM=no
+SHM_BINDMOUNT_TO_DEV_SHM=yes

Attachment: df_wrapper_to_handle_-k_devshm_exceptionally.sh
Description: Bourne shell script

Reply via email to