[Workaround]The third SunOS4.1.4 tmpfs bug

YAMAMORI Takenori (yamamori@KT.RIM.OR.JP)
Wed, 11 Feb 1998 12:35:53 +0900

Now, I think there are *three* different tmpfs bugs on SunOS4.1.4.

The first and the second was fixed by the patches.
But the third still remains unsolved, but now I wrote a workaround
program for it, and send it.

The first bug is "fifo hard link bug" that can be fixed by the patch
100507-06 (which is for SunOS4.1.3, but apply to SunOS4.1.4 anyway).

(/tmp is mounted as tmpfs)
$ cd /tmp
$ mknod aaa p
$ ln aaa bbb # should be hard-link
$ ls -l
and then kernel panics.

The second bug is "assertion failed: tp->tn_dir == NULL" that was
fixed by the patch 103314-01.

$ cd /tmp
$ mkdir a
$ cd a
$ vi b (write something to it, but keep the file open)
[ switch screen ]
$ rm -r /tmp/a
[ switch screen ]
(save the file using :w in vi)
and then kernel panics.

However ....

The third tmpfs bug still remains.
(not solved by 100507-06 nor 103314-01)
It is "tmpfs symlink bug" I previously said.

(/tmp is mounted as tmpfs)
$ cd /tmp
$ mkdir aaa
$ chmod -w aaa
$ cd aaa
$ ln -s bbb ccc # should be symbolic-link (not hard-link)
panic: kmem_free: block already free

But Now, I just finished to write a tmpfs-bug-fix program.
I modload this program to the SunOS4.1.4 kernel and I found
the tmpfs third bug no more happened !

I shall include this bug-fix program.

(Also in http://www.tt.rim.or.jp/~yamamori/sun/tmpfs-symlink-fix.tar.gz
but the README is written in Japanese, sorry)

----- cut here -------------------------------------------------------
/* tmpfs-symlink-fix.c */

/*
* tmpfs symlink bug:
*
* (/tmp is mounted as tmpfs)
* $ cd /tmp
* $ mkdir aaa
* $ chmod -w aaa
* $ cd aaa
* $ ln -s bbb ccc # should be symbolic-link (not hard-link)
* panic: kmem_free: block already free
*
*/

#define KERNEL
/* change here */
#define sun4c
#define __sun4c__ /* for the use of gcc's fix-include */
/* #define sun4m */
/* #define __sun4m__ */

#include <sys/types.h>
#include <sys/conf.h>
#include <sys/buf.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/user.h>
#include <sys/time.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
#include <sys/ucred.h>
#include <sys/syslog.h>
#include <sundev/mbvar.h>
#include <sun/autoconf.h>
#include <sun/vddrv.h>

extern struct vnodeops tmp_vnodeops;

static struct vdldrv vd = {
VDMAGIC_PSEUDO, /* Drv_magic */
"tmpfs-symlink-fix" /* Drv_name */
/* unused members */
};

static int (*real_tmp_symlink)();

int
wrap_tmp_symlink(
struct vnode *vn,
char *l_name,
int *va,
char *t_name,
struct ucred *cred
) {

struct vnode *vn1;
int err;

#ifdef DEBUG
printf("tmp_symlink: l_name=%s t_name=%s va=%x\n", l_name, t_name, *va);
#endif

if ((err = VOP_MKDIR(vn, l_name, va, &vn1, cred)) != 0) {
return err;
}
VOP_RMDIR(vn, l_name, cred);
return real_tmp_symlink(vn, l_name, va, t_name, cred);
}

int
xxxinit(
unsigned int function_code,
struct vddrv *vdp,
addr_t vdi,
struct vdstat *vds
) {

int x;

switch(function_code) {
case VDLOAD:
vdp->vdd_vdtab = (struct vdlinkage*)&vd;

x = splhigh();
real_tmp_symlink = tmp_vnodeops.vn_symlink;
tmp_vnodeops.vn_symlink = wrap_tmp_symlink;
splx(x);

log(LOG_INFO, "tmpfs symlink-fix module loaded\n");
return 0;

case VDUNLOAD:
x = splhigh();
tmp_vnodeops.vn_symlink = real_tmp_symlink;
splx(x);

log(LOG_INFO, "tmpfs symlink-fix module unloaded\n");
return 0;

case VDSTAT:
return 0;

default:
return EIO;
}
}
----- cut here -------------------------------------------------------

----------------------------------------
YAMAMORI Takenori yamamori@kt.rim.or.jp
----------------------------------------