ext4srv: reduce the number of options, align more with existing filesystems

Also provide saner defaults (block size 4k instead of 1k).
Cache write back is always enabled now as well.
This commit is contained in:
Sigrid Solveig Haflínudóttir 2024-04-27 16:26:55 +00:00
parent ce86e64ee0
commit 9ebd6f860e
4 changed files with 126 additions and 159 deletions

View file

@ -4,34 +4,29 @@ ext4srv \- ext4 file system
.SH SYNOPSIS
.B ext4srv
[
.B -Crs
.B -Ss
] [
.B -f
.I file
] [
.B -g
.I groupfile
] [
.B -R
.I uid
.B -n
.I srvname
] [
.I service
]
.PP
.B ext4srv
.B -M
.B -r
.I (2|3|4)
[
.B -L
.I label
] [
.B -b
.I blksize
] [
.B -N
.I numinodes
] [
.B -I
.I inodesize
] [
.B -L
.I label
]
.I device
.SH DESCRIPTION
.I Ext4srv
is a file server that interprets the Linux Second, Third and Fourth
@ -43,20 +38,20 @@ simultaneously.
.PP
.I Ext4srv
posts a file descriptor named
.I service
.I srvname
(default
.BR ext4 )
in the
.B /srv
directory.
To access an ext4 file system on a device, use
directory. To access an ext4 file system on a device, use
.B mount
with the
.I spec
argument
(see
.IR bind (1))
the name of the file holding the raw ext4 file system, typically the disk or partition.
the name of the file holding the raw ext4 file system, typically the
disk or partition.
If
.I spec
is undefined in the
@ -68,60 +63,52 @@ as the default name for the device holding the file system.
.PP
Normally
.I ext4srv
creates a pipe to act as the communications channel between
itself and its clients.
creates a pipe to act as the communications channel between itself and
its clients.
The
.B -s
flag instructs
.I ext4srv
to use its standard input and output instead.
This flag also prevents the creation of an explicit service file in
to use its standard input and output instead. This flag also prevents
the creation of an explicit service file in
.BR /srv .
.PP
The
.B -r
flag (recommended) makes the file system read-only.
By default,
.I ext4srv
will try to parse and use
.I /etc/group
file for permission checks, if available on the mounted filesystem.
The optional
.B -g
flags specify Unix-format group file that give the mapping between the
numeric user- and group-ID numbers in the ext4 file system and the
strings reported by Plan 9 status inquiries.
flag specifies Unix-format group file that gives the mapping between
the numeric user- and group-ID numbers in the Extended file system and
the strings reported by Plan 9 status inquiries. The file is assumed
to reside on the filesystem where
.I ext4srv
executable is running, not the one to be mounted.
.PP
With
.B -R
option the filesystem can be mounted in "root" mode, allowing full access regardless
of permissions. The usual
.I uid
in this case is
.IR 0 .
.SH MKFS
A different mode of
.I ext4srv
is enabled with
.B -M
option that accepts the file system version
.RI ( 2
for
.I ext2
and so on).
In this mode filesystem is initialized on the specified
.I device
and all existing data on it is destroyed.
.B -S
option the filesystem can be mounted in "root" mode, allowing full
access, regardless of permissions.
.PP
Additional options may be specified, for example
.B -L
may be used to set the filesystem label.
With
.B -r
option the filesystem will be reamed - the old data erased and the
file reformatted as specified. An optional label can be specified
with
.BR -L ,
block size (default is 4096 bytes) with
.B -b
and
inode size (default is 256 bytes) with
.BR -I .
.SH SOURCE
.B /sys/src/cmd/ext4srv
.SH BUGS
Yes.
.PP
Permission checking is very basic and may not be complete.
.SH NOTES
Symlinks are not resolved.
There may be many bugs.
It is advisable to use
.I ext4srv
in read-only mode whenever possible.
.SH BUGS
There may be bugs - no refunds.
.SH HISTORY
.I Ext4srv
first appeared in 9front (February, 2024).

View file

@ -3,14 +3,10 @@ typedef struct Part Part;
struct Opts {
char *group;
int cachewb;
int asroot;
int rdonly;
int fstype;
int ream;
int blksz;
int inodesz;
u32int ninode;
char *label;
};

View file

@ -30,23 +30,17 @@ struct Aux {
enum {
Adir,
Afile,
Root = 0,
};
static Opts opts = {
.group = nil,
.cachewb = 0,
.asroot = 0,
.rdonly = 0,
.fstype = -1,
.blksz = 1024,
.label = "",
.inodesz = 256,
.ninode = 0,
};
static u32int Root;
static u8int zero[65536];
static char *srvname = "ext4";
static char *srvname;
static char *device;
static Part *devpart;
static int
haveperm(Aux *a, int p, struct ext4_inode *inodeout)
@ -115,27 +109,31 @@ haveperm(Aux *a, int p, struct ext4_inode *inodeout)
static void
rattach(Req *r)
{
char err[ERRMAX];
Aux *a;
if((a = calloc(1, sizeof(*a))) == nil)
respond(r, "memory");
else if((a->p = openpart(r->ifcall.aname, &opts)) == nil){
free(a);
rerrstr(err, sizeof(err));
respond(r, err);
}else{
if(opts.asroot || findgroup(&a->p->groups, r->ifcall.uname, &a->uid) == nil)
a->uid = Root;
incref(a->p);
a->type = Adir;
a->path = estrdup9p("");
r->ofcall.qid = a->p->qidmask;
r->fid->qid = a->p->qidmask;
r->fid->aux = a;
respond(r, nil);
if(r->ifcall.aname && *r->ifcall.aname){
if((a->p = openpart(r->ifcall.aname, &opts)) == nil){
free(a);
responderror(r);
return;
}
}else if((a->p = devpart) == nil){
respond(r, "no file specified");
return;
}
if(opts.asroot || findgroup(&a->p->groups, r->ifcall.uname, &a->uid) == nil)
a->uid = Root;
incref(a->p);
a->type = Adir;
a->path = estrdup9p("");
r->ofcall.qid = a->p->qidmask;
r->fid->qid = a->p->qidmask;
r->fid->aux = a;
respond(r, nil);
}
static u32int
@ -573,7 +571,7 @@ rwstat(Req *r)
wrperm = haveperm(a, OWRITE, &inode);
uid = ext4_inode_get_uid(&inode);
isowner = uid == Root || a->uid == uid;
isowner = a->uid == Root || a->uid == uid;
/* permission to truncate */
isdir = ext4_inode_type(a->p->sb, &inode) == EXT4_INODE_MODE_DIRECTORY;
@ -876,8 +874,9 @@ static Srv fs = {
static void
usage(void)
{
fprint(2, "usage: %s [-Crs] [-g groupfile] [-R uid] [srvname]\n", argv0);
fprint(2, "mkfs: %s -M (2|3|4) [-L label] [-b blksize] [-N numinodes] [-I inodesize] device\n", argv0);
fprint(2,
"usage: %s [-Ss] [-f file] [-g groupfile] [-n srvname] [-r (2|3|4)]"
" [-b blksize] [-I inodesize] [-L label]\n", argv0);
threadexitsall("usage");
}
@ -891,20 +890,19 @@ threadmain(int argc, char **argv)
rfork(RFNOTEG);
stdio = 0;
device = nil;
ARGBEGIN{
case 'D':
chatty9p++;
nomkfs:
if(opts.fstype > 0)
usage();
opts.fstype = 0;
break;
case 'd':
ext4_dmask_set(strtoul(EARGF(usage()), nil, 0));
break;
case 'C':
opts.cachewb = 1;
goto nomkfs;
case 'f':
if(device != nil)
usage();
device = EARGF(usage());
break;
case 'g':
gr = EARGF(usage());
if((f = open(gr, OREAD)) < 0)
@ -919,70 +917,62 @@ nomkfs:
sysfatal("%s: read failed", gr);
close(f);
opts.group[sz] = 0;
goto nomkfs;
case 'R':
opts.asroot = 1;
Root = atoll(EARGF(usage()));
goto nomkfs;
case 'r':
opts.rdonly = 1;
goto nomkfs;
break;
case 'n':
if(stdio != 0)
usage();
srvname = EARGF(usage());
break;
case 's':
stdio = 1;
goto nomkfs;
case 'M':
if(!opts.fstype)
usage();
opts.fstype = atoi(EARGF(usage()));
if(opts.fstype < 2 || opts.fstype > 4)
if(srvname != nil)
usage();
break;
case 'S':
opts.asroot = 1;
break;
case 'b':
opts.blksz = atoi(EARGF(usage()));
if(opts.blksz != 1024 && opts.blksz != 2048 && opts.blksz != 4096)
usage();
yesmkfs:
if(opts.fstype < 1)
usage();
break;
case 'L':
opts.label = EARGF(usage());
goto yesmkfs;
case 'I':
opts.inodesz = atoi(EARGF(usage()));
if(opts.inodesz < 128 || ((opts.inodesz-1) & opts.inodesz) != 0)
usage();
goto yesmkfs;
case 'N':
opts.ninode = atoi(EARGF(usage()));
if(opts.ninode < 1)
break;
case 'L':
opts.label = EARGF(usage());
break;
case 'r':
if(opts.ream > 0)
usage();
goto yesmkfs;
opts.ream = atoi(EARGF(usage()));
if(opts.ream < 2 || opts.ream > 4)
usage();
break;
default:
usage();
}ARGEND
if(opts.fstype > 1){
if(argc != 1)
usage();
if(openpart(argv[0], &opts) == nil)
sysfatal("%r");
closeallparts();
threadexitsall(nil);
}else{
if(!stdio && argc == 1)
srvname = *argv;
else if(argc != 0)
usage();
if(argc != 0)
usage();
if(stdio){
fs.infd = 0;
fs.outfd = 1;
threadsrv(&fs);
}else
threadpostsrv(&fs, srvname);
threadexits(nil);
if(device == nil && opts.ream > 1)
usage();
if(device != nil && (devpart = openpart(device, &opts)) == nil)
sysfatal("%r");
if(stdio){
fs.infd = 0;
fs.outfd = 1;
threadsrv(&fs);
}else{
if(srvname == nil)
srvname = "ext4";
threadpostsrv(&fs, srvname);
}
threadexits(nil);
}

View file

@ -154,16 +154,12 @@ static void *
readfile(Part *p, char *path, usize *sz)
{
usize n, got;
char *s, *d;
ext4_file f;
char *d;
int r;
d = nil;
while(*path == '/')
path++;
s = smprint("/%s", path);
r = ext4_fopen2(&p->mp, &f, s, O_RDONLY);
free(s);
r = ext4_fopen2(&p->mp, &f, path, O_RDONLY);
if(r == 0){
*sz = ext4_fsize(&f);
@ -203,7 +199,7 @@ mountpart(Part *p, Opts *opts)
int r;
mp = &p->mp;
if(ext4_mount(mp, &p->bdev, opts->rdonly) < 0){
if(ext4_mount(mp, &p->bdev, 0) < 0){
werrstr("mount: %r");
goto error;
}
@ -219,8 +215,7 @@ mountpart(Part *p, Opts *opts)
werrstr("journal: %r");
goto error;
}
if(opts->cachewb)
ext4_cache_write_back(mp, 1);
ext4_cache_write_back(mp, 1);
if(ext4_get_sblock(mp, &p->sb) < 0){
werrstr("sblock: %r");
@ -230,7 +225,7 @@ mountpart(Part *p, Opts *opts)
r = 0;
if(opts->group != nil){
r = loadgroups(&p->groups, opts->group);
}else if((gr = readfile(p, "/etc/group", &sz)) != nil){
}else if((gr = readfile(p, "etc/group", &sz)) != nil){
gr[sz] = 0;
r = loadgroups(&p->groups, gr);
free(gr);
@ -307,19 +302,18 @@ openpart(char *dev, Opts *opts)
p->partdev = (char*)(p+1) + blksz;
strcpy(p->partdev, dev);
if(opts->fstype > 1){
if(opts->ream > 1){
memset(&fs, 0, sizeof(fs));
memset(&info, 0, sizeof(info));
info.block_size = opts->blksz;
snprint(info.label, sizeof(info.label), opts->label);
info.inode_size = opts->inodesz;
info.inodes = opts->ninode;
info.journal = opts->fstype > 2;
info.journal = opts->ream > 2;
for(i = 0; i < 16; i += 4){
rn = truerand();
memcpy(info.uuid+i, &rn, 4);
}
if(ext4_mkfs(&fs, &p->bdev, &info, opts->fstype) < 0){
if(ext4_mkfs(&fs, &p->bdev, &info, opts->ream) < 0){
werrstr("mkfs: %r");
goto error;
}