From dd58d366c3b68449538de93970a939cf808f70d3 Mon Sep 17 00:00:00 2001 From: Ken Sato Date: Wed, 8 Aug 2018 17:00:28 +0900 Subject: [PATCH] procfs: Fix pread/pwrite to procfs fail when specified size is bigger than 4MB Fujitsu: POSTK_DEBUG_TEMP_FIX_43 Refs: #1018 Change-Id: I736ac69885695ef8eeababc3fcfe69a6258b4e16 --- executer/kernel/mcctrl/procfs.c | 164 -------------------------------- test/issues/1018/C1018.sh | 79 +++++++++++++++ test/issues/1018/CT_001.c | 99 +++++++++++++++++++ test/issues/1018/CT_002.c | 89 +++++++++++++++++ test/issues/1018/Makefile | 20 ++++ test/issues/1018/README | 38 ++++++++ test/issues/1018/result.log | 62 ++++++++++++ test/issues/1018/test_chk.h | 23 +++++ 8 files changed, 410 insertions(+), 164 deletions(-) create mode 100644 test/issues/1018/C1018.sh create mode 100644 test/issues/1018/CT_001.c create mode 100644 test/issues/1018/CT_002.c create mode 100644 test/issues/1018/Makefile create mode 100644 test/issues/1018/README create mode 100644 test/issues/1018/result.log create mode 100644 test/issues/1018/test_chk.h diff --git a/executer/kernel/mcctrl/procfs.c b/executer/kernel/mcctrl/procfs.c index 4afcd1c3..d36c2900 100644 --- a/executer/kernel/mcctrl/procfs.c +++ b/executer/kernel/mcctrl/procfs.c @@ -482,7 +482,6 @@ procfs_exit(int osnum) * This function conforms to the 2) way of fs/proc/generic.c * from linux-2.6.39.4. */ -#ifdef POSTK_DEBUG_TEMP_FIX_43 /* Fixed an issue that failed pread / pwrite of size larger than 4MB */ static ssize_t __mckernel_procfs_read_write( struct file *file, char __user *buf, size_t nbytes, @@ -666,169 +665,6 @@ out: return ret; } -#else /* POSTK_DEBUG_TEMP_FIX_43 */ -static ssize_t __mckernel_procfs_read_write( - struct file *file, - char __user *buf, size_t nbytes, - loff_t *ppos, int read_write) -{ - struct inode * inode = file->f_inode; - char *kern_buffer = NULL; - int order = 0; - volatile struct procfs_read *r = NULL; - struct ikc_scd_packet isp; - int ret, osnum, pid; - unsigned long pbuf; - unsigned long count = nbytes; -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) - struct proc_dir_entry *dp = PDE(inode); - struct procfs_list_entry *e = dp->data; -#else - struct procfs_list_entry *e = PDE_DATA(inode); -#endif - loff_t offset = *ppos; - char pathbuf[PROCFS_NAME_MAX]; - char *path, *p; - ihk_os_t os = NULL; - struct mcctrl_usrdata *udp = NULL; - struct mcctrl_per_proc_data *ppd = NULL; - int do_free; - - if (count <= 0 || offset < 0) { - return 0; - } - - path = getpath(e, pathbuf, PROCFS_NAME_MAX); - dprintk("%s: invoked for %s, offset: %lu, count: %lu\n", - __FUNCTION__, path, - (unsigned long)offset, count); - - /* Verify OS number */ - ret = sscanf(path, "mcos%d/", &osnum); - if (ret != 1) { - printk("%s: error: couldn't determine OS number\n", __FUNCTION__); - return -EINVAL; - } - - if (osnum != e->osnum) { - printk("%s: error: OS numbers don't match\n", __FUNCTION__); - return -EINVAL; - } - - /* Is this request for a specific process? */ - p = strchr(path, '/') + 1; - ret = sscanf(p, "%d/", &pid); - if (ret != 1) { - pid = -1; - } - - os = osnum_to_os(osnum); - if (!os) { - printk("%s: error: no IHK OS data found for OS %d\n", - __FUNCTION__, osnum); - return -EINVAL; - } - - udp = ihk_host_os_get_usrdata(os); - if (!udp) { - printk("%s: error: no MCCTRL data found for OS %d\n", - __FUNCTION__, osnum); - return -EINVAL; - } - - if (pid > 0) { - ppd = mcctrl_get_per_proc_data(udp, pid); - - if (unlikely(!ppd)) { - printk("%s: error: no per-process structure for PID %d", - __FUNCTION__, pid); - return -EINVAL; - } - } - - while ((1 << order) < count) ++order; - if (order > 12) { - order -= 12; - } - else { - order = 1; - } - - /* NOTE: we need physically contigous memory to pass through IKC */ - kern_buffer = (char *)__get_free_pages(GFP_KERNEL, order); - if (!kern_buffer) { - printk("%s: ERROR: allocating kernel buffer\n", __FUNCTION__); - ret = -ENOMEM; - goto out; - } - - pbuf = virt_to_phys(kern_buffer); - - r = kmalloc(sizeof(struct procfs_read), GFP_KERNEL); - if (r == NULL) { - ret = -ENOMEM; - goto out; - } - r->pbuf = pbuf; - r->eof = 0; - r->ret = -EIO; /* default */ - r->offset = offset; - r->count = count; - r->readwrite = read_write; - strncpy((char *)r->fname, path, PROCFS_NAME_MAX); - isp.msg = SCD_MSG_PROCFS_REQUEST; - isp.ref = 0; - isp.arg = virt_to_phys(r); - isp.pid = pid; - - ret = mcctrl_ikc_send_wait(osnum_to_os(e->osnum), - (pid > 0) ? ppd->ikc_target_cpu : 0, - &isp, 5 * HZ, NULL, &do_free, 1, r); - - if (!do_free && ret >= 0) { - ret = -EIO; - } - - if (ret < 0) { - if (ret == -ETIME) { - pr_info("%s: error: timeout (1 sec)\n", - __func__); - } - else if (ret == -ERESTARTSYS) { - ret = -ERESTART; - } - if (!do_free) - r = NULL; - goto out; - } - - /* Wake up and check the result. */ - dprintk("%s: woke up. ret: %d, eof: %d\n", - __FUNCTION__, r->ret, r->eof); - - if (r->ret > 0) { - if (read_write == 0) { - if (copy_to_user(buf, kern_buffer, r->ret)) { - printk("%s: ERROR: copy_to_user failed.\n", __FUNCTION__); - ret = -EFAULT; - goto out; - } - } - *ppos += r->ret; - } - ret = r->ret; - -out: - if (ppd) - mcctrl_put_per_proc_data(ppd); - if (kern_buffer) - free_pages((uintptr_t)kern_buffer, order); - if (r) - kfree((void *)r); - - return ret; -} -#endif /* POSTK_DEBUG_TEMP_FIX_43 */ static ssize_t mckernel_procfs_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) diff --git a/test/issues/1018/C1018.sh b/test/issues/1018/C1018.sh new file mode 100644 index 00000000..ef06aea1 --- /dev/null +++ b/test/issues/1018/C1018.sh @@ -0,0 +1,79 @@ +#!/bin/sh +if [ -f $HOME/mck_test_config ]; then + . $HOME/mck_test_config +else + BIN= + SBIN= + OSTEST= +fi +BOOTPARAM="-c 1-7,9-15,17-23,25-31 -m 10G@0,10G@1 -r 1-7:0+9-15:8+17-23:16+25-31:24" + +if [ "x$BINDIR" = x ];then + BINDIR="$BIN" +fi + +if [ "x$SBINDIR" = x ];then + SBINDIR="$SBIN" +fi + +if [ "x$OSTESTDIR" = x ]; then + OSTESTDIR="$OSTEST" +fi + +if [ "x$LTPDIR" = x ]; then + LTPDIR="$LTP" +fi + +if [ ! -x $SBINDIR/mcstop+release.sh ]; then + echo mcstop+release: not found >&2 + exit 1 +fi +echo -n "mcstop+release.sh ... " +sudo $SBINDIR/mcstop+release.sh +echo "done" + +if [ ! -x $SBINDIR/mcreboot.sh ]; then + echo mcreboot: not found >&2 + exit 1 +fi +echo -n "mcreboot.sh $BOOTPARAM ... " +sudo $SBINDIR/mcreboot.sh $BOOTPARAM +echo "done" + +if [ ! -x $BINDIR/mcexec ]; then + echo mcexec: not found >&2 + exit 1 +fi + +$BINDIR/mcexec ./CT_001 +$BINDIR/mcexec ./CT_002 + +tid=001 +echo "*** RT_$tid start *******************************" +sudo $BINDIR/mcexec $OSTESTDIR/bin/test_mck -s procfs -n 0 2>&1 | tee ./RT_${tid}.txt +if grep -v "RESULT: TP failed" ./RT_${tid}.txt > /dev/null 2>&1 ; then + echo "*** RT_$tid: PASSED" +else + echo "*** RT_$tid: FAILED" +fi +echo "" + +tid=002 +echo "*** RT_$tid start *******************************" +sudo $BINDIR/mcexec $OSTESTDIR/bin/test_mck -s procfs -n 1 2>&1 | tee ./RT_${tid}.txt +if grep -v "RESULT: TP failed" ./RT_${tid}.txt > /dev/null 2>&1 ; then + echo "*** RT_$tid: PASSED" +else + echo "*** RT_$tid: FAILED" +fi +echo "" + +tid=003 +echo "*** RT_$tid start *******************************" +sudo $BINDIR/mcexec $OSTESTDIR/bin/test_mck -s procfs -n 3 2>&1 | tee ./RT_${tid}.txt +if grep -v "RESULT: TP failed" ./RT_${tid}.txt > /dev/null 2>&1 ; then + echo "*** RT_$tid: PASSED" +else + echo "*** RT_$tid: FAILED" +fi +echo "" diff --git a/test/issues/1018/CT_001.c b/test/issues/1018/CT_001.c new file mode 100644 index 00000000..66c39967 --- /dev/null +++ b/test/issues/1018/CT_001.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "./test_chk.h" + +#define TEST_NAME "CT_001" + +#define MEGA (1024 * 1024) + +#define PROCFILE_LEN 128 +#define MAP_LEN (8 * MEGA) + +int main(int argc, char *argv[]) +{ + int fd = 0, i = 0; + pid_t pid = getpid(); + char pfname[PROCFILE_LEN]; + unsigned long *anon_map = NULL; + unsigned long *tmp_buf = NULL; + int data_pos[3] = {1 * MEGA / sizeof(unsigned long), + 2 * MEGA / sizeof(unsigned long), + 4 * MEGA / sizeof(unsigned long)}; + off_t ret = 0; + + printf("*** %s start *******************************\n", TEST_NAME); + + /* anonymous mmap */ + anon_map = (unsigned long *)mmap(NULL, MAP_LEN, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + OKNG(anon_map == MAP_FAILED, "mmap device file"); + printf(" anonymous map to %p, size:%.2f MB\n", + anon_map, (double)MAP_LEN / MEGA); + + /* allocate tmp_buf */ + tmp_buf = (unsigned long *)mmap(NULL, MAP_LEN, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + CHKANDJUMP(tmp_buf == NULL, "alloc tmp_buf"); + + /* set magic_number */ + anon_map[data_pos[0]] = 0x1111; + anon_map[data_pos[1]] = 0x2222; + anon_map[data_pos[2]] = 0x3333; + + /* generate proc_mem path */ + sprintf(pfname, "/proc/%d/mem", pid); + + /* open proc_mem */ + fd = open(pfname, O_RDWR); + CHKANDJUMP(fd < 0, "open proc_mem"); + + /* pread 2MB */ + errno = 0; + ret = pread(fd, tmp_buf, 2 * MEGA, (off_t)anon_map); + OKNG(ret != 2 * MEGA || errno != 0, "2MB pread"); + + /* check read data */ + OKNG(tmp_buf[data_pos[0]] != anon_map[data_pos[0]], + "check read data :0x%lx", tmp_buf[data_pos[0]]); + + /* pread 4MB */ + errno = 0; + ret = pread(fd, tmp_buf, 4 * MEGA, (off_t)anon_map); + OKNG(ret != 4 * MEGA || errno != 0, "4MB pread"); + + /* check read data */ + OKNG(tmp_buf[data_pos[1]] != anon_map[data_pos[1]], + "check read data :0x%lx", tmp_buf[data_pos[1]]); + + /* pread 8MB */ + errno = 0; + ret = pread(fd, tmp_buf, 8 * MEGA, (off_t)anon_map); + OKNG(ret != 8 * MEGA || errno != 0, "8MB pread"); + + /* check read data */ + OKNG(tmp_buf[data_pos[2]] != anon_map[data_pos[2]], + "check read data :0x%lx", tmp_buf[data_pos[2]]); + + close(fd); + + printf("*** %s PASSED\n\n", TEST_NAME); + + return 0; + +fn_fail: + if (fd > 0) { + close(fd); + } + + printf("*** %s FAILED\n\n", TEST_NAME); + + return -1; + +} diff --git a/test/issues/1018/CT_002.c b/test/issues/1018/CT_002.c new file mode 100644 index 00000000..36c24d50 --- /dev/null +++ b/test/issues/1018/CT_002.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "./test_chk.h" + +#define TEST_NAME "CT_002" + +#define MEGA (1024 * 1024) + +#define PROCFILE_LEN 128 +#define MAP_LEN (8 * MEGA) + +int main(int argc, char *argv[]) +{ + int fd = 0, i = 0; + pid_t pid = getpid(); + char pfname[PROCFILE_LEN]; + unsigned long *anon_map = NULL; + unsigned long *tmp_buf = NULL; + int data_pos[3] = {0 * MEGA / sizeof(unsigned long), + 1 * MEGA / sizeof(unsigned long), + 4 * MEGA / sizeof(unsigned long)}; + off_t ret = 0; + + printf("*** %s start *******************************\n", TEST_NAME); + + /* anonymous mmap */ + anon_map = (unsigned long *)mmap(NULL, MAP_LEN, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + OKNG(anon_map == MAP_FAILED, "anonymous map"); + printf(" anonymous map to %p, size:%.2f MB\n", + anon_map, (double)MAP_LEN / MEGA); + + /* allocate tmp_buf */ + tmp_buf = (unsigned long *)mmap(NULL, MAP_LEN, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + CHKANDJUMP(tmp_buf == MAP_FAILED, "alloc tmp_buf"); + + /* set magic_number */ + tmp_buf[data_pos[0]] = 0x1111; + tmp_buf[data_pos[1]] = 0x2222; + tmp_buf[data_pos[2]] = 0x3333; + + /* generate proc_mem path */ + sprintf(pfname, "/proc/%d/mem", pid); + + /* open proc_mem */ + fd = open(pfname, O_RDWR); + CHKANDJUMP(fd < 0, "open proc_mem"); + + /* pwrite 2MB */ + errno = 0; + ret = pwrite(fd, tmp_buf, 2 * MEGA, (off_t)anon_map); + OKNG(ret != 2 * MEGA || errno != 0, "2MB pwrite"); + + /* pwrite 4MB */ + errno = 0; + ret = pwrite(fd, tmp_buf, 4 * MEGA, (off_t)anon_map); + OKNG(ret != 4 * MEGA || errno != 0, "4MB pwrite"); + + /* pwrite 8MB */ + errno = 0; + ret = pwrite(fd, tmp_buf, 8 * MEGA, (off_t)anon_map); + OKNG(ret != 8 * MEGA || errno != 0, "8MB pwrite"); + + close(fd); + + printf("*** %s PASSED\n\n", TEST_NAME); + + return 0; + +fn_fail: + + if (fd > 0) { + close(fd); + } + + printf("*** %s FAILED\n\n", TEST_NAME); + + return -1; + +} diff --git a/test/issues/1018/Makefile b/test/issues/1018/Makefile new file mode 100644 index 00000000..ae5691b0 --- /dev/null +++ b/test/issues/1018/Makefile @@ -0,0 +1,20 @@ +CC = gcc +TARGET=CT_001 CT_002 + +CPPFLAGS = +LDFLAGS = + +all: $(TARGET) + +CT_001: CT_001.c + $(CC) -o $@ $^ $(LDFLAGS) + +CT_002: CT_002.c + $(CC) -o $@ $^ $(LDFLAGS) + +test: all + @sh ./C1018.sh + +clean: + rm -f $(TARGET) *.o + diff --git a/test/issues/1018/README b/test/issues/1018/README new file mode 100644 index 00000000..721a4e14 --- /dev/null +++ b/test/issues/1018/README @@ -0,0 +1,38 @@ +【Issue#1018 動作確認】 +□ テスト内容 +1. Issueで報告された再現プログラムでの確認 +CT_001: /proc//mem に対するpread + /proc//mem に対して、2MB, 4MB, 8MB でそれぞれpreadを実行し、 + preadが成功することと、読み取ったデータが正しいことを確認 + +CT_002: /proc//mem に対するpwrite + /proc//mem に対して、2MB, 4MB, 8MB でそれぞれpwriteを実行し、 + pwriteが成功することを確認 + +2. 既存のprocfs機能に影響がないことをOSTESTを用いて確認 +RT_001: ostest_procfs.000 + /proc//auxv の内容を取得できることを確認 + +RT_002: ostest_procfs.001 + /proc//mem の内容を取得できることを確認 + +RT_003: ostest_procfs.003 + /proc//stat の内容を取得できることを確認 + +□ 実行手順 +McKernelのインストール先や、OSTEST, LTPの配置場所は、 +$HOME/mck_test_config を参照している +mck_test_config は、McKernelをビルドした際に生成される +mck_test_config.sample ファイルを$HOMEにコピーし、適宜編集する + +$ make test + +実行できない場合は、C1018.shの以下の行を適切に書き換えた後に実行。 +BIN= mcexec が存在するパス +SBIN= mcreboot.sh が存在するパス +OSTEST= OSTESTが存在するパス +LTP= LTPが存在するパス + +□ 実行結果 +result.log 参照。 +すべての項目をPASSしていることを確認。 diff --git a/test/issues/1018/result.log b/test/issues/1018/result.log new file mode 100644 index 00000000..71460200 --- /dev/null +++ b/test/issues/1018/result.log @@ -0,0 +1,62 @@ +*** CT_001 start ******************************* + [OK] mmap device file + anonymous map to 0x2aaaab200000, size:8.00 MB + [OK] 2MB pread + [OK] check read data :0x1111 + [OK] 4MB pread + [OK] check read data :0x2222 + [OK] 8MB pread + [OK] check read data :0x3333 +*** CT_001 PASSED + +*** CT_002 start ******************************* + [OK] anonymous map + anonymous map to 0x2aaaab200000, size:8.00 MB + [OK] 2MB pwrite + [OK] 4MB pwrite + [OK] 8MB pwrite +*** CT_002 PASSED + +*** RT_001 start ******************************* +TEST_SUITE: procfs +TEST_NUMBER: 0 +ARGS: +dump /proc/5267/auxv: + 0x00000000000021 0x002aaaaac24000 (AT_SYSINFO_EHDR) + 0x00000000000019 0x00547fffffffe0 (AT_RANDOM) + 0x00000000000011 0x00000000000064 (AT_CLKTCK) + 0x00000000000006 0x00000000001000 (AT_PAGESZ) + 0x00000000000003 0x00000000400040 (AT_PHDR) + 0x00000000000004 0x00000000000038 (AT_PHENT) + 0x00000000000005 0x0000000000000a (AT_PHNUM) + 0x00000000000009 0x00000000403430 (AT_ENTRY) + 0000000000000000 0000000000000000 (AT_NULL) +RESULT: you need check AUXV value +*** RT_001: PASSED + +*** RT_002 start ******************************* +TEST_SUITE: procfs +TEST_NUMBER: 1 +ARGS: +allocated: 0x00000000800010 +dump /proc/5301/mem(offset:0x00000000800010): + 0x00000000800010: 0000000000000000 0000000000000001 0000000000000002 0000000000000003 + 0x00000000800030: 0000000000000004 0000000000000005 0000000000000006 0000000000000007 + 0x00000000800050: 0000000000000008 0000000000000009 000000000000000a 000000000000000b + 0x00000000800070: 000000000000000c 000000000000000d 000000000000000e 000000000000000f + 0x00000000800090: 0000000000000010 0000000000000011 0000000000000012 0000000000000013 + 0x000000008000b0: 0000000000000014 0000000000000015 0000000000000016 0000000000000017 + 0x000000008000d0: 0000000000000018 0000000000000019 000000000000001a 000000000000001b + 0x000000008000f0: 000000000000001c 000000000000001d 000000000000001e 000000000000001f +RESULT: you need check MEM value +*** RT_002: PASSED + +*** RT_003 start ******************************* +TEST_SUITE: procfs +TEST_NUMBER: 3 +ARGS: +output /proc/5335/task/5366/stat +0 (exe) R 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 + +RESULT: you need check STAT value +*** RT_003: PASSED diff --git a/test/issues/1018/test_chk.h b/test/issues/1018/test_chk.h new file mode 100644 index 00000000..4cef42e8 --- /dev/null +++ b/test/issues/1018/test_chk.h @@ -0,0 +1,23 @@ +#ifndef HEADER_TEST_CHK_H +#define HEADER_TEST_CHK_H + +#define CHKANDJUMP(cond, ...) do {\ + if (cond) {\ + fprintf(stderr, " [NG] ");\ + fprintf(stderr, __VA_ARGS__);\ + fprintf(stderr, " failed\n");\ + goto fn_fail;\ + } \ + } while (0) + +#define OKNG(cond, ...) do {\ + if (cond) {\ + CHKANDJUMP(cond, __VA_ARGS__);\ + } else {\ + fprintf(stdout, " [OK] ");\ + fprintf(stdout, __VA_ARGS__);\ + fprintf(stdout, "\n");\ + } \ + } while (0) + +#endif