patch-2.1.53 linux/arch/sparc64/kernel/sys_sparc32.c
Next file: linux/arch/sparc64/kernel/systbls.S
Previous file: linux/arch/sparc64/kernel/sys_sparc.c
Back to the patch index
Back to the overall index
- Lines: 522
- Date:
Thu Sep 4 12:54:48 1997
- Orig file:
v2.1.52/linux/arch/sparc64/kernel/sys_sparc32.c
- Orig date:
Mon Aug 18 18:19:45 1997
diff -u --recursive --new-file v2.1.52/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.43 1997/07/17 02:20:45 davem Exp $
+/* $Id: sys_sparc32.c,v 1.55 1997/09/04 01:54:51 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -44,6 +44,7 @@
#include <asm/ipc.h>
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
+#include <asm/semaphore.h>
/* As gcc will warn about casting u32 to some ptr, we have to cast it to
* unsigned long first, and that's what is A() for.
@@ -53,6 +54,33 @@
*/
#define A(x) ((unsigned long)x)
+extern char * getname_quicklist;
+extern int getname_quickcount;
+extern struct semaphore getname_quicklock;
+extern int kerneld_msqid;
+
+/* Tuning: increase locality by reusing same pages again...
+ * if getname_quicklist becomes too long on low memory machines, either a limit
+ * should be added or after a number of cycles some pages should
+ * be released again ...
+ */
+static inline char * get_page(void)
+{
+ char * res;
+ down(&getname_quicklock);
+ res = getname_quicklist;
+ if (res) {
+ getname_quicklist = *(char**)res;
+ getname_quickcount--;
+ }
+ else
+ res = (char*)__get_free_page(GFP_KERNEL);
+ up(&getname_quicklock);
+ return res;
+}
+
+#define putname32 putname
+
/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them..
@@ -74,44 +102,67 @@
return retval;
}
-/* This is a single page for faster getname.
- * If the page is available when entering getname, use it.
- * If the page is not available, call __get_free_page instead.
- * This works even though do_getname can block (think about it).
- * -- Michael Chastain, based on idea of Linus Torvalds, 1 Dec 1996.
- * We don't use the common getname/putname from namei.c, so that
- * this still works well, as every routine which calls getname32
- * will then call getname, then putname and then putname32.
- */
-static unsigned long name_page_cache32 = 0;
+char * getname32(u32 filename)
+{
+ char *tmp, *result;
+
+ result = ERR_PTR(-ENOMEM);
+ tmp = get_page();
+ if (tmp) {
+ int retval = do_getname32(filename, tmp);
+
+ result = tmp;
+ if (retval < 0) {
+ putname32(tmp);
+ result = ERR_PTR(retval);
+ }
+ }
+ return result;
+}
-void putname32(char * name)
+/* 32-bit timeval and related flotsam. */
+
+struct timeval32
{
- unsigned long page;
+ int tv_sec, tv_usec;
+};
- page = xchg(&name_page_cache32, ((unsigned long)name));
- if(page)
- free_page(page);
+struct itimerval32
+{
+ struct timeval32 it_interval;
+ struct timeval32 it_value;
+};
+
+static inline long get_tv32(struct timeval *o, struct timeval32 *i)
+{
+ return (!access_ok(VERIFY_READ, tv32, sizeof(*tv32)) ||
+ (__get_user(o->tv_sec, &i->tv_sec) |
+ __get_user(o->tv_usec, &i->tv_usec)));
}
-int getname32(u32 filename, char **result)
+static inline long put_tv32(struct timeval32 *o, struct timeval *i)
{
- unsigned long page;
- int retval;
+ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+ (__put_user(i->tv_sec, &o->tv_sec) |
+ __put_user(i->tv_usec, &o->tv_usec)));
+}
- page = xchg(&name_page_cache32, NULL);
- if (!page) {
- page = __get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- }
+static inline long get_it32(struct itimerval *o, struct itimerval32 *i)
+{
+ return (!access_ok(VERIFY_READ, i32, sizeof(*i32)) ||
+ (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
+ __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
+ __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
+ __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
+}
- retval = do_getname32(filename, (char *) page);
- if (retval < 0)
- putname32( (char *) page );
- else
- *result = (char *) page;
- return retval;
+static inline long put_it32(struct itimerval32 *o, struct itimerval *i)
+{
+ return (!access_ok(VERIFY_WRITE, i32, sizeof(*i32)) ||
+ (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
+ __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
+ __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
+ __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
}
extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
@@ -266,14 +317,25 @@
switch (call) {
case MSGSND:
{
- struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL);
+ struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL);
if (!p) err = -ENOMEM;
else {
- if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
- __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
- err = -EFAULT;
- else {
+ err = 0;
+ if (first == kerneld_msqid) {
+ *(int *)p->mtext = 0;
+ if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_from_user(&p->mtext[4], &(((struct msgbuf32 *)A(ptr))->mtext[0]), 4) ||
+ __copy_from_user(&p->mtext[8], &(((struct msgbuf32 *)A(ptr))->mtext[4]), second-4))
+ err = -EFAULT;
+ else
+ second += 4;
+ } else {
+ if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
+ err = -EFAULT;
+ }
+ if (!err) {
unsigned long old_fs = get_fs();
set_fs (KERNEL_DS);
err = sys_msgsnd (first, p, second, third);
@@ -287,6 +349,7 @@
{
struct msgbuf *p;
unsigned long old_fs;
+ long msgtyp = fifth;
if (!version) {
struct ipc_kludge tmp;
@@ -297,20 +360,35 @@
if(copy_from_user(&tmp,(struct ipc_kludge *)A(ptr), sizeof (tmp)))
goto out;
ptr = tmp.msgp;
- fifth = tmp.msgtyp;
+ msgtyp = tmp.msgtyp;
}
- p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL);
+
+ p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL);
if (!p) {
err = -EFAULT;
goto out;
}
+
old_fs = get_fs();
set_fs (KERNEL_DS);
- err = sys_msgrcv (first, p, second, fifth, third);
+ err = sys_msgrcv (first, p, second + 4, msgtyp, third);
set_fs (old_fs);
- if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
- __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, second))
- err = -EFAULT;
+
+ if (err < 0)
+ goto out;
+
+ if (first == kerneld_msqid) {
+ if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[0]), &p->mtext[4], 4) ||
+ __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[4]), &p->mtext[8], err-8))
+ err = -EFAULT;
+ else
+ err -= 4;
+ } else {
+ if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
+ __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, err))
+ err = -EFAULT;
+ }
kfree (p);
goto out;
}
@@ -472,8 +550,9 @@
err = -EINVAL;
goto out;
}
- else
- err = -EINVAL;
+
+ err = -EINVAL;
+
out:
unlock_kernel();
return err;
@@ -565,8 +644,9 @@
return sys_quotactl(cmd, (const char *)A(special),
id, (caddr_t)A(addr));
}
- err = getname32 (special, &spec);
- if (err) return err;
+ spec = getname32 (special);
+ err = PTR_ERR(spec);
+ if (IS_ERR(spec)) return err;
old_fs = get_fs ();
set_fs (KERNEL_DS);
err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)A(addr));
@@ -608,8 +688,9 @@
unsigned long old_fs = get_fs();
char *pth;
- ret = getname32 (path, &pth);
- if (!ret) {
+ pth = getname32 (path);
+ ret = PTR_ERR(pth);
+ if (!IS_ERR(pth)) {
set_fs (KERNEL_DS);
ret = sys_statfs((const char *)pth, &s);
set_fs (old_fs);
@@ -651,8 +732,9 @@
if (get_user (t.actime, &(((struct utimbuf32 *)A(times))->actime)) ||
__get_user (t.modtime, &(((struct utimbuf32 *)A(times))->modtime)))
return -EFAULT;
- ret = getname32 (filename, &filenam);
- if (!ret) {
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
old_fs = get_fs();
set_fs (KERNEL_DS);
ret = sys_utime(filenam, &t);
@@ -1019,7 +1101,13 @@
ret = -EFAULT;
- nn = (n + (8 * sizeof(unsigned long)) - 1) / (8 * sizeof (unsigned long));
+ nn = (n + (8 * sizeof(long)) - 1) / (8 * sizeof(long));
+ if (inp && verify_area(VERIFY_WRITE, Inp, nn*sizeof(long)))
+ goto out;
+ if (outp && verify_area(VERIFY_WRITE, Outp, nn*sizeof(long)))
+ goto out;
+ if (exp && verify_area(VERIFY_WRITE, Exp, nn*sizeof(long)))
+ goto out;
for (i = 0; i < nn; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
if(inp && (__get_user (q[1], Inp) || __get_user (q[0], Inp+1)))
goto out;
@@ -1033,7 +1121,7 @@
ktvp = NULL;
if(tvp) {
- if(copy_from_user(&kern_tv, (struct timeval *)A(tvp), sizeof(*ktvp)))
+ if (get_tv32(&kern_tv, (struct timeval32 *)A(tvp)))
goto out;
ktvp = &kern_tv;
}
@@ -1048,8 +1136,12 @@
ktvp);
set_fs (old_fs);
- if(tvp && !(current->personality & STICKY_TIMEOUTS))
- copy_to_user((struct timeval *)A(tvp), &kern_tv, sizeof(*ktvp));
+ if(tvp && !(current->personality & STICKY_TIMEOUTS)) {
+ if (put_tv32((struct timeval32 *)A(tvp), &kern_tv)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
q = (u32 *)p;
Inp = (u32 *)A(inp);
@@ -1112,8 +1204,9 @@
char *filenam;
unsigned long old_fs = get_fs();
- ret = getname32 (filename, &filenam);
- if (!ret) {
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
set_fs (KERNEL_DS);
ret = sys_newstat(filenam, &s);
set_fs (old_fs);
@@ -1133,8 +1226,9 @@
char *filenam;
unsigned long old_fs = get_fs();
- ret = getname32 (filename, &filenam);
- if (!ret) {
+ filenam = getname32 (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
set_fs (KERNEL_DS);
ret = sys_newlstat(filenam, &s);
set_fs (old_fs);
@@ -1240,12 +1334,12 @@
struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
- s->dir_mode = s32->dir_mode;
- s->file_mode = s32->file_mode;
- s->gid = s32->gid;
- s->uid = s32->uid;
- memmove (&s->addr, &s32->addr, (((long)&s->uid) - ((long)&s->addr)));
+ s->version = s32->version;
s->mounted_uid = s32->mounted_uid;
+ s->uid = s32->uid;
+ s->gid = s32->gid;
+ s->file_mode = s32->file_mode;
+ s->dir_mode = s32->dir_mode;
return raw_data;
}
@@ -1345,8 +1439,8 @@
}
struct rusage32 {
- struct timeval ru_utime;
- struct timeval ru_stime;
+ struct timeval32 ru_utime;
+ struct timeval32 ru_stime;
s32 ru_maxrss;
s32 ru_ixrss;
s32 ru_idrss;
@@ -1704,7 +1798,7 @@
s32 constant;
s32 precision;
s32 tolerance;
- struct timeval time;
+ struct timeval32 time;
s32 tick;
s32 ppsfreq;
s32 jitter;
@@ -2302,6 +2396,7 @@
if(!error) {
fprs_write(0);
regs->fprs = 0;
+ regs->tstate &= ~TSTATE_PEF;
}
out:
unlock_kernel();
@@ -2361,8 +2456,12 @@
case QM_MODULES:
case QM_REFS:
case QM_DEPS:
- if (name_user && (ret = getname32 (name_user, &usernam)))
- return ret;
+ if (name_user) {
+ usernam = getname32 (name_user);
+ ret = PTR_ERR(usernam);
+ if (IS_ERR(usernam))
+ return ret;
+ }
buff = kmalloc (bufsiz, GFP_KERNEL);
if (!buff) {
if (name_user) putname32 (usernam);
@@ -2423,8 +2522,12 @@
if (name_user) putname32 (usernam);
return ret;
case QM_INFO:
- if (name_user && (ret = getname32 (name_user, &usernam)))
- return ret;
+ if (name_user) {
+ usernam = getname32 (name_user);
+ ret = PTR_ERR(usernam);
+ if (IS_ERR(usernam))
+ return ret;
+ }
set_fs (KERNEL_DS);
ret = sys_query_module (usernam, which, (char *)&mi, sizeof (mi), &val);
set_fs (old_fs);
@@ -2782,4 +2885,107 @@
if(kres)
kfree(kres);
return err;
+}
+
+/* Translations due to time_t size differences. Which affects all
+ sorts of things, like timeval and itimerval. */
+
+extern struct timezone sys_tz;
+extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+
+asmlinkage int sys32_gettimeofday(u32 tv, u32 tz)
+{
+ if (tv) {
+ struct timeval ktv;
+ do_gettimeofday(&ktv);
+ if (put_tv32((struct timeval32 *)A(tv), &ktv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_to_user((void*)A(tz), &sys_tz, sizeof(sys_tz)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage int sys32_settimeofday(u32 tv, u32 tz)
+{
+ struct timeval ktv;
+ struct timezone ktz;
+
+ if (tv) {
+ if (get_tv32(&ktv, (struct timeval32 *)A(tv)))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_from_user(&ktz, (void*)A(tz), sizeof(ktz)))
+ return -EFAULT;
+ }
+
+ return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
+}
+
+extern int do_getitimer(int which, struct itimerval *value);
+
+asmlinkage int sys32_getitimer(int which, u32 it)
+{
+ struct itimerval kit;
+ int error;
+
+ error = do_getitimer(which, &kit);
+ if (!error && put_it32((struct itimerval32 *)A(it), &kit))
+ error = -EFAULT;
+
+ return error;
+}
+
+extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
+
+asmlinkage int sys32_setitimer(int which, u32 in, u32 out)
+{
+ struct itimerval kin, kout;
+ int error;
+
+ if (in) {
+ if (get_it32(&kin, (struct itimerval32 *)A(in)))
+ return -EFAULT;
+ } else
+ memset(&kin, 0, sizeof(kin));
+
+ error = do_setitimer(which, &kin, out ? &kout : NULL);
+ if (error || !out)
+ return error;
+ if (put_it32((struct itimerval32 *)A(out), &kout))
+ return -EFAULT;
+
+ return 0;
+
+}
+
+asmlinkage int sys_utimes(char *, struct timeval *);
+
+asmlinkage int sys32_utimes(u32 filename, u32 tvs)
+{
+ char *kfilename;
+ struct timeval ktvs[2];
+ unsigned long old_fs;
+ int ret;
+
+ kfilename = getname32(filename);
+ ret = PTR_ERR(kfilename);
+ if (!IS_ERR(kfilename)) {
+ if (tvs) {
+ if (get_tv32(&ktvs[0], (struct timeval32 *)A(tvs)) ||
+ get_tv32(&ktvs[1], 1+(struct timeval32 *)A(tvs)))
+ return -EFAULT;
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_utimes(kfilename, &ktvs[0]);
+ set_fs(old_fs);
+
+ putname32(kfilename);
+ }
+ return ret;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov