Date: Mon, 6 Jun 2005 15:56:37 +0300 (EEST) From: Andriy Gapon <avg@icyb.net.ua> To: FreeBSD-gnats-submit@FreeBSD.org Subject: kern/81951: [patch] linux emulation: getpriority() returns incorrect value Message-ID: <200506061256.j56CubHG002660@oddity.topspin.kiev.ua> Resent-Message-ID: <200506061300.j56D06eH084281@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 81951 >Category: kern >Synopsis: [patch] linux emulation: getpriority() returns incorrect value >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Mon Jun 06 13:00:03 GMT 2005 >Closed-Date: >Last-Modified: >Originator: Andriy Gapon >Release: FreeBSD 5.4-RELEASE i386 >Organization: >Environment: System: FreeBSD 5.4-RELEASE #1: Sat May 14 17:26:13 EEST 2005 i386 FreeBSD-CURRENT linux_base-8-8.0_6 >Description: As far as I could understand from Linux source and documentation Linux getpriority(2) syscall returns values in range [1..40] and glibc counterpart converts the return value using 20 - X formula, so that a caller receives return values in range [-20..19] FreeBSD linux emualtion does not emulate getpriority(2) syscall and FreeBSD syscall is invoked directly. The FreeBSD syscall returns values in range [-20..20], so after glibc convertion user recives incorrect priority level. This problem impacts Linux applications that change their priority levels using relative increments instead of setting an absolute value, especially affected those applications that use nice(3) function that is implemented using getpriority(2)+setpriority(2). >How-To-Repeat: 1. enable linux emulation 2. Compile the following program using /compat/linux/usr/bin/gcc 3. execute the compiled program 4. see that after setpriority(,,1) getpriority returns 19 /** start of test.c **/ #include <sys/resource.h> int main() { int p; p = getpriority(PRIO_PROCESS, 0); printf("get prio = %d\n", p); setpriority(PRIO_PROCESS, 0, 1); p = getpriority(PRIO_PROCESS, 0); printf("get prio = %d\n", p); return 0; } /*** end of test.c ***/ >Fix: the following patch should fix the problem. it probably contains some unneeded extra lines due to my inexperience with system call handling. it also will return values in range [0..40] instead of real linux [1..40] but that should not cause any problems in practice, at least it has not for me. diff -u -r -N sys/i386/linux.orig/init_sysent.c sys/i386/linux/init_sysent.c --- sys/i386/linux.orig/init_sysent.c Thu Jan 1 03:00:00 1970 +++ sys/i386/linux/init_sysent.c Mon Jun 6 15:06:03 2005 @@ -0,0 +1,5 @@ +/* + * System call switch table. + * + * DO NOT EDIT-- this file is automatically generated. + * $FreeBSD$ diff -u -r -N sys/i386/linux.orig/linux_proto.h sys/i386/linux/linux_proto.h --- sys/i386/linux.orig/linux_proto.h Mon Jun 6 14:48:39 2005 +++ sys/i386/linux/linux_proto.h Mon Jun 6 15:11:02 2005 @@ -2,7 +2,7 @@ * System call prototypes. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/i386/linux/linux_proto.h,v 1.59.2.2 2005/03/31 22:24:24 sobomax Exp $ + * $FreeBSD$ * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.56.2.2 2005/03/31 22:17:42 sobomax Exp */ @@ -277,6 +277,10 @@ char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char length_l_[PADL_(l_ulong)]; l_ulong length; char length_r_[PADR_(l_ulong)]; }; +struct linux_getpriority_args { + char which_l_[PADL_(int)]; int which; char which_r_[PADR_(int)]; + char who_l_[PADL_(int)]; int who; char who_r_[PADR_(int)]; +}; struct linux_statfs_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char buf_l_[PADL_(struct l_statfs_buf *)]; struct l_statfs_buf * buf; char buf_r_[PADR_(struct l_statfs_buf *)]; @@ -745,6 +749,7 @@ int linux_readdir(struct thread *, struct linux_readdir_args *); int linux_mmap(struct thread *, struct linux_mmap_args *); int linux_truncate(struct thread *, struct linux_truncate_args *); +int linux_getpriority(struct thread *, struct linux_getpriority_args *); int linux_statfs(struct thread *, struct linux_statfs_args *); int linux_fstatfs(struct thread *, struct linux_fstatfs_args *); int linux_ioperm(struct thread *, struct linux_ioperm_args *); diff -u -r -N sys/i386/linux.orig/linux_syscall.h sys/i386/linux/linux_syscall.h --- sys/i386/linux.orig/linux_syscall.h Mon Jun 6 14:48:39 2005 +++ sys/i386/linux/linux_syscall.h Mon Jun 6 15:11:02 2005 @@ -2,7 +2,7 @@ * System call numbers. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/i386/linux/linux_syscall.h,v 1.53.2.2 2005/03/31 22:24:24 sobomax Exp $ + * $FreeBSD$ * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.56.2.2 2005/03/31 22:17:42 sobomax Exp */ @@ -93,7 +93,7 @@ #define LINUX_SYS_oftruncate 93 #define LINUX_SYS_fchmod 94 #define LINUX_SYS_fchown 95 -#define LINUX_SYS_getpriority 96 +#define LINUX_SYS_linux_getpriority 96 #define LINUX_SYS_setpriority 97 #define LINUX_SYS_linux_statfs 99 #define LINUX_SYS_linux_fstatfs 100 diff -u -r -N sys/i386/linux.orig/linux_sysent.c sys/i386/linux/linux_sysent.c --- sys/i386/linux.orig/linux_sysent.c Mon Jun 6 14:48:39 2005 +++ sys/i386/linux/linux_sysent.c Mon Jun 6 15:11:02 2005 @@ -2,7 +2,7 @@ * System call switch table. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/i386/linux/linux_sysent.c,v 1.60.2.2 2005/03/31 22:24:24 sobomax Exp $ + * $FreeBSD$ * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.56.2.2 2005/03/31 22:17:42 sobomax Exp */ @@ -115,7 +115,7 @@ { AS(oftruncate_args), (sy_call_t *)oftruncate }, /* 93 = oftruncate */ { AS(fchmod_args), (sy_call_t *)fchmod }, /* 94 = fchmod */ { AS(fchown_args), (sy_call_t *)fchown }, /* 95 = fchown */ - { SYF_MPSAFE | AS(getpriority_args), (sy_call_t *)getpriority }, /* 96 = getpriority */ + { SYF_MPSAFE | AS(linux_getpriority_args), (sy_call_t *)linux_getpriority }, /* 96 = linux_getpriority */ { SYF_MPSAFE | AS(setpriority_args), (sy_call_t *)setpriority }, /* 97 = setpriority */ { 0, (sy_call_t *)nosys }, /* 98 = profil */ { AS(linux_statfs_args), (sy_call_t *)linux_statfs }, /* 99 = linux_statfs */ diff -u -r -N sys/i386/linux.orig/syscalls.c sys/i386/linux/syscalls.c --- sys/i386/linux.orig/syscalls.c Thu Jan 1 03:00:00 1970 +++ sys/i386/linux/syscalls.c Mon Jun 6 15:06:03 2005 @@ -0,0 +1,5 @@ +/* + * System call names. + * + * DO NOT EDIT-- this file is automatically generated. + * $FreeBSD$ diff -u -r -N sys/i386/linux.orig/syscalls.master sys/i386/linux/syscalls.master --- sys/i386/linux.orig/syscalls.master Mon Jun 6 14:48:39 2005 +++ sys/i386/linux/syscalls.master Mon Jun 6 15:10:58 2005 @@ -140,7 +140,7 @@ 93 NOPROTO { int oftruncate(int fd, long length); } 94 NOPROTO { int fchmod(int fd, int mode); } 95 NOPROTO { int fchown(int fd, int uid, int gid); } -96 MNOPROTO { int getpriority(int which, int who); } +96 MSTD { int linux_getpriority(int which, int who); } 97 MNOPROTO { int setpriority(int which, int who, int prio); } 98 UNIMPL profil 99 STD { int linux_statfs(char *path, struct l_statfs_buf *buf); } --- sys/compat/linux/linux_misc.c.orig Mon Jun 6 14:57:36 2005 +++ sys/compat/linux/linux_misc.c Mon Jun 6 15:25:43 2005 @@ -1053,6 +1053,19 @@ #endif /*!__alpha__*/ int +linux_getpriority(struct thread *td, struct linux_getpriority_args *args) +{ + struct getpriority_args bsd_args; + int error; + + bsd_args.which = args->which; + bsd_args.who = args->who; + error = getpriority(td, &bsd_args); + td->td_retval[0] = 20 - td->td_retval[0]; + return error; +} + +int linux_setgroups(struct thread *td, struct linux_setgroups_args *args) { struct ucred *newcred, *oldcred; >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200506061256.j56CubHG002660>