aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle McMartin <kyle@parisc-linux.org>2007-02-10 04:46:00 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-11 13:51:32 -0500
commitd4d23add3abcd18d8021b99f230df608ccb2f007 (patch)
tree756c5a7d21a9f5a25f10bfcec40c01aecc596c2f
parent72fd4a35a824331d7a0f4168d7576502d95d34b3 (diff)
[PATCH] Common compat_sys_sysinfo
I noticed that almost all architectures implemented exactly the same sys32_sysinfo... except parisc, where a bug was to be found in handling of the uptime. So let's remove a whole whack of code for fun and profit. Cribbed compat_sys_sysinfo from x86_64's implementation, since I figured it would be the best tested. This patch incorporates Arnd's suggestion of not using set_fs/get_fs, but instead extracting out the common code from sys_sysinfo. Cc: Christoph Hellwig <hch@infradead.org> Cc: <linux-arch@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/ia64/ia32/ia32_entry.S2
-rw-r--r--arch/ia64/ia32/sys_ia32.c68
-rw-r--r--arch/mips/kernel/linux32.c44
-rw-r--r--arch/mips/kernel/scall64-n32.S2
-rw-r--r--arch/mips/kernel/scall64-o32.S2
-rw-r--r--arch/parisc/kernel/sys_parisc32.c64
-rw-r--r--arch/parisc/kernel/syscall_table.S2
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c67
-rw-r--r--arch/s390/kernel/compat_linux.c45
-rw-r--r--arch/s390/kernel/compat_wrapper.S6
-rw-r--r--arch/s390/kernel/syscalls.S2
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c64
-rw-r--r--arch/sparc64/kernel/systbls.S2
-rw-r--r--arch/x86_64/ia32/ia32entry.S2
-rw-r--r--arch/x86_64/ia32/sys_ia32.c66
-rw-r--r--include/linux/kernel.h3
-rw-r--r--kernel/compat.c66
-rw-r--r--kernel/timer.c58
18 files changed, 112 insertions, 453 deletions
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
index a32cd59b81ed..687e5fdc9683 100644
--- a/arch/ia64/ia32/ia32_entry.S
+++ b/arch/ia64/ia32/ia32_entry.S
@@ -326,7 +326,7 @@ ia32_syscall_table:
326 data8 sys_ni_syscall 326 data8 sys_ni_syscall
327 data8 compat_sys_wait4 327 data8 compat_sys_wait4
328 data8 sys_swapoff /* 115 */ 328 data8 sys_swapoff /* 115 */
329 data8 sys32_sysinfo 329 data8 compat_sys_sysinfo
330 data8 sys32_ipc 330 data8 sys32_ipc
331 data8 sys_fsync 331 data8 sys_fsync
332 data8 sys32_sigreturn 332 data8 sys32_sigreturn
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index 957681c39ad9..d430d36ae49d 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -2209,74 +2209,6 @@ sys32_fstat64 (unsigned int fd, struct stat64 __user *statbuf)
2209 return ret; 2209 return ret;
2210} 2210}
2211 2211
2212struct sysinfo32 {
2213 s32 uptime;
2214 u32 loads[3];
2215 u32 totalram;
2216 u32 freeram;
2217 u32 sharedram;
2218 u32 bufferram;
2219 u32 totalswap;
2220 u32 freeswap;
2221 u16 procs;
2222 u16 pad;
2223 u32 totalhigh;
2224 u32 freehigh;
2225 u32 mem_unit;
2226 char _f[8];
2227};
2228
2229asmlinkage long
2230sys32_sysinfo (struct sysinfo32 __user *info)
2231{
2232 struct sysinfo s;
2233 long ret, err;
2234 int bitcount = 0;
2235 mm_segment_t old_fs = get_fs();
2236
2237 set_fs(KERNEL_DS);
2238 ret = sys_sysinfo((struct sysinfo __user *) &s);
2239 set_fs(old_fs);
2240 /* Check to see if any memory value is too large for 32-bit and
2241 * scale down if needed.
2242 */
2243 if ((s.totalram >> 32) || (s.totalswap >> 32)) {
2244 while (s.mem_unit < PAGE_SIZE) {
2245 s.mem_unit <<= 1;
2246 bitcount++;
2247 }
2248 s.totalram >>= bitcount;
2249 s.freeram >>= bitcount;
2250 s.sharedram >>= bitcount;
2251 s.bufferram >>= bitcount;
2252 s.totalswap >>= bitcount;
2253 s.freeswap >>= bitcount;
2254 s.totalhigh >>= bitcount;
2255 s.freehigh >>= bitcount;
2256 }
2257
2258 if (!access_ok(VERIFY_WRITE, info, sizeof(*info)))
2259 return -EFAULT;
2260
2261 err = __put_user(s.uptime, &info->uptime);
2262 err |= __put_user(s.loads[0], &info->loads[0]);
2263 err |= __put_user(s.loads[1], &info->loads[1]);
2264 err |= __put_user(s.loads[2], &info->loads[2]);
2265 err |= __put_user(s.totalram, &info->totalram);
2266 err |= __put_user(s.freeram, &info->freeram);
2267 err |= __put_user(s.sharedram, &info->sharedram);
2268 err |= __put_user(s.bufferram, &info->bufferram);
2269 err |= __put_user(s.totalswap, &info->totalswap);
2270 err |= __put_user(s.freeswap, &info->freeswap);
2271 err |= __put_user(s.procs, &info->procs);
2272 err |= __put_user (s.totalhigh, &info->totalhigh);
2273 err |= __put_user (s.freehigh, &info->freehigh);
2274 err |= __put_user (s.mem_unit, &info->mem_unit);
2275 if (err)
2276 return -EFAULT;
2277 return ret;
2278}
2279
2280asmlinkage long 2212asmlinkage long
2281sys32_sched_rr_get_interval (pid_t pid, struct compat_timespec __user *interval) 2213sys32_sched_rr_get_interval (pid_t pid, struct compat_timespec __user *interval)
2282{ 2214{
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 0b8ce59429a8..ca7ad78f4def 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -193,50 +193,6 @@ sysn32_waitid(int which, compat_pid_t pid,
193 return ret; 193 return ret;
194} 194}
195 195
196struct sysinfo32 {
197 s32 uptime;
198 u32 loads[3];
199 u32 totalram;
200 u32 freeram;
201 u32 sharedram;
202 u32 bufferram;
203 u32 totalswap;
204 u32 freeswap;
205 u16 procs;
206 u32 totalhigh;
207 u32 freehigh;
208 u32 mem_unit;
209 char _f[8];
210};
211
212asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info)
213{
214 struct sysinfo s;
215 int ret, err;
216 mm_segment_t old_fs = get_fs ();
217
218 set_fs (KERNEL_DS);
219 ret = sys_sysinfo((struct sysinfo __user *)&s);
220 set_fs (old_fs);
221 err = put_user (s.uptime, &info->uptime);
222 err |= __put_user (s.loads[0], &info->loads[0]);
223 err |= __put_user (s.loads[1], &info->loads[1]);
224 err |= __put_user (s.loads[2], &info->loads[2]);
225 err |= __put_user (s.totalram, &info->totalram);
226 err |= __put_user (s.freeram, &info->freeram);
227 err |= __put_user (s.sharedram, &info->sharedram);
228 err |= __put_user (s.bufferram, &info->bufferram);
229 err |= __put_user (s.totalswap, &info->totalswap);
230 err |= __put_user (s.freeswap, &info->freeswap);
231 err |= __put_user (s.procs, &info->procs);
232 err |= __put_user (s.totalhigh, &info->totalhigh);
233 err |= __put_user (s.freehigh, &info->freehigh);
234 err |= __put_user (s.mem_unit, &info->mem_unit);
235 if (err)
236 return -EFAULT;
237 return ret;
238}
239
240#define RLIM_INFINITY32 0x7fffffff 196#define RLIM_INFINITY32 0x7fffffff
241#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) 197#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
242 198
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 39add2341aa2..ee8802b59758 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -217,7 +217,7 @@ EXPORT(sysn32_call_table)
217 PTR sys32_gettimeofday 217 PTR sys32_gettimeofday
218 PTR compat_sys_getrlimit /* 6095 */ 218 PTR compat_sys_getrlimit /* 6095 */
219 PTR compat_sys_getrusage 219 PTR compat_sys_getrusage
220 PTR sys32_sysinfo 220 PTR compat_sys_sysinfo
221 PTR compat_sys_times 221 PTR compat_sys_times
222 PTR sys32_ptrace 222 PTR sys32_ptrace
223 PTR sys_getuid /* 6100 */ 223 PTR sys_getuid /* 6100 */
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index c58b8e0105ea..c5f590ca99b0 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -321,7 +321,7 @@ sys_call_table:
321 PTR sys_ni_syscall /* sys_vm86 */ 321 PTR sys_ni_syscall /* sys_vm86 */
322 PTR compat_sys_wait4 322 PTR compat_sys_wait4
323 PTR sys_swapoff /* 4115 */ 323 PTR sys_swapoff /* 4115 */
324 PTR sys32_sysinfo 324 PTR compat_sys_sysinfo
325 PTR sys32_ipc 325 PTR sys32_ipc
326 PTR sys_fsync 326 PTR sys_fsync
327 PTR sys32_sigreturn 327 PTR sys32_sigreturn
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index 29be4377aca6..ce3245f87fdd 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -579,70 +579,6 @@ asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *off
579} 579}
580 580
581 581
582struct sysinfo32 {
583 s32 uptime;
584 u32 loads[3];
585 u32 totalram;
586 u32 freeram;
587 u32 sharedram;
588 u32 bufferram;
589 u32 totalswap;
590 u32 freeswap;
591 unsigned short procs;
592 u32 totalhigh;
593 u32 freehigh;
594 u32 mem_unit;
595 char _f[12];
596};
597
598/* We used to call sys_sysinfo and translate the result. But sys_sysinfo
599 * undoes the good work done elsewhere, and rather than undoing the
600 * damage, I decided to just duplicate the code from sys_sysinfo here.
601 */
602
603asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info)
604{
605 struct sysinfo val;
606 int err;
607 unsigned long seq;
608
609 /* We don't need a memset here because we copy the
610 * struct to userspace once element at a time.
611 */
612
613 do {
614 seq = read_seqbegin(&xtime_lock);
615 val.uptime = jiffies / HZ;
616
617 val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
618 val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
619 val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
620
621 val.procs = nr_threads;
622 } while (read_seqretry(&xtime_lock, seq));
623
624
625 si_meminfo(&val);
626 si_swapinfo(&val);
627
628 err = put_user (val.uptime, &info->uptime);
629 err |= __put_user (val.loads[0], &info->loads[0]);
630 err |= __put_user (val.loads[1], &info->loads[1]);
631 err |= __put_user (val.loads[2], &info->loads[2]);
632 err |= __put_user (val.totalram, &info->totalram);
633 err |= __put_user (val.freeram, &info->freeram);
634 err |= __put_user (val.sharedram, &info->sharedram);
635 err |= __put_user (val.bufferram, &info->bufferram);
636 err |= __put_user (val.totalswap, &info->totalswap);
637 err |= __put_user (val.freeswap, &info->freeswap);
638 err |= __put_user (val.procs, &info->procs);
639 err |= __put_user (val.totalhigh, &info->totalhigh);
640 err |= __put_user (val.freehigh, &info->freehigh);
641 err |= __put_user (val.mem_unit, &info->mem_unit);
642 return err ? -EFAULT : 0;
643}
644
645
646/* lseek() needs a wrapper because 'offset' can be negative, but the top 582/* lseek() needs a wrapper because 'offset' can be negative, but the top
647 * half of the argument has been zeroed by syscall.S. 583 * half of the argument has been zeroed by syscall.S.
648 */ 584 */
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 701d66a596e8..be8eb9a0d24a 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -197,7 +197,7 @@
197 /* struct rusage contains longs... */ 197 /* struct rusage contains longs... */
198 ENTRY_COMP(wait4) 198 ENTRY_COMP(wait4)
199 ENTRY_SAME(swapoff) /* 115 */ 199 ENTRY_SAME(swapoff) /* 115 */
200 ENTRY_DIFF(sysinfo) 200 ENTRY_COMP(sysinfo)
201 ENTRY_SAME(shutdown) 201 ENTRY_SAME(shutdown)
202 ENTRY_SAME(fsync) 202 ENTRY_SAME(fsync)
203 ENTRY_SAME(madvise) 203 ENTRY_SAME(madvise)
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index 03a2a2f30d66..673e8d9df7f5 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -198,73 +198,6 @@ static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
198 __put_user(i->tv_usec, &o->tv_usec))); 198 __put_user(i->tv_usec, &o->tv_usec)));
199} 199}
200 200
201struct sysinfo32 {
202 s32 uptime;
203 u32 loads[3];
204 u32 totalram;
205 u32 freeram;
206 u32 sharedram;
207 u32 bufferram;
208 u32 totalswap;
209 u32 freeswap;
210 unsigned short procs;
211 unsigned short pad;
212 u32 totalhigh;
213 u32 freehigh;
214 u32 mem_unit;
215 char _f[20-2*sizeof(int)-sizeof(int)];
216};
217
218asmlinkage long compat_sys_sysinfo(struct sysinfo32 __user *info)
219{
220 struct sysinfo s;
221 int ret, err;
222 int bitcount=0;
223 mm_segment_t old_fs = get_fs ();
224
225 /* The __user cast is valid due to set_fs() */
226 set_fs (KERNEL_DS);
227 ret = sys_sysinfo((struct sysinfo __user *)&s);
228 set_fs (old_fs);
229
230 /* Check to see if any memory value is too large for 32-bit and
231 * scale down if needed.
232 */
233 if ((s.totalram >> 32) || (s.totalswap >> 32)) {
234 while (s.mem_unit < PAGE_SIZE) {
235 s.mem_unit <<= 1;
236 bitcount++;
237 }
238 s.totalram >>=bitcount;
239 s.freeram >>= bitcount;
240 s.sharedram >>= bitcount;
241 s.bufferram >>= bitcount;
242 s.totalswap >>= bitcount;
243 s.freeswap >>= bitcount;
244 s.totalhigh >>= bitcount;
245 s.freehigh >>= bitcount;
246 }
247
248 err = put_user (s.uptime, &info->uptime);
249 err |= __put_user (s.loads[0], &info->loads[0]);
250 err |= __put_user (s.loads[1], &info->loads[1]);
251 err |= __put_user (s.loads[2], &info->loads[2]);
252 err |= __put_user (s.totalram, &info->totalram);
253 err |= __put_user (s.freeram, &info->freeram);
254 err |= __put_user (s.sharedram, &info->sharedram);
255 err |= __put_user (s.bufferram, &info->bufferram);
256 err |= __put_user (s.totalswap, &info->totalswap);
257 err |= __put_user (s.freeswap, &info->freeswap);
258 err |= __put_user (s.procs, &info->procs);
259 err |= __put_user (s.totalhigh, &info->totalhigh);
260 err |= __put_user (s.freehigh, &info->freehigh);
261 err |= __put_user (s.mem_unit, &info->mem_unit);
262 if (err)
263 return -EFAULT;
264
265 return ret;
266}
267
268 201
269 202
270 203
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 666bb6daa148..664c669b1856 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -398,51 +398,6 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
398 return err; 398 return err;
399} 399}
400 400
401struct sysinfo32 {
402 s32 uptime;
403 u32 loads[3];
404 u32 totalram;
405 u32 freeram;
406 u32 sharedram;
407 u32 bufferram;
408 u32 totalswap;
409 u32 freeswap;
410 unsigned short procs;
411 unsigned short pads;
412 u32 totalhigh;
413 u32 freehigh;
414 unsigned int mem_unit;
415 char _f[8];
416};
417
418asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
419{
420 struct sysinfo s;
421 int ret, err;
422 mm_segment_t old_fs = get_fs ();
423
424 set_fs (KERNEL_DS);
425 ret = sys_sysinfo((struct sysinfo __force __user *) &s);
426 set_fs (old_fs);
427 err = put_user (s.uptime, &info->uptime);
428 err |= __put_user (s.loads[0], &info->loads[0]);
429 err |= __put_user (s.loads[1], &info->loads[1]);
430 err |= __put_user (s.loads[2], &info->loads[2]);
431 err |= __put_user (s.totalram, &info->totalram);
432 err |= __put_user (s.freeram, &info->freeram);
433 err |= __put_user (s.sharedram, &info->sharedram);
434 err |= __put_user (s.bufferram, &info->bufferram);
435 err |= __put_user (s.totalswap, &info->totalswap);
436 err |= __put_user (s.freeswap, &info->freeswap);
437 err |= __put_user (s.procs, &info->procs);
438 err |= __put_user (s.totalhigh, &info->totalhigh);
439 err |= __put_user (s.freehigh, &info->freehigh);
440 err |= __put_user (s.mem_unit, &info->mem_unit);
441 if (err)
442 return -EFAULT;
443 return ret;
444}
445
446asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid, 401asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
447 struct compat_timespec __user *interval) 402 struct compat_timespec __user *interval)
448{ 403{
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 71e54ef0931e..97901296894e 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -517,10 +517,10 @@ sys32_swapoff_wrapper:
517 llgtr %r2,%r2 # const char * 517 llgtr %r2,%r2 # const char *
518 jg sys_swapoff # branch to system call 518 jg sys_swapoff # branch to system call
519 519
520 .globl sys32_sysinfo_wrapper 520 .globl compat_sys_sysinfo_wrapper
521sys32_sysinfo_wrapper: 521compat_sys_sysinfo_wrapper:
522 llgtr %r2,%r2 # struct sysinfo_emu31 * 522 llgtr %r2,%r2 # struct sysinfo_emu31 *
523 jg sys32_sysinfo # branch to system call 523 jg compat_sys_sysinfo # branch to system call
524 524
525 .globl sys32_ipc_wrapper 525 .globl sys32_ipc_wrapper
526sys32_ipc_wrapper: 526sys32_ipc_wrapper:
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index a4ceae3dbcf1..a52c44455bf0 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -124,7 +124,7 @@ NI_SYSCALL /* old "idle" system call */
124NI_SYSCALL /* vm86old for i386 */ 124NI_SYSCALL /* vm86old for i386 */
125SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4_wrapper) 125SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4_wrapper)
126SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper) /* 115 */ 126SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper) /* 115 */
127SYSCALL(sys_sysinfo,sys_sysinfo,sys32_sysinfo_wrapper) 127SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper)
128SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper) 128SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper)
129SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper) 129SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper)
130SYSCALL(sys_sigreturn_glue,sys_sigreturn_glue,sys32_sigreturn_glue) 130SYSCALL(sys_sigreturn_glue,sys_sigreturn_glue,sys32_sigreturn_glue)
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index e27cb71bd8e2..7876a0226285 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -459,70 +459,6 @@ asmlinkage long compat_sys_sysfs(int option, u32 arg1, u32 arg2)
459 return sys_sysfs(option, arg1, arg2); 459 return sys_sysfs(option, arg1, arg2);
460} 460}
461 461
462struct sysinfo32 {
463 s32 uptime;
464 u32 loads[3];
465 u32 totalram;
466 u32 freeram;
467 u32 sharedram;
468 u32 bufferram;
469 u32 totalswap;
470 u32 freeswap;
471 unsigned short procs;
472 unsigned short pad;
473 u32 totalhigh;
474 u32 freehigh;
475 u32 mem_unit;
476 char _f[20-2*sizeof(int)-sizeof(int)];
477};
478
479asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
480{
481 struct sysinfo s;
482 int ret, err;
483 int bitcount = 0;
484 mm_segment_t old_fs = get_fs ();
485
486 set_fs(KERNEL_DS);
487 ret = sys_sysinfo((struct sysinfo __user *) &s);
488 set_fs(old_fs);
489 /* Check to see if any memory value is too large for 32-bit and
490 * scale down if needed.
491 */
492 if ((s.totalram >> 32) || (s.totalswap >> 32)) {
493 while (s.mem_unit < PAGE_SIZE) {
494 s.mem_unit <<= 1;
495 bitcount++;
496 }
497 s.totalram >>= bitcount;
498 s.freeram >>= bitcount;
499 s.sharedram >>= bitcount;
500 s.bufferram >>= bitcount;
501 s.totalswap >>= bitcount;
502 s.freeswap >>= bitcount;
503 s.totalhigh >>= bitcount;
504 s.freehigh >>= bitcount;
505 }
506
507 err = put_user (s.uptime, &info->uptime);
508 err |= __put_user (s.loads[0], &info->loads[0]);
509 err |= __put_user (s.loads[1], &info->loads[1]);
510 err |= __put_user (s.loads[2], &info->loads[2]);
511 err |= __put_user (s.totalram, &info->totalram);
512 err |= __put_user (s.freeram, &info->freeram);
513 err |= __put_user (s.sharedram, &info->sharedram);
514 err |= __put_user (s.bufferram, &info->bufferram);
515 err |= __put_user (s.totalswap, &info->totalswap);
516 err |= __put_user (s.freeswap, &info->freeswap);
517 err |= __put_user (s.procs, &info->procs);
518 err |= __put_user (s.totalhigh, &info->totalhigh);
519 err |= __put_user (s.freehigh, &info->freehigh);
520 err |= __put_user (s.mem_unit, &info->mem_unit);
521 if (err)
522 return -EFAULT;
523 return ret;
524}
525
526asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval) 462asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval)
527{ 463{
528 struct timespec t; 464 struct timespec t;
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 9a8026797ac0..948b7d2d5874 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -61,7 +61,7 @@ sys_call_table32:
61 .word sys32_epoll_wait, sys32_ioprio_set, sys_getppid, sys32_sigaction, sys_sgetmask 61 .word sys32_epoll_wait, sys32_ioprio_set, sys_getppid, sys32_sigaction, sys_sgetmask
62/*200*/ .word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir 62/*200*/ .word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir
63 .word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64 63 .word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64
64/*210*/ .word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, sys32_sysinfo 64/*210*/ .word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, compat_sys_sysinfo
65 .word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex 65 .word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex
66/*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid 66/*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid
67 .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16 67 .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index b4aa875e175b..5f32cf4de5fb 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -515,7 +515,7 @@ ia32_sys_call_table:
515 .quad sys32_vm86_warning /* vm86old */ 515 .quad sys32_vm86_warning /* vm86old */
516 .quad compat_sys_wait4 516 .quad compat_sys_wait4
517 .quad sys_swapoff /* 115 */ 517 .quad sys_swapoff /* 115 */
518 .quad sys32_sysinfo 518 .quad compat_sys_sysinfo
519 .quad sys32_ipc 519 .quad sys32_ipc
520 .quad sys_fsync 520 .quad sys_fsync
521 .quad stub32_sigreturn 521 .quad stub32_sigreturn
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
index c9bac3af29d6..200fdde18d96 100644
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -523,72 +523,6 @@ sys32_sysfs(int option, u32 arg1, u32 arg2)
523 return sys_sysfs(option, arg1, arg2); 523 return sys_sysfs(option, arg1, arg2);
524} 524}
525 525
526struct sysinfo32 {
527 s32 uptime;
528 u32 loads[3];
529 u32 totalram;
530 u32 freeram;
531 u32 sharedram;
532 u32 bufferram;
533 u32 totalswap;
534 u32 freeswap;
535 unsigned short procs;
536 unsigned short pad;
537 u32 totalhigh;
538 u32 freehigh;
539 u32 mem_unit;
540 char _f[20-2*sizeof(u32)-sizeof(int)];
541};
542
543asmlinkage long
544sys32_sysinfo(struct sysinfo32 __user *info)
545{
546 struct sysinfo s;
547 int ret;
548 mm_segment_t old_fs = get_fs ();
549 int bitcount = 0;
550
551 set_fs (KERNEL_DS);
552 ret = sys_sysinfo((struct sysinfo __user *)&s);
553 set_fs (old_fs);
554
555 /* Check to see if any memory value is too large for 32-bit and scale
556 * down if needed
557 */
558 if ((s.totalram >> 32) || (s.totalswap >> 32)) {
559 while (s.mem_unit < PAGE_SIZE) {
560 s.mem_unit <<= 1;
561 bitcount++;
562 }
563 s.totalram >>= bitcount;
564 s.freeram >>= bitcount;
565 s.sharedram >>= bitcount;
566 s.bufferram >>= bitcount;
567 s.totalswap >>= bitcount;
568 s.freeswap >>= bitcount;
569 s.totalhigh >>= bitcount;
570 s.freehigh >>= bitcount;
571 }
572
573 if (!access_ok(VERIFY_WRITE, info, sizeof(struct sysinfo32)) ||
574 __put_user (s.uptime, &info->uptime) ||
575 __put_user (s.loads[0], &info->loads[0]) ||
576 __put_user (s.loads[1], &info->loads[1]) ||
577 __put_user (s.loads[2], &info->loads[2]) ||
578 __put_user (s.totalram, &info->totalram) ||
579 __put_user (s.freeram, &info->freeram) ||
580 __put_user (s.sharedram, &info->sharedram) ||
581 __put_user (s.bufferram, &info->bufferram) ||
582 __put_user (s.totalswap, &info->totalswap) ||
583 __put_user (s.freeswap, &info->freeswap) ||
584 __put_user (s.procs, &info->procs) ||
585 __put_user (s.totalhigh, &info->totalhigh) ||
586 __put_user (s.freehigh, &info->freehigh) ||
587 __put_user (s.mem_unit, &info->mem_unit))
588 return -EFAULT;
589 return 0;
590}
591
592asmlinkage long 526asmlinkage long
593sys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval) 527sys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval)
594{ 528{
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index e1a429ada97f..7e861303cbde 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -313,6 +313,9 @@ static inline int __attribute__ ((format (printf, 1, 2))) pr_debug(const char *
313 (void)__tmp; \ 313 (void)__tmp; \
314}) 314})
315 315
316struct sysinfo;
317extern int do_sysinfo(struct sysinfo *info);
318
316#endif /* __KERNEL__ */ 319#endif /* __KERNEL__ */
317 320
318#define SI_LOAD_SHIFT 16 321#define SI_LOAD_SHIFT 16
diff --git a/kernel/compat.c b/kernel/compat.c
index 6952dd057300..cebb4c28c039 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -1016,3 +1016,69 @@ asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
1016 return sys_migrate_pages(pid, nr_bits + 1, old, new); 1016 return sys_migrate_pages(pid, nr_bits + 1, old, new);
1017} 1017}
1018#endif 1018#endif
1019
1020struct compat_sysinfo {
1021 s32 uptime;
1022 u32 loads[3];
1023 u32 totalram;
1024 u32 freeram;
1025 u32 sharedram;
1026 u32 bufferram;
1027 u32 totalswap;
1028 u32 freeswap;
1029 u16 procs;
1030 u16 pad;
1031 u32 totalhigh;
1032 u32 freehigh;
1033 u32 mem_unit;
1034 char _f[20-2*sizeof(u32)-sizeof(int)];
1035};
1036
1037asmlinkage long
1038compat_sys_sysinfo(struct compat_sysinfo __user *info)
1039{
1040 struct sysinfo s;
1041
1042 do_sysinfo(&s);
1043
1044 /* Check to see if any memory value is too large for 32-bit and scale
1045 * down if needed
1046 */
1047 if ((s.totalram >> 32) || (s.totalswap >> 32)) {
1048 int bitcount = 0;
1049
1050 while (s.mem_unit < PAGE_SIZE) {
1051 s.mem_unit <<= 1;
1052 bitcount++;
1053 }
1054
1055 s.totalram >>= bitcount;
1056 s.freeram >>= bitcount;
1057 s.sharedram >>= bitcount;
1058 s.bufferram >>= bitcount;
1059 s.totalswap >>= bitcount;
1060 s.freeswap >>= bitcount;
1061 s.totalhigh >>= bitcount;
1062 s.freehigh >>= bitcount;
1063 }
1064
1065 if (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo)) ||
1066 __put_user (s.uptime, &info->uptime) ||
1067 __put_user (s.loads[0], &info->loads[0]) ||
1068 __put_user (s.loads[1], &info->loads[1]) ||
1069 __put_user (s.loads[2], &info->loads[2]) ||
1070 __put_user (s.totalram, &info->totalram) ||
1071 __put_user (s.freeram, &info->freeram) ||
1072 __put_user (s.sharedram, &info->sharedram) ||
1073 __put_user (s.bufferram, &info->bufferram) ||
1074 __put_user (s.totalswap, &info->totalswap) ||
1075 __put_user (s.freeswap, &info->freeswap) ||
1076 __put_user (s.procs, &info->procs) ||
1077 __put_user (s.totalhigh, &info->totalhigh) ||
1078 __put_user (s.freehigh, &info->freehigh) ||
1079 __put_user (s.mem_unit, &info->mem_unit))
1080 return -EFAULT;
1081
1082 return 0;
1083}
1084
diff --git a/kernel/timer.c b/kernel/timer.c
index 31ab627df8a0..8533c3796082 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1392,17 +1392,16 @@ asmlinkage long sys_gettid(void)
1392} 1392}
1393 1393
1394/** 1394/**
1395 * sys_sysinfo - fill in sysinfo struct 1395 * do_sysinfo - fill in sysinfo struct
1396 * @info: pointer to buffer to fill 1396 * @info: pointer to buffer to fill
1397 */ 1397 */
1398asmlinkage long sys_sysinfo(struct sysinfo __user *info) 1398int do_sysinfo(struct sysinfo *info)
1399{ 1399{
1400 struct sysinfo val;
1401 unsigned long mem_total, sav_total; 1400 unsigned long mem_total, sav_total;
1402 unsigned int mem_unit, bitcount; 1401 unsigned int mem_unit, bitcount;
1403 unsigned long seq; 1402 unsigned long seq;
1404 1403
1405 memset((char *)&val, 0, sizeof(struct sysinfo)); 1404 memset(info, 0, sizeof(struct sysinfo));
1406 1405
1407 do { 1406 do {
1408 struct timespec tp; 1407 struct timespec tp;
@@ -1422,17 +1421,17 @@ asmlinkage long sys_sysinfo(struct sysinfo __user *info)
1422 tp.tv_nsec = tp.tv_nsec - NSEC_PER_SEC; 1421 tp.tv_nsec = tp.tv_nsec - NSEC_PER_SEC;
1423 tp.tv_sec++; 1422 tp.tv_sec++;
1424 } 1423 }
1425 val.uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0); 1424 info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0);
1426 1425
1427 val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT); 1426 info->loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
1428 val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT); 1427 info->loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
1429 val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT); 1428 info->loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
1430 1429
1431 val.procs = nr_threads; 1430 info->procs = nr_threads;
1432 } while (read_seqretry(&xtime_lock, seq)); 1431 } while (read_seqretry(&xtime_lock, seq));
1433 1432
1434 si_meminfo(&val); 1433 si_meminfo(info);
1435 si_swapinfo(&val); 1434 si_swapinfo(info);
1436 1435
1437 /* 1436 /*
1438 * If the sum of all the available memory (i.e. ram + swap) 1437 * If the sum of all the available memory (i.e. ram + swap)
@@ -1443,11 +1442,11 @@ asmlinkage long sys_sysinfo(struct sysinfo __user *info)
1443 * -Erik Andersen <andersee@debian.org> 1442 * -Erik Andersen <andersee@debian.org>
1444 */ 1443 */
1445 1444
1446 mem_total = val.totalram + val.totalswap; 1445 mem_total = info->totalram + info->totalswap;
1447 if (mem_total < val.totalram || mem_total < val.totalswap) 1446 if (mem_total < info->totalram || mem_total < info->totalswap)
1448 goto out; 1447 goto out;
1449 bitcount = 0; 1448 bitcount = 0;
1450 mem_unit = val.mem_unit; 1449 mem_unit = info->mem_unit;
1451 while (mem_unit > 1) { 1450 while (mem_unit > 1) {
1452 bitcount++; 1451 bitcount++;
1453 mem_unit >>= 1; 1452 mem_unit >>= 1;
@@ -1459,22 +1458,31 @@ asmlinkage long sys_sysinfo(struct sysinfo __user *info)
1459 1458
1460 /* 1459 /*
1461 * If mem_total did not overflow, multiply all memory values by 1460 * If mem_total did not overflow, multiply all memory values by
1462 * val.mem_unit and set it to 1. This leaves things compatible 1461 * info->mem_unit and set it to 1. This leaves things compatible
1463 * with 2.2.x, and also retains compatibility with earlier 2.4.x 1462 * with 2.2.x, and also retains compatibility with earlier 2.4.x
1464 * kernels... 1463 * kernels...
1465 */ 1464 */
1466 1465
1467 val.mem_unit = 1; 1466 info->mem_unit = 1;
1468 val.totalram <<= bitcount; 1467 info->totalram <<= bitcount;
1469 val.freeram <<= bitcount; 1468 info->freeram <<= bitcount;
1470 val.sharedram <<= bitcount; 1469 info->sharedram <<= bitcount;
1471 val.bufferram <<= bitcount; 1470 info->bufferram <<= bitcount;
1472 val.totalswap <<= bitcount; 1471 info->totalswap <<= bitcount;
1473 val.freeswap <<= bitcount; 1472 info->freeswap <<= bitcount;
1474 val.totalhigh <<= bitcount; 1473 info->totalhigh <<= bitcount;
1475 val.freehigh <<= bitcount; 1474 info->freehigh <<= bitcount;
1475
1476out:
1477 return 0;
1478}
1479
1480asmlinkage long sys_sysinfo(struct sysinfo __user *info)
1481{
1482 struct sysinfo val;
1483
1484 do_sysinfo(&val);
1476 1485
1477 out:
1478 if (copy_to_user(info, &val, sizeof(struct sysinfo))) 1486 if (copy_to_user(info, &val, sizeof(struct sysinfo)))
1479 return -EFAULT; 1487 return -EFAULT;
1480 1488