Skip site navigation (1)Skip section navigation (2)
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>