procfs: Support multiple reads of e.g. /proc/*/maps

Refs: #1021
Change-Id: If36e1a0f3f41f0215868daf578e96775d96a59a3
This commit is contained in:
Tomoki Shirasawa
2018-08-22 16:18:23 +09:00
committed by Masamichi Takagi
parent e531ee626e
commit 895a8c4099
10 changed files with 1042 additions and 230 deletions

View File

@ -40,6 +40,78 @@ extern int sprintf(char * buf, const char *fmt, ...);
extern int sscanf(const char * buf, const char * fmt, ...);
extern int scnprintf(char * buf, size_t size, const char *fmt, ...);
struct mckernel_procfs_buffer {
unsigned long next_pa;
unsigned long pos;
unsigned long size;
char buf[0];
};
#define PA_NULL (-1L)
static struct mckernel_procfs_buffer *buf_alloc(unsigned long *phys, long pos)
{
struct mckernel_procfs_buffer *buf;
buf = ihk_mc_alloc_pages(1, IHK_MC_AP_NOWAIT);
if (!buf)
return NULL;
buf->next_pa = PA_NULL;
buf->pos = pos;
buf->size = 0;
if (phys)
*phys = virt_to_phys(buf);
return buf;
}
static void buf_free(unsigned long phys)
{
struct mckernel_procfs_buffer *pbuf;
unsigned long next;
while (phys != PA_NULL) {
pbuf = phys_to_virt(phys);
next = pbuf->next_pa;
ihk_mc_free_pages(pbuf, 1);
phys = next;
}
}
static int buf_add(struct mckernel_procfs_buffer **top,
struct mckernel_procfs_buffer **cur, void *buf, int l)
{
int pos = 0;
int r;
int bufmax = PAGE_SIZE - sizeof(struct mckernel_procfs_buffer);
char *chr = buf;
if (!*top) {
*top = *cur = buf_alloc(NULL, 0);
if (!*top)
return -ENOMEM;
}
while (l) {
r = bufmax - (*cur)->size;
if (!r) {
*cur = buf_alloc(&(*cur)->next_pa, (*cur)->pos +
bufmax);
if (!*cur) {
buf_free(virt_to_phys(*top));
return -ENOMEM;
}
r = bufmax;
}
if (r > l) {
r = l;
}
memcpy((*cur)->buf + (*cur)->size, chr + pos, r);
l -= r;
pos += r;
(*cur)->size += r;
}
return 0;
}
static void
procfs_thread_ctl(struct thread *thread, int msg)
{
@ -85,13 +157,17 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
struct procfs_read *r;
int osnum = ihk_mc_get_osnum();
int rosnum, ret, pid, tid, ans = -EIO, eof = 0;
char *buf, *p;
char *buf, *p = NULL;
char *vbuf = NULL;
char *tmp = NULL;
struct mcs_rwlock_node_irqsave lock;
unsigned long offset;
int count;
int npages;
int readwrite = 0;
int err = -EIO;
struct mckernel_procfs_buffer *buf_top = NULL;
struct mckernel_procfs_buffer *buf_cur = NULL;
dprintf("process_procfs_request: invoked.\n");
@ -100,27 +176,55 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
dprintf("parg: %x\n", parg);
r = ihk_mc_map_virtual(parg, 1, PTATTR_WRITABLE | PTATTR_ACTIVE);
if (r == NULL) {
ihk_mc_unmap_memory(NULL, parg, sizeof(struct procfs_read));
kprintf("ERROR: process_procfs_request: got a null procfs_read structure.\n");
goto dataunavail;
goto err;
}
dprintf("r: %p\n", r);
dprintf("remote pbuf: %x\n", r->pbuf);
pbuf = ihk_mc_map_memory(NULL, r->pbuf, r->count);
dprintf("pbuf: %x\n", pbuf);
count = r->count + ((uintptr_t)pbuf & (PAGE_SIZE - 1));
npages = (count + (PAGE_SIZE - 1)) / PAGE_SIZE;
buf = ihk_mc_map_virtual(pbuf, npages, PTATTR_WRITABLE | PTATTR_ACTIVE);
dprintf("buf: %p\n", buf);
if (buf == NULL) {
kprintf("ERROR: process_procfs_request: got a null buffer.\n");
goto bufunavail;
if (rpacket->msg == SCD_MSG_PROCFS_RELEASE) {
struct mckernel_procfs_buffer *pbuf;
unsigned long phys;
unsigned long next;
for (phys = r->pbuf; phys != PA_NULL; phys = next) {
pbuf = phys_to_virt(phys);
next = pbuf->next_pa;
ihk_mc_free_pages(pbuf, 1);
}
r->ret = 0;
err = 0;
goto err;
}
readwrite = r->readwrite;
count = r->count;
if (r->pbuf == PA_NULL) {
tmp = ihk_mc_alloc_pages(1, IHK_MC_AP_NOWAIT);
if (!tmp)
goto err;
buf = tmp;
count = PAGE_SIZE;
}
else {
dprintf("remote pbuf: %x\n", r->pbuf);
pbuf = ihk_mc_map_memory(NULL, r->pbuf, r->count);
dprintf("pbuf: %x\n", pbuf);
count = r->count + ((uintptr_t)pbuf & (PAGE_SIZE - 1));
npages = (count + (PAGE_SIZE - 1)) / PAGE_SIZE;
vbuf = ihk_mc_map_virtual(pbuf, npages,
PTATTR_WRITABLE|PTATTR_ACTIVE);
dprintf("buf: %p\n", vbuf);
if (vbuf == NULL) {
ihk_mc_unmap_memory(NULL, pbuf, r->count);
kprintf("ERROR: %s: got a null buffer.\n", __func__);
goto err;
}
buf = vbuf;
readwrite = r->readwrite;
count = r->count;
dprintf("fname: %s, offset: %lx, count:%d.\n", r->fname,
r->offset, r->count);
}
offset = r->offset;
dprintf("fname: %s, offset: %lx, count:%d.\n", r->fname, r->offset, r->count);
/*
* check for "mcos%d/"
@ -200,35 +304,24 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
}
else if (!strcmp(p, "stat")) { /* "/proc/stat" */
extern int num_processors; /* kernel/ap.c */
char *p;
size_t remain;
int cpu;
if (offset > 0) {
ans = 0;
eof = 1;
goto end;
}
p = buf;
remain = count;
for (cpu = 0; cpu < num_processors; ++cpu) {
size_t n;
n = snprintf(p, remain, "cpu%d\n", cpu);
if (n >= remain) {
ans = -ENOSPC;
eof = 1;
goto end;
}
p += n;
snprintf(buf, count, "cpu%d\n", cpu);
if (buf_add(&buf_top, &buf_cur, buf, strlen(buf)) < 0)
goto err;
}
ans = p - buf;
eof = 1;
ans = 0;
goto end;
}
#ifdef POSTK_DEBUG_ARCH_DEP_42 /* /proc/cpuinfo support added. */
else if (!strcmp(p, "cpuinfo")) { /* "/proc/cpuinfo" */
ans = ihk_mc_show_cpuinfo(buf, count, offset, &eof);
ans = ihk_mc_show_cpuinfo(buf, count, 0, &eof);
if (ans < 0)
goto err;
if (buf_add(&buf_top, &buf_cur, buf, strlen(buf)) < 0)
goto err;
ans = 0;
goto end;
}
#endif /* POSTK_DEBUG_ARCH_DEP_42 */
@ -313,110 +406,51 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
*/
if (strcmp(p, "maps") == 0) {
struct vm_range *range;
#ifdef POSTK_DEBUG_TEMP_FIX_47 /* /proc/<pid>/maps 1024 byte over read fix. */
int left = PAGE_SIZE * 2;
#else /* POSTK_DEBUG_TEMP_FIX_47 */
int left = r->count - 1; /* extra 1 for terminating NULL */
#endif /* POSTK_DEBUG_TEMP_FIX_47 */
int written = 0;
char *_buf = buf;
#ifdef POSTK_DEBUG_TEMP_FIX_47 /* /proc/<pid>/maps 1024 byte over read fix. */
int len = 0;
char *tmp = NULL;
_buf = tmp = kmalloc(left, IHK_MC_AP_CRITICAL);
if (!tmp) {
kprintf("%s: error allocating /proc/self/maps buffer\n",
__FUNCTION__);
ans = 0;
goto end;
}
#endif /* POSTK_DEBUG_TEMP_FIX_47 */
#ifndef POSTK_DEBUG_TEMP_FIX_47 /* /proc/<pid>/maps 1024 byte over read fix. */
/* Starting from the middle of a proc file is not supported for maps */
if (offset > 0) {
ans = 0;
eof = 1;
goto end;
}
#endif /* POSTK_DEBUG_TEMP_FIX_47 */
ihk_mc_spinlock_lock_noirq(&vm->memory_range_lock);
range = lookup_process_memory_range(vm, 0, -1);
while (range) {
int written_now;
/* format is (from man proc):
* address perms offset dev inode pathname
* 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
*/
written_now = snprintf(_buf, left,
"%012lx-%012lx %s%s%s%s %lx %lx:%lx %d\t\t\t%s\n",
range->start, range->end,
range->flag & VR_PROT_READ ? "r" : "-",
range->flag & VR_PROT_WRITE ? "w" : "-",
range->flag & VR_PROT_EXEC ? "x" : "-",
range->flag & VR_PRIVATE ? "p" : "s",
/* TODO: fill in file details! */
0UL,
0UL,
0UL,
0,
range->memobj && range->memobj->path ? range->memobj->path :
range->start ==
(unsigned long)vm->vdso_addr ? "[vdso]" :
range->start ==
(unsigned long)vm->vvar_addr ? "[vsyscall]" :
range->flag & VR_STACK ? "[stack]" :
range->start >= vm->region.brk_start &&
range->end <= vm->region.brk_end_allocated ?
"[heap]" :
snprintf(buf, count,
"%012lx-%012lx %s%s%s%s %lx %lx:%lx %d\t\t\t%s\n",
range->start, range->end,
range->flag & VR_PROT_READ ? "r" : "-",
range->flag & VR_PROT_WRITE ? "w" : "-",
range->flag & VR_PROT_EXEC ? "x" : "-",
range->flag & VR_PRIVATE ? "p" : "s",
/* TODO: fill in file details! */
0UL,
0UL,
0UL,
0,
range->memobj && range->memobj->path ?
range->memobj->path :
range->start == (unsigned long)vm->vdso_addr ?
"[vdso]" :
range->start == (unsigned long)vm->vvar_addr ?
"[vsyscall]" :
range->flag & VR_STACK ?
"[stack]" :
range->start >= vm->region.brk_start &&
range->end <= vm->region.brk_end_allocated ?
"[heap]" :
""
);
left -= written_now;
_buf += written_now;
written += written_now;
);
#ifdef POSTK_DEBUG_TEMP_FIX_47 /* /proc/<pid>/maps 1024 byte over read fix. */
if (left == 0) {
kprintf("%s(): WARNING: buffer too small to fill proc/maps\n",
__FUNCTION__);
break;
if (buf_add(&buf_top, &buf_cur, buf, strlen(buf)) < 0) {
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
goto err;
}
#else /* POSTK_DEBUG_TEMP_FIX_47 */
if (left == 1) {
kprintf("%s(): WARNING: buffer too small to fill proc/maps\n",
__FUNCTION__);
break;
}
#endif /* POSTK_DEBUG_TEMP_FIX_47 */
range = next_process_memory_range(vm, range);
}
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
#ifdef POSTK_DEBUG_TEMP_FIX_47 /* /proc/<pid>/maps 1024 byte over read fix. */
len = strlen(tmp);
if (r->offset < len) {
if (r->offset + r->count < len) {
ans = r->count;
} else {
eof = 1;
ans = len;
}
strncpy(buf, tmp + r->offset, ans);
} else if (r->offset == len) {
ans = 0;
eof = 1;
}
kfree(tmp);
#else /* POSTK_DEBUG_TEMP_FIX_47 */
ans = written;
eof = 1;
#endif /* POSTK_DEBUG_TEMP_FIX_47 */
ans = 0;
goto end;
}
@ -465,28 +499,16 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
extern int num_processors; /* kernel/ap.c */
struct vm_range *range;
unsigned long lockedsize = 0;
char *tmp;
char *bitmasks;
int bitmasks_offset = 0;
char *cpu_bitmask, *cpu_list, *numa_bitmask, *numa_list;
int len;
char *state;
tmp = kmalloc(8192, IHK_MC_AP_CRITICAL);
if (!tmp) {
kprintf("%s: error allocating /proc/self/status buffer\n",
__FUNCTION__);
ans = 0;
goto end;
}
bitmasks = kmalloc(BITMASKS_BUF_SIZE, IHK_MC_AP_CRITICAL);
if (!tmp) {
if (!bitmasks) {
kprintf("%s: error allocating /proc/self/status bitmaks buffer\n",
__FUNCTION__);
kfree(tmp);
ans = 0;
goto end;
goto err;
}
ihk_mc_spinlock_lock_noirq(&proc->vm->memory_range_lock);
@ -529,37 +551,43 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
state = "T (tracing stop)";
else if (proc->status == PS_EXITED)
state = "Z (zombie)";
sprintf(tmp,
"Pid:\t%d\n"
"Uid:\t%d\t%d\t%d\t%d\n"
"Gid:\t%d\t%d\t%d\t%d\n"
sprintf(buf,
"Pid:\t%d\n"
"Uid:\t%d\t%d\t%d\t%d\n"
"Gid:\t%d\t%d\t%d\t%d\n"
"State:\t%s\n"
"VmLck:\t%9lu kB\n"
"Cpus_allowed:\t%s\n"
"Cpus_allowed_list:\t%s\n"
"Mems_allowed:\t%s\n"
"Mems_allowed_list:\t%s\n",
proc->pid,
proc->ruid, proc->euid, proc->suid, proc->fsuid,
proc->rgid, proc->egid, proc->sgid, proc->fsgid,
"VmLck:\t%9lu kB\n",
proc->pid,
proc->ruid, proc->euid, proc->suid, proc->fsuid,
proc->rgid, proc->egid, proc->sgid, proc->fsgid,
state,
(lockedsize + 1023) >> 10,
cpu_bitmask, cpu_list, numa_bitmask, numa_list);
len = strlen(tmp);
if (r->offset < len) {
if (r->offset + r->count < len) {
ans = r->count;
} else {
eof = 1;
ans = len;
}
strncpy(buf, tmp + r->offset, ans);
} else if (r->offset == len) {
ans = 0;
eof = 1;
(lockedsize + 1023) >> 10);
if (buf_add(&buf_top, &buf_cur, buf, strlen(buf)) < 0) {
goto err;
}
sprintf(buf, "Cpus_allowed:\t%s\n", cpu_bitmask);
if (buf_add(&buf_top, &buf_cur, buf, strlen(buf)) < 0) {
kfree(bitmasks);
goto err;
}
sprintf(buf, "Cpus_allowed_list:\t%s\n", cpu_list);
if (buf_add(&buf_top, &buf_cur, buf, strlen(buf)) < 0) {
kfree(bitmasks);
goto err;
}
sprintf(buf, "Mems_allowed:\t%s\n", numa_bitmask);
if (buf_add(&buf_top, &buf_cur, buf, strlen(buf)) < 0) {
kfree(bitmasks);
goto err;
}
sprintf(buf, "Mems_allowed_list:\t%s\n", numa_list);
if (buf_add(&buf_top, &buf_cur, buf, strlen(buf)) < 0) {
kfree(bitmasks);
goto err;
}
kfree(tmp);
kfree(bitmasks);
ans = 0;
goto end;
}
@ -568,20 +596,10 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
*/
if (strcmp(p, "auxv") == 0) {
unsigned int limit = AUXV_LEN * sizeof(unsigned long);
unsigned int len = r->count;
if (r->offset < limit) {
if (limit < r->offset + r->count) {
len = limit - r->offset;
}
memcpy((void *)buf, ((char *) proc->saved_auxv) + r->offset, len);
ans = len;
if (r->offset + len == limit) {
eof = 1;
}
} else if (r->offset == limit) {
ans = 0;
eof = 1;
}
if (buf_add(&buf_top, &buf_cur, proc->saved_auxv, limit) < 0)
goto err;
ans = 0;
goto end;
}
@ -590,27 +608,17 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
*/
if (strcmp(p, "cmdline") == 0) {
unsigned int limit = proc->saved_cmdline_len;
unsigned int len = r->count;
if(!proc->saved_cmdline){
if (buf_add(&buf_top, &buf_cur, "", 0) < 0)
goto err;
ans = 0;
eof = 1;
goto end;
}
if (r->offset < limit) {
if (limit < r->offset + r->count) {
len = limit - r->offset;
}
memcpy((void *)buf, ((char *) proc->saved_cmdline) + r->offset, len);
ans = len;
if (r->offset + len == limit) {
eof = 1;
}
} else if (r->offset == limit) {
ans = 0;
eof = 1;
}
if (buf_add(&buf_top, &buf_cur, proc->saved_cmdline, limit) < 0)
goto err;
ans = 0;
goto end;
}
@ -622,8 +630,6 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
*/
if (!strcmp(p, "stat")) {
char tmp[1024];
int len;
/*
* pid (comm) state ppid
@ -638,7 +644,7 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
* cnswap exit_signal processor rt_priority
* policy delayacct_blkio_ticks guest_time cguest_time
*/
ans = sprintf(tmp,
ans = sprintf(buf,
"%d (%s) %c %d " // pid...
"%d %d %d %d " // pgrp...
"%u %lu %lu %lu " // flags...
@ -662,21 +668,10 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
0L, 0, thread->cpu_id, 0, // cnswap...
0, 0LL, 0L, 0L // policy...
);
dprintf("tmp=%s\n", tmp);
len = strlen(tmp);
if (r->offset < len) {
if (r->offset + r->count < len) {
ans = r->count;
} else {
eof = 1;
ans = len;
}
strncpy(buf, tmp + r->offset, ans);
} else if (r->offset == len) {
ans = 0;
eof = 1;
}
if (buf_add(&buf_top, &buf_cur, buf, strlen(buf)) < 0)
goto err;
ans = 0;
goto end;
}
@ -686,16 +681,24 @@ int process_procfs_request(struct ikc_scd_packet *rpacket)
kprintf("unsupported procfs entry: %d/%s\n", pid, p);
end:
ihk_mc_unmap_virtual(buf, npages);
dprintf("ret: %d, eof: %d\n", ans, eof);
r->ret = ans;
r->eof = eof;
err = 0;
bufunavail:
ihk_mc_unmap_memory(NULL, pbuf, r->count);
ihk_mc_unmap_virtual(r, 1);
dataunavail:
ihk_mc_unmap_memory(NULL, parg, sizeof(struct procfs_read));
if (r->pbuf == PA_NULL && buf_top)
r->pbuf = virt_to_phys(buf_top);
err:
if (vbuf) {
ihk_mc_unmap_virtual(vbuf, npages);
ihk_mc_unmap_memory(NULL, pbuf, r->count);
}
if (r) {
ihk_mc_unmap_virtual(r, 1);
ihk_mc_unmap_memory(NULL, parg, sizeof(struct procfs_read));
}
if (tmp) {
ihk_mc_free_pages(tmp, 1);
}
if(proc)
release_process(proc);