ref: 7a98f323b297c1e108a953bc167a024be402d58a
dir: /part.c/
#include <ext4.h> #include <ext4_mkfs.h> #include <thread.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){ fprint(2, "bdread: %r\n"); return EIO; } 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 EIO; 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){ if((x = strtoll(a[2], &e, 0)) > 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; char *s, *d; ext4_file f; int r; d = nil; while(*path == '/') path++; s = smprint("%M/%s", p, path); r = ext4_fopen2(&f, s, O_RDONLY); free(s); 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((r = ext4_fread(&f, d+n, *sz-n, &got)) != 0){ werrstr("readfile: %s", errno2s(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) { usize sz; char *gr; int r; if(snprint(p->dev, sizeof(p->dev), "%Ð", p) >= sizeof(p->dev)){ werrstr("part path too long"); goto error; } if(snprint(p->mnt, sizeof(p->mnt), "%M/", p) >= sizeof(p->mnt)){ werrstr("part path too long"); goto error; } if((r = ext4_device_register(&p->bdev, p->dev)) != 0){ werrstr("register: %s", errno2s(r)); goto error; } if((r = ext4_mount(p->dev, p->mnt, false)) != 0){ werrstr("mount: %s", errno2s(r)); goto error; } if((r = ext4_mount_setup_locks(p->mnt, &p->oslocks)) != 0){ werrstr("locks: %s", errno2s(r)); goto error; } if((r = ext4_recover(p->mnt)) != 0 && r != ENOTSUP){ werrstr("recover: %s", errno2s(r)); goto error; } if((r = ext4_journal_start(p->mnt)) != 0 && r != ENOTSUP){ werrstr("journal: %s", errno2s(r)); goto error; } if(opts->cachewb) ext4_cache_write_back(p->mnt, 1); if((r = ext4_get_sblock(p->mnt, &p->sb)) != 0){ werrstr("sblock: %s", errno2s(r)); goto error; } 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; int f, r; Part *p; char *s; Dir *d; d = nil; p = nil; s = nil; qlock(&sv); fmtinstall(L'Ð', fmtpart); fmtinstall('M', fmtpart); 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->fstype > 1){ memset(&fs, 0, sizeof(fs)); memset(&info, 0, sizeof(info)); info.block_size = opts->blksz; info.label = opts->label; info.inode_size = opts->inodesz; info.inodes = opts->ninode; info.journal = true; if((r = ext4_mkfs(&fs, &p->bdev, &info, opts->fstype)) != 0){ werrstr("mkfs: %s", errno2s(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) { int r; ext4_cache_write_back(p->mnt, 0); if((r = ext4_journal_stop(p->mnt)) != 0 && r != ENOTSUP) fprint(2, "closepart: journal %s: %s\n", p->mnt, errno2s(r)); if((r = ext4_umount(p->mnt)) != 0 && r != ENOTSUP) fprint(2, "closepart: umount %s: %s\n", p->mnt, errno2s(r)); if((r = ext4_device_unregister(p->dev)) != 0 && r != ENOTSUP) fprint(2, "closepart: unregister %s: %s\n", p->dev, errno2s(r)); 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; int r; qlock(&sv); for(p = sv.ps; p != nil; p = p->next){ if((r = ext4_mount_point_stats(p->mnt, &s)) != 0){ print("error: %s: %s\n", p->partdev, errno2s(r)); }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; int r; qlock(&sv); for(p = sv.ps; p != nil; p = p->next){ if((r = ext4_cache_flush(p->mnt)) != 0) print("error: %s: %s\n", p->partdev, errno2s(r)); } qunlock(&sv); }