[parisc-linux] Re: [PATCH] Generic compat_sys_sysinfo
Arnd Bergmann
arnd at arndb.de
Sat Nov 25 06:28:27 MST 2006
On Saturday 25 November 2006 02:43, Kyle McMartin wrote:
> +asmlinkage long
> +compat_sys_sysinfo(struct compat_sysinfo __user *info)
> +{
> + struct sysinfo s;
> + int ret;
> + mm_segment_t old_fs = get_fs ();
> + int bitcount = 0;
> +
> + set_fs (KERNEL_DS);
> + ret = sys_sysinfo((struct sysinfo __user *)&s);
> + set_fs (old_fs);
Maybe we should avoid the ugly get_fs/set_fs hack at the same time
and do it more like the (untested) code below. I also noticed that
all implementations of compat_sys_sysinfo do not set the reserved
fields to zero in user space, so maybe it should also be converted
to use copy_to_user().
Arnd <><
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 24b6111..634959a 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -322,6 +322,9 @@ static inline int __attribute__ ((format
(void)__tmp; \
})
+struct sysinfo;
+extern void do_sysinfo(struct sysinfo *);
+
#endif /* __KERNEL__ */
#define SI_LOAD_SHIFT 16
diff --git a/kernel/compat.c b/kernel/compat.c
index 6952dd0..cd6e0ee 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -1016,3 +1016,66 @@ asmlinkage long compat_sys_migrate_pages
return sys_migrate_pages(pid, nr_bits + 1, old, new);
}
#endif
+
+struct compat_sysinfo {
+ s32 uptime;
+ u32 loads[3];
+ u32 totalram;
+ u32 freeram;
+ u32 sharedram;
+ u32 bufferram;
+ u32 totalswap;
+ u32 freeswap;
+ u16 procs;
+ u16 pad;
+ u32 totalhigh;
+ u32 freehigh;
+ u32 mem_unit;
+ char _f[20 - 2 * sizeof(u32) - sizeof(int)];
+};
+
+asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info)
+{
+ struct sysinfo s;
+ int bitcount = 0;
+
+ do_sysinfo(&s);
+
+ /*
+ * Check to see if any memory value is too large for 32-bit and
+ * scale down if needed.
+ */
+ if ((s.totalram >> 32) || (s.totalswap >> 32)) {
+ while (s.mem_unit < PAGE_SIZE) {
+ s.mem_unit <<= 1;
+ bitcount++;
+ }
+ s.totalram >>= bitcount;
+ s.freeram >>= bitcount;
+ s.sharedram >>= bitcount;
+ s.bufferram >>= bitcount;
+ s.totalswap >>= bitcount;
+ s.freeswap >>= bitcount;
+ s.totalhigh >>= bitcount;
+ s.freehigh >>= bitcount;
+ }
+
+ if (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo))
+ || __put_user(s.uptime, &info->uptime)
+ || __put_user(s.loads[0], &info->loads[0])
+ || __put_user(s.loads[1], &info->loads[1])
+ || __put_user(s.loads[2], &info->loads[2])
+ || __put_user(s.totalram, &info->totalram)
+ || __put_user(s.freeram, &info->freeram)
+ || __put_user(s.sharedram, &info->sharedram)
+ || __put_user(s.bufferram, &info->bufferram)
+ || __put_user(s.totalswap, &info->totalswap)
+ || __put_user(s.freeswap, &info->freeswap)
+ || __put_user(s.procs, &info->procs)
+ || __put_user(s.totalhigh, &info->totalhigh)
+ || __put_user(s.freehigh, &info->freehigh)
+ || __put_user(s.mem_unit, &info->mem_unit))
+ return -EFAULT;
+
+ return 0;
+}
diff --git a/kernel/timer.c b/kernel/timer.c
index c1c7fbc..878568b 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1251,17 +1251,16 @@ asmlinkage long sys_gettid(void)
}
/**
- * sys_sysinfo - fill in sysinfo struct
+ * do_sysinfo - fill in sysinfo struct
* @info: pointer to buffer to fill
- */
-asmlinkage long sys_sysinfo(struct sysinfo __user *info)
+ */
+void do_sysinfo(struct sysinfo *val)
{
- struct sysinfo val;
unsigned long mem_total, sav_total;
unsigned int mem_unit, bitcount;
unsigned long seq;
- memset((char *)&val, 0, sizeof(struct sysinfo));
+ memset(val, 0, sizeof(struct sysinfo));
do {
struct timespec tp;
@@ -1281,17 +1280,17 @@ asmlinkage long sys_sysinfo(struct sysin
tp.tv_nsec = tp.tv_nsec - NSEC_PER_SEC;
tp.tv_sec++;
}
- val.uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0);
+ val->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0);
- val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
- val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
- val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
+ val->loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
+ val->loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
+ val->loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
- val.procs = nr_threads;
+ val->procs = nr_threads;
} while (read_seqretry(&xtime_lock, seq));
- si_meminfo(&val);
- si_swapinfo(&val);
+ si_meminfo(val);
+ si_swapinfo(val);
/*
* If the sum of all the available memory (i.e. ram + swap)
@@ -1302,41 +1301,46 @@ asmlinkage long sys_sysinfo(struct sysin
* -Erik Andersen <andersee at debian.org>
*/
- mem_total = val.totalram + val.totalswap;
- if (mem_total < val.totalram || mem_total < val.totalswap)
- goto out;
+ mem_total = val->totalram + val->totalswap;
+ if (mem_total < val->totalram || mem_total < val->totalswap)
+ return;
bitcount = 0;
- mem_unit = val.mem_unit;
+ mem_unit = val->mem_unit;
while (mem_unit > 1) {
bitcount++;
mem_unit >>= 1;
sav_total = mem_total;
mem_total <<= 1;
if (mem_total < sav_total)
- goto out;
+ return;
}
/*
* If mem_total did not overflow, multiply all memory values by
- * val.mem_unit and set it to 1. This leaves things compatible
+ * val->mem_unit and set it to 1. This leaves things compatible
* with 2.2.x, and also retains compatibility with earlier 2.4.x
* kernels...
*/
- val.mem_unit = 1;
- val.totalram <<= bitcount;
- val.freeram <<= bitcount;
- val.sharedram <<= bitcount;
- val.bufferram <<= bitcount;
- val.totalswap <<= bitcount;
- val.freeswap <<= bitcount;
- val.totalhigh <<= bitcount;
- val.freehigh <<= bitcount;
+ val->mem_unit = 1;
+ val->totalram <<= bitcount;
+ val->freeram <<= bitcount;
+ val->sharedram <<= bitcount;
+ val->bufferram <<= bitcount;
+ val->totalswap <<= bitcount;
+ val->freeswap <<= bitcount;
+ val->totalhigh <<= bitcount;
+ val->freehigh <<= bitcount;
+}
+
+asmlinkage long sys_sysinfo(struct sysinfo __user *info)
+{
+ struct sysinfo val;
+
+ do_sysinfo(&val);
- out:
if (copy_to_user(info, &val, sizeof(struct sysinfo)))
return -EFAULT;
-
return 0;
}
More information about the parisc-linux
mailing list