ref: a6e5d4bae6075c741a39fcba62a365d9dffaed93
dir: /sys/src/cmd/ext4srv/part.c/
#include "ext4_config.h"
#include "ext4.h"
#include <thread.h>
#include "ext4_mkfs.h"
#include "group.h"
#include "common.h"
#define TRACE(fmt, ...) //fprint(2, fmt, __VA_ARGS__)
#define BDEV2PART(bdev) ((bdev)->bdif->p_user)
static struct {
QLock;
Part *ps;
u32int id;
}sv;
static long
preadn(int f, void *av, long n, vlong offset)
{
char *a;
long m, t;
assert(offset >= 0);
a = av;
t = 0;
while(t < n){
m = pread(f, a+t, n-t, offset);
if(m <= 0){
if(t == 0)
return m;
break;
}
t += m;
offset += m;
}
return t;
}
static int
bdopen(struct ext4_blockdev *bdev)
{
Part *p;
p = BDEV2PART(bdev);
TRACE("bdopen %p\n", p);
USED(p);
return 0;
}
static int
bdread(struct ext4_blockdev *bdev, void *buf, u64int blkid, u32int blkcnt)
{
Part *p;
p = BDEV2PART(bdev);
TRACE("bdread %p %p %llud %ud\n", p, buf, blkid, blkcnt);
if(preadn(p->f, buf, blkcnt*p->bdif.ph_bsize, blkid*p->bdif.ph_bsize) != blkcnt*p->bdif.ph_bsize)
return -1;
return 0;
}
static int
bdwrite(struct ext4_blockdev *bdev, const void *buf, u64int blkid, u32int blkcnt)
{
Part *p;
p = BDEV2PART(bdev);
TRACE("bdwrite %p %p %llud %ud\n", p, buf, blkid, blkcnt);
if(pwrite(p->f, buf, blkcnt*p->bdif.ph_bsize, blkid*p->bdif.ph_bsize) != blkcnt*p->bdif.ph_bsize)
return -1;
return 0;
}
static int
bdclose(struct ext4_blockdev *bdev)
{
Part *p;
p = BDEV2PART(bdev);
TRACE("bdclose %p\n", p);
USED(p);
return 0;
}
static int
getblksz(char *dev, u32int *blksz)
{
char *s, *e, *g, *a[5];
vlong x;
int f, n, r;
/* default blksz if couldn't find out the real one */
*blksz = 512;
f = -1;
g = nil;
if((s = smprint("%s_ctl", dev)) == nil)
goto error;
cleanname(s);
if((e = strrchr(s, '/')) == nil)
e = s;
strcpy(e, "/ctl");
f = open(s, OREAD);
free(s);
if(f >= 0){
if((g = malloc(4096)) == nil)
goto error;
for(n = 0; (r = read(f, g+n, 4096-n-1)) > 0; n += r);
g[n] = 0;
close(f);
f = -1;
for(s = g; (e = strchr(s, '\n')) != nil; s = e+1){
*e = 0;
if(tokenize(s, a, nelem(a)) >= 3 && strcmp(a[0], "geometry") == 0){
x = strtoll(a[2], &e, 0);
if(x > 0 && *e == 0)
*blksz = x;
if(*blksz != x){
werrstr("invalid block size: %s", a[2]);
goto error;
}
break;
}
}
}
close(f);
free(g);
return 0;
error:
close(f);
free(g);
return -1;
}
static int
fmtpart(Fmt *f)
{
Part *p;
p = va_arg(f->args, Part*);
return fmtprint(f, f->r == 'M' ? "/%#llux" : "dev%#llux", p->qid.path);
}
static void *
readfile(Part *p, char *path, usize *sz)
{
usize n, got;
ext4_file f;
char *d;
int r;
d = nil;
r = ext4_fopen2(&p->mp, &f, path, O_RDONLY);
if(r == 0){
*sz = ext4_fsize(&f);
if((d = malloc(*sz+1)) == nil){
ext4_fclose(&f);
goto error;
}
for(n = 0; n < *sz; n += got){
if(ext4_fread(&f, d+n, *sz-n, &got) < 0){
werrstr("readfile: %r");
ext4_fclose(&f);
goto error;
}
if(got == 0)
break;
}
*sz = n;
ext4_fclose(&f);
}else{
error:
free(d);
d = nil;
*sz = 0;
}
return d;
}
static int
mountpart(Part *p, Opts *opts)
{
struct ext4_mountpoint *mp;
usize sz;
char *gr;
int r;
mp = &p->mp;
if(ext4_mount(mp, &p->bdev, 0) < 0){
werrstr("mount: %r");
goto error;
}
if(ext4_mount_setup_locks(mp, &p->oslocks) < 0){
werrstr("locks: %r");
goto error;
}
if(ext4_recover(mp) < 0){
werrstr("recover: %r");
goto error;
}
if(ext4_journal_start(mp) < 0){
werrstr("journal: %r");
goto error;
}
ext4_cache_write_back(mp, 1);
if(ext4_get_sblock(mp, &p->sb) < 0){
werrstr("sblock: %r");
goto error;
}
r = 0;
if(opts->group != nil){
r = loadgroups(&p->groups, opts->group);
}else if((gr = readfile(p, "etc/group", &sz)) != nil){
gr[sz] = 0;
r = loadgroups(&p->groups, gr);
free(gr);
}
if(r != 0)
goto error;
return 0;
error:
werrstr("mountpart: %r");
return -1;
}
static void
plock(void *aux)
{
Part *p;
p = aux;
qlock(p);
}
static void
punlock(void *aux)
{
Part *p;
p = aux;
qunlock(p);
}
Part *
openpart(char *dev, Opts *opts)
{
struct ext4_mkfs_info info;
struct ext4_fs fs;
u32int blksz;
ulong rn;
int f, i;
Part *p;
char *s;
Dir *d;
d = nil;
p = nil;
s = nil;
qlock(&sv);
f = open(dev, ORDWR);
if(f < 0 || (d = dirfstat(f)) == nil)
goto error;
/* see if it's already opened */
for(p = sv.ps; p != nil && p->qid.path != d->qid.path; p = p->next);
if(p == nil){ /* no? then make one */
if(getblksz(dev, &blksz) != 0 || (p = calloc(1, sizeof(*p)+blksz+strlen(dev)+1)) == nil)
goto error;
p->f = f;
p->qid = d->qid;
p->bdev.bdif = &p->bdif;
p->bdev.part_size = d->length;
p->bdif.open = bdopen;
p->bdif.bread = bdread;
p->bdif.bwrite = bdwrite;
p->bdif.close = bdclose;
p->bdif.ph_bsize = blksz;
p->bdif.ph_bcnt = d->length/blksz;
p->bdif.ph_bbuf = p->blkbuf;
p->oslocks.lock = plock;
p->oslocks.unlock = punlock;
p->oslocks.p_user = p;
p->bdif.p_user = p;
p->partdev = (char*)(p+1) + blksz;
strcpy(p->partdev, dev);
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.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->ream) < 0){
werrstr("mkfs: %r");
goto error;
}
}
if(mountpart(p, opts) != 0)
goto error;
p->next = sv.ps;
if(sv.ps != nil)
sv.ps->prev = p;
sv.ps = p;
p->qidmask.path = ((uvlong)sv.id++) << 32;
p->qidmask.type = QTDIR;
}else{
close(f);
}
free(d);
free(s);
qunlock(&sv);
return p;
error:
werrstr("openpart: %r");
if(f >= 0)
close(f);
free(d);
free(p);
free(s);
qunlock(&sv);
return nil;
}
static void
_closepart(Part *p)
{
struct ext4_mountpoint *mp;
mp = &p->mp;
ext4_cache_write_back(mp, 0);
if(ext4_journal_stop(mp) < 0)
fprint(2, "closepart: journal: %s: %r\n", p->partdev);
if(ext4_umount(mp) < 0)
fprint(2, "closepart: umount %s: %r\n", p->partdev);
close(p->f);
if(p->prev != nil)
p->prev = p->next;
if(p->next != nil)
p->next->prev = p->prev;
if(p == sv.ps)
sv.ps = p->next;
freegroups(&p->groups);
free(p);
}
void
closepart(Part *p)
{
qlock(&sv);
_closepart(p);
qunlock(&sv);
}
void
closeallparts(void)
{
qlock(&sv);
while(sv.ps != nil)
_closepart(sv.ps);
qunlock(&sv);
}
void
statallparts(void)
{
struct ext4_mount_stats s;
uvlong div;
Part *p;
qlock(&sv);
for(p = sv.ps; p != nil; p = p->next){
if(ext4_mount_point_stats(&p->mp, &s) < 0){
fprint(2, "%s: %r\n", p->partdev);
}else{
print(
"%s (inodes) free %ud, used %ud, total %ud\n",
p->partdev,
s.free_inodes_count,
s.inodes_count-s.free_inodes_count,
s.inodes_count
);
print(
"%s (blocks) free %llud, used %llud, total %llud, each %ud\n",
p->partdev,
s.free_blocks_count,
s.blocks_count-s.free_blocks_count,
s.blocks_count, s.block_size
);
div = 1024/(s.block_size/1024);
print(
"%s (MB) free %llud, used %llud, total %llud\n",
p->partdev,
s.free_blocks_count/div,
(s.blocks_count-s.free_blocks_count)/div,
s.blocks_count/div
);
}
}
qunlock(&sv);
}
void
syncallparts(void)
{
Part *p;
qlock(&sv);
for(p = sv.ps; p != nil; p = p->next){
if(ext4_cache_flush(&p->mp) < 0)
fprint(2, "%s: %r\n", p->partdev);
}
qunlock(&sv);
}