kernel: chroot, #! scripts, rename and mmap as apk needs them
Found by running Alpine's apk on SchOS, one failure at a time: - chroot(2) was a stub returning EPERM. Each process now has a root: where an absolute path starts and where .. stops. Mounts remember whose root they were made under, and a walk leaves a mount by the way it came in, so one filesystem can be mounted twice. - devtmpfs and proc mounted only on /dev and /proc, whatever the target; a chroot got "already mounted". - mmap never reused freed address space, so musl's malloc used up the 256 mapping records while 780 MB were free. A mergeable mapping now goes straight after an anonymous one whose end has room. - unlinkat returned -1 (EPERM) where apk expects ENOENT, and renameat was an old copy of rename: no replacing the target, and v1 dirents written into SchFS. Both now share rename's implementation. - execve runs #! scripts, and says ENOEXEC for what it cannot run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
6f3175d8a5
commit
2cfa3f0bf2
9 changed files with 361 additions and 129 deletions
|
|
@ -76,6 +76,52 @@ vma_note_anon(struct proc *p, uint64 va, uint64 len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Nothing recorded and nothing mapped anywhere in [va, va+len).
|
||||
static int
|
||||
range_free(struct proc *p, uint64 va, uint64 len)
|
||||
{
|
||||
for (int i = 0; i < NVMA; i++) {
|
||||
struct vma *v = &p->vma[i];
|
||||
if (v->used && va < v->addr + v->length && v->addr < va + len)
|
||||
return 0;
|
||||
}
|
||||
for (uint64 a = va; a < va + len; a += PGSIZE)
|
||||
if (uva2ka(p->pgdir, (char *)a))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Where a new mapping of `len` goes.
|
||||
//
|
||||
// Fresh addresses from the bump pointer, except for memory that can merge:
|
||||
// that goes straight after an anonymous mapping whose end has room, so it
|
||||
// extends the record rather than taking a slot. Without this a slot was
|
||||
// spent each time the record that ended at the bump pointer had been trimmed,
|
||||
// and every time munmap split one -- and musl's malloc frees 32 KB pieces out
|
||||
// of the middle of larger ones all day. apk ran out of NVMA slots within a
|
||||
// second of starting to install, with 780 MB free, and said "Out of memory".
|
||||
// It also gives freed address space back, which the bump pointer never did.
|
||||
static uint64
|
||||
mmap_va(struct proc *p, uint64 len, int mergeable)
|
||||
{
|
||||
if (p->mmap_next == 0)
|
||||
p->mmap_next = 0x40000000;
|
||||
if (mergeable) {
|
||||
for (int i = 0; i < NVMA; i++) {
|
||||
struct vma *v = &p->vma[i];
|
||||
uint64 e = v->addr + v->length;
|
||||
if (vma_anon(v) && e >= 0x40000000 && e + len <= p->mmap_next &&
|
||||
range_free(p, e, len))
|
||||
return e;
|
||||
}
|
||||
}
|
||||
uint64 va = p->mmap_next;
|
||||
if (bad_user_range(va, len))
|
||||
return 0;
|
||||
p->mmap_next += len;
|
||||
return va;
|
||||
}
|
||||
|
||||
// Record [va, va+len) as anonymous memory wherever no mapping already covers
|
||||
// it, for a MAP_FIXED that may land anywhere: inside an earlier mapping, across
|
||||
// the end of one, or in a gap. Below sz is the program image and its heap,
|
||||
|
|
@ -210,13 +256,13 @@ sys_mmap(void)
|
|||
// slot index, which a single allocation bigger than 8MB — e.g. a large
|
||||
// realloc() growth — could map straight past, panicking mappages("remap")
|
||||
// when it hit an already-present PTE in the next slot's territory).
|
||||
// munmap()'d ranges are not reclaimed for reuse; that's fine at this scale.
|
||||
if (myproc()->mmap_next == 0)
|
||||
myproc()->mmap_next = 0x40000000;
|
||||
va = myproc()->mmap_next;
|
||||
if (bad_user_range(va, length))
|
||||
// Anonymous memory and private file copies may also reuse a freed range
|
||||
// next to an existing one; see mmap_va().
|
||||
int mergeable = !(f && (f->type == FD_MEMFD ||
|
||||
(f->type == FD_INODE && f->ip->type == T_DEV)));
|
||||
va = mmap_va(myproc(), length, mergeable);
|
||||
if (va == 0)
|
||||
return -ENOMEM;
|
||||
myproc()->mmap_next += length;
|
||||
|
||||
int is_fb = 0;
|
||||
int shmid = -1;
|
||||
|
|
|
|||
Loading…
Reference in a new issue