kernel: introduce devswap #¶ to serve /dev/swap and handle swapfile encryption

This commit is contained in:
cinap_lenrek 2017-10-29 23:09:54 +01:00
parent 93117262c2
commit f3f9392517
44 changed files with 273 additions and 142 deletions

View file

@ -10,6 +10,7 @@ bind #p /proc
bind -c #s /srv
bind -q #σ /shr
bind -a #¤ /dev
bind -qa #¶ /dev
# authentication
mount -b /srv/factotum /mnt

View file

@ -22,7 +22,6 @@ cons \- console, clocks, process/process group ids, user, null, reboot, etc.
.B /dev/ppid
.B /dev/random
.B /dev/reboot
.B /dev/swap
.B /dev/sysname
.B /dev/sysstat
.B /dev/time
@ -240,41 +239,6 @@ Writing anything to
.B sysstat
resets all of the counts on all processors.
.PP
The
.B swap
device holds a text block giving memory usage statistics:
.IP
.EX
\fIn\fP memory
\fIn\fP pagesize
\fIn\fP kernel
\fIn\fP/\fIm\fP user
\fIn\fP/\fIm\fP swap
\fIa\fP/\fIn\fP/\fIm\fP kernel malloc
\fIa\fP/\fIn\fP/\fIm\fP kernel draw
.EE
.PP
These are total memory (bytes), system page size (bytes),
kernel memory (pages), user memory (pages), swap space (pages),
kernel malloced data (bytes), and kernel graphics data (bytes).
The expression
.IR n / m
indicates
.I n
used out of
.I m
available.
For kernel malloc and kernel draw,
.IR a
indicates the current allocation in bytes.
These numbers are not blank padded.
.PP
To turn on swapping, write to
.B swap
the textual file descriptor number of a file or device on which to swap.
See
.IR swap (8).
.PP
Reads and writes to
.IR mordor
will inevitably cause the front to fall off.

46
sys/man/3/swap Normal file
View file

@ -0,0 +1,46 @@
.TH SWAP 3
.SH NAME
swap \- memory usage statistics and pagefile control
.SH SYNOPSIS
.nf
.B bind -a #¶ /dev
.B /dev/swap
.fi
.SH DESCRIPTION
The
.B swap
device holds a text block giving memory usage statistics:
.IP
.EX
\fIn\fP memory
\fIn\fP pagesize
\fIn\fP kernel
\fIn\fP/\fIm\fP user
\fIn\fP/\fIm\fP swap
\fIa\fP/\fIn\fP/\fIm\fP kernel malloc
\fIa\fP/\fIn\fP/\fIm\fP kernel draw
.EE
.PP
These are total memory (bytes), system page size (bytes),
kernel memory (pages), user memory (pages), swap space (pages),
kernel malloced data (bytes), and kernel graphics data (bytes).
The expression
.IR n / m
indicates
.I n
used out of
.I m
available.
For kernel malloc and kernel draw,
.IR a
indicates the current allocation in bytes.
These numbers are not blank padded.
.PP
To turn on swapping, write to
.B swap
the textual file descriptor number of a file or device on which to swap.
.SH SEE ALSO
.IR swap (8).
.SH SOURCE
.B /sys/src/9/port/devswap.c

View file

@ -35,4 +35,5 @@ will lead to deadlock if the process isn't made non-swappable
ctl-message in
.IR proc (3)).
.SH "SEE ALSO"
.IR swap (3),
.IR proc (3)

View file

@ -270,7 +270,6 @@ main(void)
links();
chandevreset(); /* most devices are discovered here */
pageinit();
swapinit();
userinit();
gpiomeminit();
schedinit();

View file

@ -33,7 +33,6 @@ PORT=\
rdb.$O\
rebootcmd.$O\
segment.$O\
swap.$O\
syscallfmt.$O\
sysfile.$O\
sysproc.$O\

View file

@ -1,6 +1,7 @@
dev
root
cons
swap
env
pipe
proc

View file

@ -1,6 +1,7 @@
dev
root
cons
swap
env
pipe
proc

View file

@ -10,7 +10,7 @@ unmount /root
bind -q '#d' /fd
bind -q '#p' /proc
for(i in S f k æ t b m)
for(i in ¶ P S f k æ t b m)
bind -qa '#'^$i /dev
# bind in an ip interface

View file

@ -322,7 +322,6 @@ wave(' ');
chandevreset(); /* most devices are discovered here */
pageinit();
swapinit();
userinit();
schedinit();
panic("schedinit returned");

View file

@ -32,7 +32,6 @@ PORT=\
qio.$O\
qlock.$O\
segment.$O\
swap.$O\
syscallfmt.$O\
sysfile.$O\
sysproc.$O\

View file

@ -3,6 +3,7 @@
dev
root
cons
swap
env
pipe
proc

View file

@ -35,7 +35,6 @@ main(void)
links();
chandevreset();
pageinit();
swapinit();
fpsave(&initfp);
initfp.fpscr = 0;
userinit();

View file

@ -30,7 +30,6 @@ PORT=\
qlock.$O\
rdb.$O\
segment.$O\
swap.$O\
sysfile.$O\
sysproc.$O\
taslock.$O\

View file

@ -1,6 +1,7 @@
dev
root
cons
swap
arch
pnp pci
env

View file

@ -1,6 +1,7 @@
dev
root
cons
swap
arch
pnp pci
env

View file

@ -2,6 +2,7 @@
dev
root
cons
swap
env
pipe
proc

View file

@ -276,7 +276,6 @@ wave('l');
// i8250console(); /* too early; see init0 */
pageinit();
swapinit();
userinit();
schedinit();
}

View file

@ -33,7 +33,6 @@ PORT=\
qio.$O\
qlock.$O\
segment.$O\
swap.$O\
sysfile.$O\
sysproc.$O\
taslock.$O\

View file

@ -62,7 +62,6 @@ main(void)
chandevreset();
netconsole();
pageinit();
swapinit();
userinit();
schedinit();
}

View file

@ -35,7 +35,6 @@ PORT=\
rdb.$O\
rebootcmd.$O\
segment.$O\
swap.$O\
syscallfmt.$O\
sysfile.$O\
sysproc.$O\

View file

@ -2,6 +2,7 @@
dev
root
cons
swap
arch
pnp pci
env

View file

@ -332,7 +332,6 @@ main()
netconsole();
preallocpages();
pageinit();
swapinit();
userinit();
schedinit();
}

View file

@ -33,7 +33,6 @@ PORT=\
rdb.$O\
rebootcmd.$O\
segment.$O\
swap.$O\
syscallfmt.$O\
sysfile.$O\
sysproc.$O\

View file

@ -2,6 +2,7 @@
dev
root
cons
swap
arch
pnp pci
env

View file

@ -5,7 +5,6 @@
#include "fns.h"
#include "../port/error.h"
#include <pool.h>
#include <authsrv.h>
void (*consdebug)(void) = nil;
@ -324,7 +323,6 @@ enum{
Qppid,
Qrandom,
Qreboot,
Qswap,
Qsysname,
Qsysstat,
Qtime,
@ -357,7 +355,6 @@ static Dirtab consdir[]={
"ppid", {Qppid}, NUMSIZE, 0444,
"random", {Qrandom}, 0, 0444,
"reboot", {Qreboot}, 0, 0664,
"swap", {Qswap}, 0, 0664,
"sysname", {Qsysname}, 0, 0664,
"sysstat", {Qsysstat}, 0, 0666,
"time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
@ -471,8 +468,6 @@ consread(Chan *c, void *buf, long n, vlong off)
int i, k, id;
vlong offset = off;
extern char configfile[];
extern Image fscache;
extern Image swapimage;
if(n <= 0)
return n;
@ -592,33 +587,6 @@ consread(Chan *c, void *buf, long n, vlong off)
poperror();
return n;
case Qswap:
snprint(tmp, sizeof tmp,
"%llud memory\n"
"%llud pagesize\n"
"%lud kernel\n"
"%lud/%lud user\n"
"%lud/%lud swap\n"
"%llud/%llud/%llud kernel malloc\n"
"%llud/%llud/%llud kernel draw\n"
"%llud/%llud/%llud kernel secret\n",
(uvlong)conf.npage*BY2PG,
(uvlong)BY2PG,
conf.npage-conf.upages,
palloc.user-palloc.freecount-fscache.pgref-swapimage.pgref, palloc.user,
conf.nswap-swapalloc.free, conf.nswap,
(uvlong)mainmem->curalloc,
(uvlong)mainmem->cursize,
(uvlong)mainmem->maxsize,
(uvlong)imagmem->curalloc,
(uvlong)imagmem->cursize,
(uvlong)imagmem->maxsize,
(uvlong)secrmem->curalloc,
(uvlong)secrmem->cursize,
(uvlong)secrmem->maxsize);
return readstr((ulong)offset, buf, n, tmp);
case Qsysname:
if(sysname == nil)
return 0;
@ -669,8 +637,7 @@ conswrite(Chan *c, void *va, long n, vlong off)
long l, bp;
char *a;
Mach *mp;
int id, fd;
Chan *swc;
int id;
ulong offset;
Cmdbuf *cb;
Cmdtab *ct;
@ -765,25 +732,6 @@ conswrite(Chan *c, void *va, long n, vlong off)
}
break;
case Qswap:
if(n >= sizeof buf)
error(Egreg);
memmove(buf, va, n); /* so we can NUL-terminate */
buf[n] = 0;
/* start a pager if not already started */
if(strncmp(buf, "start", 5) == 0){
kickpager();
break;
}
if(!iseve())
error(Eperm);
if(buf[0]<'0' || '9'<buf[0])
error(Ebadarg);
fd = strtoul(buf, 0, 0);
swc = fdtochan(fd, ORDWR, 1, 1);
setswapchan(swc);
break;
case Qsysname:
if(offset != 0)
error(Ebadarg);

View file

@ -5,21 +5,29 @@
#include "fns.h"
#include "../port/error.h"
#include <libsec.h>
#include <pool.h>
static int canflush(Proc*, Segment*);
static void executeio(void);
static void pageout(Proc*, Segment*);
static void pagepte(int, Page**);
static void pager(void*);
Image swapimage;
Image swapimage = {
.notext = 1,
};
static int swopen;
static Page **iolist;
static int ioptr;
static Chan *swapchan;
static uchar *swapbuf;
static AESstate *swapkey;
static ushort ageclock;
static Page **iolist;
static int ioptr;
void
static ushort ageclock;
static void
swapinit(void)
{
swapalloc.swmap = xalloc(conf.nswap);
@ -30,10 +38,8 @@ swapinit(void)
swapalloc.xref = 0;
iolist = xalloc(conf.nswppo*sizeof(Page*));
if(swapalloc.swmap == 0 || iolist == 0)
if(swapalloc.swmap == nil || iolist == nil)
panic("swapinit: not enough memory");
swapimage.notext = 1;
}
static uintptr
@ -216,13 +222,8 @@ pageout(Proc *p, Segment *s)
if(!canqlock(s)) /* We cannot afford to wait, we will surely deadlock */
return;
if(!canflush(p, s)) { /* Able to invalidate all tlbs with references */
qunlock(s);
putseg(s);
return;
}
if(waserror()) {
if(!canflush(p, s) /* Able to invalidate all tlbs with references */
|| waserror()) {
qunlock(s);
putseg(s);
return;
@ -389,10 +390,10 @@ needpages(void*)
return palloc.freecount < swapalloc.headroom;
}
void
static void
setswapchan(Chan *c)
{
uchar dirbuf[sizeof(Dir)+100];
uchar buf[sizeof(Dir)+100];
Dir d;
int n;
@ -412,8 +413,8 @@ setswapchan(Chan *c)
* to be at most the size of the partition
*/
if(devtab[c->type]->dc != L'M'){
n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
if(n <= 0 || convM2D(dirbuf, n, &d, nil) == 0)
n = devtab[c->type]->stat(c, buf, sizeof buf);
if(n <= 0 || convM2D(buf, n, &d, nil) == 0)
error("stat failed in setswapchan");
if(d.length < conf.nswppo*BY2PG)
error("swap device too small");
@ -425,6 +426,187 @@ setswapchan(Chan *c)
}
c->flag &= ~CCACHE;
cclunk(c);
swapimage.c = c;
poperror();
swapchan = c;
swapimage.c = namec("#¶/swapfile", Aopen, ORDWR, 0);
}
enum {
Qdir,
Qswap,
Qswapfile,
};
static Dirtab swapdir[]={
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
"swap", {Qswap}, 0, 0664,
"swapfile", {Qswapfile}, 0, 0600,
};
static Chan*
swapattach(char *spec)
{
return devattach(L'', spec);
}
static Walkqid*
swapwalk(Chan *c, Chan *nc, char **name, int nname)
{
return devwalk(c, nc, name, nname, swapdir, nelem(swapdir), devgen);
}
static int
swapstat(Chan *c, uchar *dp, int n)
{
return devstat(c, dp, n, swapdir, nelem(swapdir), devgen);
}
static Chan*
swapopen(Chan *c, int omode)
{
uchar key[128/8];
switch((ulong)c->qid.path){
case Qswapfile:
if(!iseve() || omode != ORDWR)
error(Eperm);
if(swapimage.c != nil)
error(Einuse);
if(swapchan == nil)
error(Egreg);
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
swapbuf = mallocalign(BY2PG, BY2PG, 0, 0);
swapkey = secalloc(sizeof(AESstate)*2);
if(swapbuf == nil || swapkey == nil)
error(Enomem);
genrandom(key, sizeof(key));
setupAESstate(&swapkey[0], key, sizeof(key), nil);
genrandom(key, sizeof(key));
setupAESstate(&swapkey[1], key, sizeof(key), nil);
memset(key, 0, sizeof(key));
return c;
}
return devopen(c, omode, swapdir, nelem(swapdir), devgen);
}
static void
swapclose(Chan *c)
{
if((c->flag & COPEN) == 0)
return;
switch((ulong)c->qid.path){
case Qswapfile:
cclose(swapchan);
swapchan = nil;
secfree(swapkey);
swapkey = nil;
free(swapbuf);
swapbuf = nil;
break;
}
}
static long
swapread(Chan *c, void *va, long n, vlong off)
{
char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
switch((ulong)c->qid.path){
case Qdir:
return devdirread(c, va, n, swapdir, nelem(swapdir), devgen);
case Qswap:
snprint(tmp, sizeof tmp,
"%llud memory\n"
"%llud pagesize\n"
"%lud kernel\n"
"%lud/%lud user\n"
"%lud/%lud swap\n"
"%llud/%llud/%llud kernel malloc\n"
"%llud/%llud/%llud kernel draw\n"
"%llud/%llud/%llud kernel secret\n",
(uvlong)conf.npage*BY2PG,
(uvlong)BY2PG,
conf.npage-conf.upages,
palloc.user-palloc.freecount-fscache.pgref-swapimage.pgref, palloc.user,
conf.nswap-swapalloc.free, conf.nswap,
(uvlong)mainmem->curalloc,
(uvlong)mainmem->cursize,
(uvlong)mainmem->maxsize,
(uvlong)imagmem->curalloc,
(uvlong)imagmem->cursize,
(uvlong)imagmem->maxsize,
(uvlong)secrmem->curalloc,
(uvlong)secrmem->cursize,
(uvlong)secrmem->maxsize);
return readstr((ulong)off, va, n, tmp);
case Qswapfile:
if(n != BY2PG)
error(Ebadarg);
if(devtab[swapchan->type]->read(swapchan, va, n, off) != n)
error(Eio);
aes_xts_decrypt(&swapkey[0], &swapkey[1], off, va, va, n);
return n;
}
error(Egreg);
return 0;
}
static long
swapwrite(Chan *c, void *va, long n, vlong off)
{
char buf[256];
switch((ulong)c->qid.path){
case Qswap:
if(!iseve())
error(Eperm);
if(n >= sizeof buf)
error(Egreg);
memmove(buf, va, n); /* so we can NUL-terminate */
buf[n] = 0;
/* start a pager if not already started */
if(strncmp(buf, "start", 5) == 0)
kickpager();
else if(buf[0]>='0' && '9'<=buf[0])
setswapchan(fdtochan(strtoul(buf, nil, 0), ORDWR, 1, 1));
else
error(Ebadctl);
return n;
case Qswapfile:
if(n != BY2PG)
error(Ebadarg);
aes_xts_encrypt(&swapkey[0], &swapkey[1], off, va, swapbuf, n);
if(devtab[swapchan->type]->write(swapchan, swapbuf, n, off) != n)
error(Eio);
return n;
}
error(Egreg);
return 0;
}
Dev swapdevtab = {
L'',
"swap",
devreset,
swapinit,
devshutdown,
swapattach,
swapwalk,
swapstat,
swapopen,
devcreate,
swapclose,
swapread,
devbread,
swapwrite,
devbwrite,
devremove,
devwstat,
};

View file

@ -318,7 +318,6 @@ int setlabel(Label*);
void setmalloctag(void*, uintptr);
void setrealloctag(void*, uintptr);
void setregisters(Ureg*, char*, char*, int);
void setswapchan(Chan*);
void setupwatchpts(Proc*, Watchpt*, int);
char* skipslash(char*);
void sleep(Rendez*, int(*)(void*), void*);
@ -332,7 +331,6 @@ void srvrenameuser(char*, char*);
void shrrenameuser(char*, char*);
int swapcount(uintptr);
int swapfull(void);
void swapinit(void);
void syscallfmt(ulong syscallno, uintptr pc, va_list list);
void sysretfmt(ulong syscallno, va_list list, uintptr ret, uvlong start, uvlong stop);
void timeradd(Timer*);

View file

@ -62,15 +62,15 @@ errstr.h: ../port/mkerrstr ../port/error.h
%.db: main.$O
$CC -s$stem main.c | dbfmt > $stem.db
alloc.$O: /sys/include/pool.h
alloc.$O devswap.$O: /sys/include/pool.h
devmnt.$O: /sys/include/fcall.h
proc.$O proc.acid: errstr.h
devroot.$O: errstr.h
devaudio.$O: ../port/audioif.h
devaoe.$O: /$objtype/include/ureg.h
devfs.$O: /$objtype/include/ureg.h
devsd.$O: /$objtype/include/ureg.h
sdscsi.$O: /$objtype/include/ureg.h
devaoe.$O: ../port/sd.h /$objtype/include/ureg.h
devfs.$O: ../port/sd.h /$objtype/include/ureg.h
devsd.$O: ../port/sd.h /$objtype/include/ureg.h
sdscsi.$O: ../port/sd.h /$objtype/include/ureg.h
trap.$O: /$objtype/include/ureg.h
devproc.$O: /$objtype/include/ureg.h
main.$O: init.h
@ -87,3 +87,5 @@ unthwack.$O: ../port/thwack.h
devsdp.$O: ../port/thwack.h
devproc.$O sysproc.$O: /sys/include/tos.h
devproc.$O edf.$O proc.$O: /sys/include/trace.h
devcons.$O: /sys/include/authsrv.h
devcap.$O devfs.$O devsdp.$O devssl.$O devtls.$O devswap.$O random.$O: /sys/include/libsec.h

View file

@ -1,6 +1,7 @@
dev
root
cons
swap
env
flash
pipe

View file

@ -84,7 +84,6 @@ main(void)
links();
chandevreset();
pageinit();
swapinit();
sharedseginit();
fpsave(&initfp);
initfp.fpscr = 0;

View file

@ -31,7 +31,6 @@ PORT=\
qlock.$O\
rdb.$O\
segment.$O\
swap.$O\
sysfile.$O\
sysproc.$O\
taslock.$O\

View file

@ -1,6 +1,7 @@
dev
root
cons
swap
uart
mnt
srv

View file

@ -192,8 +192,6 @@ main(void)
initseg();
links();
chandevreset();
swapinit();
userinit();
schedinit();
panic("schedinit returned");

View file

@ -38,7 +38,6 @@ PORT=\
rdb.$O\
rebootcmd.$O\
segment.$O\
swap.$O\
syscallfmt.$O\
sysfile.$O\
sysproc.$O\

View file

@ -455,7 +455,6 @@ main(void)
// i8250console(); /* too early; see init0 */
pageinit(); /* prints "1020M memory: ⋯ */
swapinit();
userinit();
/*

View file

@ -34,7 +34,6 @@ PORT=\
qio.$O\
qlock.$O\
segment.$O\
swap.$O\
syscallfmt.$O\
sysfile.$O\
sysproc.$O\

View file

@ -2,6 +2,7 @@
dev
root
cons
swap
env
pipe
proc

View file

@ -103,8 +103,6 @@ main(void)
// conf.monitor = 1;
chandevreset();
pageinit();
swapinit();
userinit();
schedinit();
}

View file

@ -32,7 +32,6 @@ PORT=\
qlock.$O\
rebootcmd.$O\
segment.$O\
swap.$O\
sysfile.$O\
sysproc.$O\
taslock.$O\

View file

@ -1,6 +1,7 @@
dev
root netif
cons
swap
uart
arch
env

View file

@ -393,7 +393,6 @@ main(void)
archinit();
chandevreset();
pageinit();
swapinit();
screeninit();
userinit();
schedinit();

View file

@ -31,7 +31,6 @@ PORT=\
qio.$O\
qlock.$O\
segment.$O\
swap.$O\
sysfile.$O\
sysproc.$O\
taslock.$O\

View file

@ -1,6 +1,7 @@
dev
root
cons
swap
arch
uart
mnt