diff options
Diffstat (limited to 'arch/sparc64/kernel/sys_sparc32.c')
-rw-r--r-- | arch/sparc64/kernel/sys_sparc32.c | 440 |
1 files changed, 287 insertions, 153 deletions
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index caad42736..a5043b3ac 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.77 1998/03/29 10:10:50 davem Exp $ +/* $Id: sys_sparc32.c,v 1.90 1998/07/29 16:32:30 jj Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -58,27 +58,10 @@ */ #define A(x) ((unsigned long)x) -extern char * getname_quicklist; -extern int getname_quickcount; -extern struct semaphore getname_quicklock; - -/* 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); + res = (char *)__get_free_page(GFP_KERNEL); return res; } @@ -845,9 +828,6 @@ asmlinkage long sys32_readv(int fd, u32 vector, u32 count) ret = do_readv_writev32(VERIFY_WRITE, file, (struct iovec32 *)A(vector), count); - if (ret > 0) - current->io_usage += ret; - out: fput(file); bad_file: @@ -872,9 +852,6 @@ asmlinkage long sys32_writev(int fd, u32 vector, u32 count) ret = do_readv_writev32(VERIFY_READ, file, (struct iovec32 *)A(vector), count); up(&file->f_dentry->d_inode->i_sem); - if (ret > 0) - current->io_usage += ret; - out: fput(file); bad_file: @@ -1148,6 +1125,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x) put_user(sec, &tvp->tv_sec); put_user(usec, &tvp->tv_usec); } + current->timeout = 0; if (ret < 0) goto out; @@ -1247,27 +1225,6 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf) return ret; } -extern asmlinkage int sys_xstat(int ver, char *filename, struct stat64 * statbuf); - -asmlinkage int sys32_xstat(int ver, u32 file, u32 statbuf) -{ - switch (ver & __XSTAT_VER_MASK) { - case __XSTAT_VER_1: - switch (ver & __XSTAT_VER_TYPEMASK) { - case __XSTAT_VER_XSTAT: - return sys32_newstat(file, statbuf); - case __XSTAT_VER_LXSTAT: - return sys32_newlstat(file, statbuf); - case __XSTAT_VER_FXSTAT: - return sys32_newfstat(file, statbuf); - } - return -EINVAL; - case __XSTAT_VER_2: - return sys_xstat(ver, (char *)A(file), (struct stat64 *)A(statbuf)); - } - return -EINVAL; -} - extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2); asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2) @@ -2662,7 +2619,8 @@ asmlinkage int sparc32_execve(struct pt_regs *regs) if(!error) { fprs_write(0); - regs->fprs = 0; + current->tss.xfsr[0] = 0; + current->tss.fpsaved[0] = 0; regs->tstate &= ~TSTATE_PEF; } out: @@ -2703,119 +2661,274 @@ struct module_info32 { s32 usecount; }; -extern asmlinkage int sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t *ret); +/* Query various bits about modules. */ + +extern long get_mod_name(const char *user_name, char **buf); +extern void put_mod_name(char *buf); +extern struct module *find_module(const char *name); +extern struct module kernel_module; -asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 retv) +static int +qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret) { - char *buff; - mm_segment_t old_fs = get_fs(); - size_t val; - int ret, i, j; - unsigned long *p; - char *usernam = NULL; - int bufsiz = bufsize; - struct module_info mi; - - switch (which) { - case 0: return sys_query_module ((const char *)A(name_user), which, (char *)A(buf), (size_t)bufsize, (size_t *)A(retv)); - case QM_SYMBOLS: - bufsiz <<= 1; - case QM_MODULES: - case QM_REFS: - case QM_DEPS: - 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); - return -ENOMEM; + struct module *mod; + size_t nmod, space, len; + + nmod = space = 0; + + for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) { + len = strlen(mod->name)+1; + if (len > bufsize) + goto calc_space_needed; + if (copy_to_user(buf, mod->name, len)) + return -EFAULT; + buf += len; + bufsize -= len; + space += len; + } + + if (put_user(nmod, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + space += len; + while ((mod = mod->next) != &kernel_module) + space += strlen(mod->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static int +qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + size_t i, space, len; + + if (mod == &kernel_module) + return -EINVAL; + if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) + if (put_user(0, ret)) + return -EFAULT; + else + return 0; + + space = 0; + for (i = 0; i < mod->ndeps; ++i) { + const char *dep_name = mod->deps[i].dep->name; + + len = strlen(dep_name)+1; + if (len > bufsize) + goto calc_space_needed; + if (copy_to_user(buf, dep_name, len)) + return -EFAULT; + buf += len; + bufsize -= len; + space += len; + } + + if (put_user(i, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + space += len; + while (++i < mod->ndeps) + space += strlen(mod->deps[i].dep->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static int +qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + size_t nrefs, space, len; + struct module_ref *ref; + + if (mod == &kernel_module) + return -EINVAL; + if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) + if (put_user(0, ret)) + return -EFAULT; + else + return 0; + + space = 0; + for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) { + const char *ref_name = ref->ref->name; + + len = strlen(ref_name)+1; + if (len > bufsize) + goto calc_space_needed; + if (copy_to_user(buf, ref_name, len)) + return -EFAULT; + buf += len; + bufsize -= len; + space += len; + } + + if (put_user(nrefs, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + space += len; + while ((ref = ref->next_ref) != NULL) + space += strlen(ref->ref->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static inline int +qm_symbols(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + size_t i, space, len; + struct module_symbol *s; + char *strings; + unsigned *vals; + + if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) + if (put_user(0, ret)) + return -EFAULT; + else + return 0; + + space = mod->nsyms * 2*sizeof(u32); + + i = len = 0; + s = mod->syms; + + if (space > bufsize) + goto calc_space_needed; + + if (!access_ok(VERIFY_WRITE, buf, space)) + return -EFAULT; + + bufsize -= space; + vals = (unsigned *)buf; + strings = buf+space; + + for (; i < mod->nsyms ; ++i, ++s, vals += 2) { + len = strlen(s->name)+1; + if (len > bufsize) + goto calc_space_needed; + + if (copy_to_user(strings, s->name, len) + || __put_user(s->value, vals+0) + || __put_user(space, vals+1)) + return -EFAULT; + + strings += len; + bufsize -= len; + space += len; + } + + if (put_user(i, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + for (; i < mod->nsyms; ++i, ++s) + space += strlen(s->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static inline int +qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + int error = 0; + + if (mod == &kernel_module) + return -EINVAL; + + if (sizeof(struct module_info32) <= bufsize) { + struct module_info32 info; + info.addr = (unsigned long)mod; + info.size = mod->size; + info.flags = mod->flags; + info.usecount = (mod_member_present(mod, can_unload) + && mod->can_unload ? -1 : mod->usecount); + + if (copy_to_user(buf, &info, sizeof(struct module_info32))) + return -EFAULT; + } else + error = -ENOSPC; + + if (put_user(sizeof(struct module_info32), ret)) + return -EFAULT; + + return error; +} + +asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 ret) +{ + struct module *mod; + int err; + + lock_kernel(); + if (name_user == 0) + mod = &kernel_module; + else { + long namelen; + char *name; + + if ((namelen = get_mod_name((char *)A(name_user), &name)) < 0) { + err = namelen; + goto out; } -qmsym_toshort: - set_fs (KERNEL_DS); - ret = sys_query_module (usernam, which, buff, bufsiz, &val); - set_fs (old_fs); - if (which != QM_SYMBOLS) { - if (ret == -ENOSPC || !ret) { - if (put_user (val, (__kernel_size_t32 *)A(retv))) - ret = -EFAULT; - } - if (!ret) { - if (copy_to_user ((char *)A(buf), buff, bufsize)) - ret = -EFAULT; - } - } else { - if (ret == -ENOSPC) { - if (put_user (2 * val, (__kernel_size_t32 *)A(retv))) - ret = -EFAULT; - } - p = (unsigned long *)buff; - if (!ret) { - if (put_user (val, (__kernel_size_t32 *)A(retv))) - ret = -EFAULT; - } - if (!ret) { - j = val * 8; - for (i = 0; i < val; i++, p += 2) { - if (bufsize < (2 * sizeof (u32))) { - bufsiz = 0; - goto qmsym_toshort; - } - if (put_user (p[0], (u32 *)A(buf)) || - __put_user (p[1] - j, (((u32 *)A(buf))+1))) { - ret = -EFAULT; - break; - } - bufsize -= (2 * sizeof (u32)); - buf += (2 * sizeof (u32)); - } - } - if (!ret && val) { - char *strings = buff + ((unsigned long *)buff)[1]; - j = *(p - 1) - ((unsigned long *)buff)[1]; - j = j + strlen (strings + j) + 1; - if (bufsize < j) { - bufsiz = 0; - goto qmsym_toshort; - } - if (copy_to_user ((char *)A(buf), strings, j)) - ret = -EFAULT; - } + err = -ENOENT; + if (namelen == 0) + mod = &kernel_module; + else if ((mod = find_module(name)) == NULL) { + put_mod_name(name); + goto out; } - kfree (buff); - if (name_user) putname32 (usernam); - return ret; + put_mod_name(name); + } + + switch (which) + { + case 0: + err = 0; + break; + case QM_MODULES: + err = qm_modules((char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + break; + case QM_DEPS: + err = qm_deps(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + break; + case QM_REFS: + err = qm_refs(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + break; + case QM_SYMBOLS: + err = qm_symbols(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + break; case QM_INFO: - 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); - if (!ret) { - if (put_user (sizeof (struct module_info32), (__kernel_size_t32 *)A(retv))) - ret = -EFAULT; - else if (bufsize < sizeof (struct module_info32)) - ret = -ENOSPC; - } - if (!ret) { - if (put_user (mi.addr, &(((struct module_info32 *)A(buf))->addr)) || - __put_user (mi.size, &(((struct module_info32 *)A(buf))->size)) || - __put_user (mi.flags, &(((struct module_info32 *)A(buf))->flags)) || - __put_user (mi.usecount, &(((struct module_info32 *)A(buf))->usecount))) - ret = -EFAULT; - } - if (name_user) putname32 (usernam); - return ret; + err = qm_info(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + break; default: - return -EINVAL; + err = -EINVAL; + break; } +out: + unlock_kernel(); + return err; } struct kernel_sym32 { @@ -3356,3 +3469,24 @@ asmlinkage int sys32_personality(unsigned long personality) ret = PER_LINUX; return ret; } + +extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count); + +asmlinkage int sys32_sendfile(int out_fd, int in_fd, u32 offset, s32 count) +{ + mm_segment_t old_fs = get_fs(); + int ret; + off_t of; + + if (offset && get_user(of, (__kernel_off_t32 *)A(offset))) + return -EFAULT; + + set_fs(KERNEL_DS); + ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); + set_fs(old_fs); + + if (!ret && offset && put_user(of, (__kernel_off_t32 *)A(offset))) + return -EFAULT; + + return ret; +} |