flock, fcntl record locks

There were none: fcntl answered F_SETLK with EINVAL and flock was not a
system call. Alpine's apk, which runs unmodified on SchOS through
Alpine's own musl, locks its database before reading it and stopped
there.

kernel/fs/lock.c keeps one table of advisory locks keyed by (dev, inum):
flock() for the whole file, owned by the open file description;
F_SETLK/F_SETLKW/F_GETLK for byte ranges, owned by the process and
released when it closes any descriptor on the file or exits; and the
F_OFD_* forms, ranges owned by the description. flock and record locks
do not see each other, as on Linux. Waiters sleep until any release and
are interrupted by a signal.

cmd/locktest checks each between a parent and a child, including range
splitting, F_GETLK's report, and a blocked waiter being woken.

shell.nix gains pkg-config, meson, ninja, m4, bison, flex and xz, for
the X ports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-24 12:22:36 +02:00
commit 6f3175d8a5
11 changed files with 562 additions and 2 deletions

View file

@ -332,10 +332,20 @@ addr_t sys_close(void)
if (argfd(0, &fd, &f) < 0) return -EBADF;
myproc()->ofile[fd] = 0;
myproc()->ofile_flags[fd] = 0;
lock_close_fd(f);
fileclose(f);
return 0;
}
addr_t sys_flock(void)
{
struct file *f;
int op;
if (argfd(0, 0, &f) < 0) return -EBADF;
if (argint(1, &op) < 0) return -EINVAL;
return lock_flock(f, op);
}
addr_t
sys_fcntl(void)
{
@ -374,6 +384,13 @@ sys_fcntl(void)
case F_SETFL:
f->nonblock = (arg & O_NONBLOCK) != 0;
return 0;
case F_GETLK: case F_SETLK: case F_SETLKW:
case F_OFD_GETLK: case F_OFD_SETLK: case F_OFD_SETLKW: {
// A pointer, which argint() above would have cut to 32 bits.
uint64 a;
if (argaddr(2, &a) < 0) return -EFAULT;
return lock_fcntl(f, cmd, (addr_t)a);
}
}
return -EINVAL;
}