/* * Copyright (c) 2013, Coraid, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Coraid nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CORAID BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Adapted by Brian L. Stuart from: * * vblade — virtual aoe target * copyright © 2007—2013 erik quanstrom */ #include #include #include #include /* irony */ #include #include #include <9p.h> enum { Eaddrlen = 6, /* only defined in kernel */ }; #include "aoe.h" #include "dat.h" enum { Fclone, Fdata, Flast, Nether = 8, Nvblade = 16, Nmask = 10, Nmaxout= 128, Maxpkt = 10000, Conflen = 1024, }; typedef struct Vblade Vblade; struct Vblade { vlong maxlba; uint nmask; Lock mlk; uchar *mask; int shelf; int slot; int clen; char *config; }; static Vblade vblade[Nvblade]; static int nblade; static char *ethertab[Nether] = { "#l0/ether0", }; static int etheridx = 1; static int efdtab[Nether*Flast]; static uchar pkttab[Nether][Maxpkt]; static uchar bctab[Nether][Maxpkt]; static int mtutab[Nether]; static Ioproc *ioprocs[Nether]; static int getmtu(char *p) { char buf[50]; int fd, mtu; snprint(buf, sizeof buf, "%s/mtu", p); if((fd = open(buf, OREAD)) == -1) return 2; if(read(fd, buf, 36) < 0) return 2; close(fd); buf[36] = 0; mtu = strtoul(buf+12, 0, 0)-Aoehsz-Aoeatasz; return mtu>>9; } static int aoeopen(Ioproc *io, char *e, int fds[]) { char buf[128], ctl[13]; int n; snprint(buf, sizeof buf, "%s/clone", e); if((fds[Fclone] = ioopen(io, buf, ORDWR)) == -1) return -1; memset(ctl, 0, sizeof ctl); if(ioread(io, fds[Fclone], ctl, sizeof ctl - 1) < 0) return -1; n = atoi(ctl); snprint(buf, sizeof buf, "connect %d", Aoetype); if(iowrite(io, fds[Fclone], buf, strlen(buf)) != strlen(buf)) return -1; snprint(buf, sizeof buf, "%s/%d/data", e, n); fds[Fdata] = ioopen(io, buf, ORDWR); return fds[Fdata]; } static void replyhdr(Aoehdr *h, Vblade *vblade) { uchar ea[Eaddrlen]; memmove(ea, h->dst, Eaddrlen); memmove(h->dst, h->src, Eaddrlen); memmove(h->src, ea, Eaddrlen); hnputs(h->major, vblade->shelf); h->minor = vblade->slot; h->verflag |= AFrsp; } static int servebad(uchar *pkt, Vblade*, int) { Aoehdr *h; h = (Aoehdr*)pkt; h->verflag |= AFerr; h->error = AEcmd; return Aoehsz; } static uchar nilea[Eaddrlen]; /* static void savemask(Vblade *vb) { uvlong qpath, meta; qpath = ((uvlong)TLun << 60) | (vb->shelf << 8) | vb->slot; meta = q2m(-1, qpath, 0); if(meta == 0) return; setmetaint(meta, "nmask", nil, vb->nmask); if(vb->mask) setmetablob(meta, "mask", nil, vb->mask, vb->nmask * Eaddrlen, 0); else setmetastr(meta, "mask", nil, "", 0); } */ static int servemask(uchar *pkt, Vblade *vb, int mtu) { int i, j, r, e; uchar mx[Nmask*Eaddrlen], *mtab[Nmask], *p; Aoem *m; Aoemd *d; m = (Aoem*)(pkt + Aoehsz); if(m->mcnt > (mtu - Aoehsz - Aoemsz)/Aoemdsz) return -1; if(!canlock(&vb->mlk)) return -1; /* drop */ switch(m->mcmd){ default: unlock(&vb->mlk); return servebad(pkt, vb, mtu); case Medit: memcpy(mx, vb->mask, vb->nmask*Eaddrlen); j = 0; for(i = 0; i < vb->nmask; i++){ p = mx + i*Eaddrlen; if(memcmp(p, nilea, Eaddrlen) != 0) mtab[j++] = p; } e = 0; p = pkt + Aoehsz + Aoemsz; for(i = 0; i < m->mcnt && e == 0; i++){ d = (Aoemd*)(p + i*Aoemdsz); switch(d->dcmd){ default: e = MEunk; break; case MDnop: break; case MDadd: for(i = 0; i < j; i++) if(memcmp(d->ea, mtab[j], Eaddrlen) == 0) continue; if(j == Nmask) e = MEfull; else memcpy(mtab[j++], d->ea, Eaddrlen); break; case MDdel: for(i = 0; i < j; i++) if(memcmp(d->ea, mtab[j], Eaddrlen) == 0) break; if(i < j){ for(; i < j; i++) mtab[i] = mtab[i+1]; j--; } break; } } if(e != 0){ m->merr = e; r = Aoehsz + Aoemsz; break; } p = malloc(j*Eaddrlen); if(p == nil){ r = -1; break; } for(i = 0; i < j; i++) memcpy(p+i*Eaddrlen, mtab[i], Eaddrlen); free(vb->mask); vb->nmask = j; vb->mask = p; case Mread: m->mcnt = vb->nmask; m->merr = 0; p = pkt + Aoehsz + Aoemsz; for(i = 0; i < m->mcnt; i++){ d = (Aoemd*)(p + i*Aoemdsz); d->dres = 0; d->dcmd = MDnop; memcpy(d->ea, vb->mask + i*Eaddrlen, Eaddrlen); } r = Aoehsz + Aoemsz + m->mcnt * Aoemdsz; break; } unlock(&vb->mlk); return r; } static void saveconfig(Vblade *vb) { uvlong qpath, meta; qpath = ((uvlong)TLun << 60) | (vb->shelf << 8) | vb->slot; meta = q2m(-1, qpath, 0); if(meta == 0) return; if(vb->config) setmetastr(meta, "config", nil, vb->config, 0); else setmetastr(meta, "config", nil, "", 0); } static int serveconfig(uchar *pkt, Vblade *vb, int mtu) { char *cfg; int cmd, reqlen, len; Aoehdr *h; Aoecfg *q; h = (Aoehdr*)pkt; q = (Aoecfg*)(pkt + Aoehsz); if(memcmp(h->src, h->dst, Eaddrlen) == 0) return -1; reqlen = nhgets(q->cslen); len = vb->clen; cmd = q->verccmd&0xf; cfg = (char*)(pkt + Aoehsz + Aoecfgsz); switch(cmd){ case AQCtest: if(reqlen != len) return -1; case AQCprefix: if(reqlen > len) return -1; if(memcmp(vb->config, cfg, reqlen) != 0) return -1; case AQCread: break; case AQCset: if(len && len != reqlen || memcmp(vb->config, cfg, reqlen) != 0){ h->verflag |= AFerr; h->error = AEcfg; break; } case AQCfset: if(reqlen > Conflen){ h->verflag |= AFerr; h->error = AEarg; break; } free(vb->config); vb->config = θmalloc(reqlen + 1); memmove(vb->config, cfg, reqlen); vb->clen = len = reqlen; saveconfig(vb); break; default: h->verflag |= AFerr; h->error = AEarg; break; } if(vb->config) memmove(cfg, vb->config, len); hnputs(q->cslen, len); hnputs(q->bufcnt, Nmaxout); q->scnt = mtu; hnputs(q->fwver, 2323); q->verccmd = Aoever<<4 | cmd; return len; } static ushort ident[256] = { [47] 0x8000, [49] 0x0200, [50] 0x4000, [83] 0x5400, [84] 0x4000, [86] 0x1400, [87] 0x4000, [93] 0x400b, }; static void idmoveto(char *a, int idx, int len, char *s) { char *p; p = a+idx*2; for(; len > 0; len -= 2) { if(*s == 0) p[1] = ' '; else p[1] = *s++; if (*s == 0) p[0] = ' '; else p[0] = *s++; p += 2; } } static void lbamoveto(char *p, int idx, int n, vlong lba) { int i; p += idx*2; for(i = 0; i < n; i++) *p++ = lba>>i*8; } enum { Crd = 0x20, Crdext = 0x24, Cwr = 0x30, Cwrext = 0x34, Cid = 0xec, }; static uvlong getlba(uchar *p) { uvlong v; v = p[0]; v |= p[1]<<8; v |= p[2]<<16; v |= p[3]<<24; v |= (uvlong)p[4]<<32; v |= (uvlong)p[5]<<40; return v; } static void putlba(uchar *p, vlong lba) { p[0] = lba; p[1] = lba>>8; p[2] = lba>>16; p[3] = lba>>24; p[4] = lba>>32; p[5] = lba>>40; } static int serveata(uchar *pkt, Vblade *vb, int mtu) { char *buf; int rbytes, bytes, len; vlong lba, off, qpath; Aoehdr *h; Aoeata *a; h = (Aoehdr*)pkt; a = (Aoeata*)(pkt + Aoehsz); buf = (char*)(pkt + Aoehsz + Aoeatasz); lba = getlba(a->lba); len = a->scnt<<9; off = lba<<9; if(a->scnt > mtu || a->scnt == 0){ h->verflag |= AFerr; h->error = AEarg; a->cmdstat = ASdrdy|ASerr; return 0; } if(a->cmdstat != Cid) if(lba+a->scnt > vb->maxlba){ a->errfeat = Eidnf; a->cmdstat = ASdrdy|ASerr; return 0; } if(a->cmdstat&0xf0 == 0x20) lba &= 0xfffffff; switch(a->cmdstat){ default: a->errfeat = Eabrt; a->cmdstat = ASdrdy|ASerr; return 0; case Cid: memmove(buf, ident, sizeof ident); idmoveto(buf, 27, 40, "Plan 9 Vblade"); idmoveto(buf, 10, 20, "serial#"); idmoveto(buf, 23, 8, "2"); lbamoveto(buf, 60, 4, vb->maxlba); lbamoveto(buf, 100, 8, vb->maxlba); a->cmdstat = ASdrdy; return 512; break; case Crd: case Crdext: qpath = ((uvlong)TLun << 60) | (vb->shelf << 8) | vb->slot; bytes = θpread(-1, qpath, buf, len, off); rbytes = bytes; break; case Cwr: case Cwrext: qpath = ((uvlong)TLun << 60) | (vb->shelf << 8) | vb->slot; bytes = θpwrite(qpath, buf, len, off, 0); rbytes = 0; break; } if(bytes != len){ a->errfeat = Eabrt; a->cmdstat = ASdf|ASerr; putlba(a->lba, lba+(len-bytes)>>9); return 0; } putlba(a->lba, lba+a->scnt); a->scnt = 0; a->errfeat = 0; a->cmdstat = ASdrdy; return rbytes; } static int myea(Ioproc *io, uchar ea[6], char *p) { char buf[50]; int fd; snprint(buf, sizeof buf, "%s/addr", p); if((fd = ioopen(io, buf, OREAD)) == -1) return -1; if(ioread(io, fd, buf, 12) < 12) return -1; ioclose(io, fd); return parseether(ea, buf); } static int bcastpkt(uchar *pkt, uint shelf, uint slot, int i) { Aoehdr *h; h = (Aoehdr*)pkt; myea(ioprocs[i], h->dst, ethertab[i]); memset(h->src, 0xff, Eaddrlen); hnputs(h->type, Aoetype); hnputs(h->major, shelf); h->minor = slot; h->cmd = ACconfig; *(u32int*)h->tag = 0; return Aoehsz + Aoecfgsz; } static int osdgetattr(Aoeosd *o, int len, uvlong pid, uvlong oid) { MVal x; uchar *inbuf, *outbuf, *end; char *name, *strval; uvlong meta; int n, nn, typ, tot; name = smprint("%016ullx:%016ullx", pid, oid); meta = q2m(-1, p2q(-1, name, 0), 0); free(name); if(meta == 0) { o->oflag = 0x40; return 0; } len -= 20; inbuf = θmalloc(len); memmove(inbuf, o->oaddr, len); end = inbuf + len; outbuf = o->opid; tot = 0; while(inbuf < end) { name = (char *)inbuf; /* the compiler's obsession with signed and unsigned is annoying */ nn = strlen(name); inbuf += nn + 1; typ = getmeta(-1, meta, name, &x); switch(typ) { /* case MTshort: if(tot + nn + 4 >= 8192) goto done; tot += nn + 4; strcpy((char *)outbuf, name); outbuf += nn + 1; *outbuf++ = 'h'; hnputs(outbuf, *((ushort *)x)); outbuf += 2; break; case MTlong: if(tot + nn + 6 >= 8192) goto done; tot += nn + 6; strcpy((char *)outbuf, name); outbuf += nn + 1; *outbuf++ = 'l'; hnputl(outbuf, *((ulong *)x)); outbuf += 4; break; */ case MTint: if(tot + nn + 10 >= 8192) goto done; tot += nn + 10; strcpy((char *)outbuf, name); outbuf += nn + 1; *outbuf++ = 'v'; hnputv(outbuf, x.val); outbuf += 8; break; case MTistring: n = strlen(x.str) + 1; if(tot + nn + n + 3 >= 8192) goto done; tot += nn + n + 3; strcpy((char *)outbuf, name); outbuf += nn + 1; *outbuf++ = 's'; strcpy((char *)outbuf, x.str); outbuf += n; break; case MTstring: strval = getblob(-1, x.val, &n); if(tot + nn + n + 3 >= 8192) goto done; tot += nn + n + 3; strcpy((char *)outbuf, name); outbuf += nn + 1; *outbuf++ = 's'; strcpy((char *)outbuf, strval); free(strval); outbuf += n; break; case MTblob: strval = getblob(-1, x.val, &n); if(tot + nn + n + 4 >= 8192) goto done; tot += nn + n + 4; strcpy((char *)outbuf, name); outbuf += nn + 1; *outbuf++ = 'b'; hnputs(outbuf, n); outbuf += 2; memmove(outbuf, strval, n); free(strval); outbuf += n; break; } } done: brelease(meta); return tot; } static int osdsetattr(Aoeosd *o, int len, uvlong pid, uvlong oid) { uchar *buf, *end; char *name; uvlong meta; int n; name = smprint("%016ullx:%016ullx", pid, oid); meta = q2m(-1, p2q(-1, name, 0), 0); free(name); if(meta == 0) { o->oflag = 0x40; return 0; } buf = o->oaddr; end = buf + len; while(buf < end) { name = (char *)buf; /* the compiler's obsession with signed and unsigned is annoying */ buf += strlen(name) + 1; switch(*buf) { case 'h': setmetaint(meta, name, nil, nhgets(buf + 1)); buf += 3; break; case 'l': setmetaint(meta, name, nil, nhgetl(buf + 1)); buf += 5; break; case 'v': setmetaint(meta, name, nil, nhgetv(buf + 1)); buf += 9; break; case 's': setmetastr(meta, name, nil, (char *)(buf + 1), 0); buf += strlen((char *)(buf + 1)) + 2; break; case 'b': n = *((ushort *)(buf + 1)); setmetablob(meta, name, nil, buf + 3, n, 0); buf += n + 1; break; } } return 0; } static int serveosd(Ioproc *io, uchar *pkt, int fd, int) { Qid nqid; Aoehdr *ah; Aoeosd *o; uchar *buf; char *name; uvlong x; uvlong pid, oid, addr, meta, pmeta, dirblk, pqpath; int n, len, rlen; ah = (Aoehdr *)pkt; o = (Aoeosd *)(pkt + Aoehsz); len = nhgets(o->olen); /* for some commands, the pid, oid, or addr may be junk */ pid = nhgetv(o->opid); oid = nhgetv(o->ooid); addr = nhgetv(o->oaddr); rlen = 0; o->oflag = 0; fprint(2, "OSD request: %016ullx:%016ullx len:%d cmd:%x addr:%ulld\n", pid, oid, len, o->ocmd, addr); switch(o->ocmd) { case AOCformat: name = smprint("0000000000000000:0000000000000000"); nqid.path = p2q(-1, name, 1); nqid.vers = 0; nqid.type = QTFILE; meta = q2m(-1, nqid.path, 1); setmetastr(meta, "name", nil, name, 0); setmetaint(meta, "pid", nil, 0); setmetaint(meta, "oid", nil, 0); setmetaint(meta, "qpath", nil, nqid.path); setmetaint(meta, "qvers", nil, nqid.vers); setmetaint(meta, "qtype", nil, nqid.type); setmetaint(meta, "child", nil, 0); setqhash(nqid.path, meta); free(name); savesuper(); break; case AOCcreate: name = smprint("%016ullx:0000000000000000", pid); pqpath = p2q(-1, name, 0); pmeta = q2m(-1, pqpath, 0); free(name); if(pmeta == 0) { o->oflag = 0x40; break; } name = smprint("%016ullx:%016ullx", pid, oid); nqid.path = p2q(-1, name, 1); nqid.vers = 0; nqid.type = QTFILE; meta = q2m(-1, nqid.path, 1); if(meta == 0) { o->oflag = 0x40; free(name); break; } setmetastr(meta, "name", nil, name, 0); setmetaint(meta, "pid", nil, pid); setmetaint(meta, "oid", nil, oid); setmetaint(meta, "qpath", nil, nqid.path); setmetaint(meta, "qvers", nil, nqid.vers); setmetaint(meta, "qtype", nil, nqid.type); setmetaint(meta, "length", nil, 0); setmetaint(meta, "parent", nil, pqpath); getmetaint(-1, pmeta, "child", &x); setmetaint(meta, "sib", nil, x); setmetaint(pmeta, "child", nil, nqid.path); dirblk = allocblock(); if(dirblk != 0) { cbclean(dirblk); cbwrite(dirblk); brelease(dirblk); } setmetaint(meta, "index", nil, dirblk); setqhash(nqid.path, meta); free(name); savesuper(); break; case AOClist: name = smprint("%016ullx:%016ullx", pid, oid); pqpath = p2q(-1, name, 0); meta = q2m(-1, pqpath, 0); getmetaint(-1, meta, "child", &pqpath); buf = o->opid; while(len > 0 && pqpath != 0) { meta = q2m(-1, pqpath, 0); if(meta == 0) break; if(pid == 0) getmetaint(-1, meta, "pid", &x); else getmetaint(-1, meta, "oid", &x); hnputv(buf, x); buf += 8; len -= 8; getmetaint(-1, meta, "sib", &pqpath); } rlen = len = buf - o->opid; hnputs(o->olen, len); break; case AOCread: name = smprint("%016ullx:%016ullx", pid, oid); pqpath = p2q(-1, name, 0); buf = o->opid; len = θpread(-1, pqpath, buf, len, addr); rlen = len; free(name); break; case AOCwrite: name = smprint("%016ullx:%016ullx", pid, oid); pqpath = p2q(-1, name, 0); buf = o->oaddr + 8; len = θpwrite(pqpath, buf, len, addr, 1); free(name); break; case AOCappend: name = smprint("%016ullx:%016ullx", pid, oid); pqpath = p2q(-1, name, 0); buf = o->oaddr + 8; len = θpwrite(pqpath, buf, len, 0, 2); free(name); break; case AOCflush: resetmeta(); csync(); break; case AOCremove: name = smprint("%016ullx:%016ullx", pid, oid); meta = q2m(-1, p2q(-1, name, 0), 0); if(meta == 0) { o->oflag = 0x40; free(name); break; } getmetaint(-1, meta, "qpath", &x); rmdlist(meta, x); rmq(x, meta); rmp(name); free(name); break; case AOCpcreate: name = smprint("0000000000000000:0000000000000000"); pqpath = p2q(-1, name, 0); pmeta = q2m(-1, pqpath, 0); free(name); if(pmeta == 0) { o->oflag = 0x40; break; } name = smprint("%016ullx:0000000000000000", pid); nqid.path = p2q(-1, name, 1); nqid.vers = 0; nqid.type = QTFILE; meta = q2m(-1, nqid.path, 1); if(meta == 0) { o->oflag = 0x40; free(name); break; } setmetastr(meta, "name", nil, name, 0); setmetaint(meta, "pid", nil, pid); setmetaint(meta, "oid", nil, 0); setmetaint(meta, "qpath", nil, nqid.path); setmetaint(meta, "qvers", nil, nqid.vers); setmetaint(meta, "qtype", nil, nqid.type); setmetaint(meta, "parent", nil, pqpath); setmetaint(meta, "child", nil, 0); getmetaint(-1, pmeta, "child", &x); setmetaint(meta, "sib", nil, x); setmetaint(pmeta, "child", nil, nqid.path); setqhash(nqid.path, meta); free(name); savesuper(); break; case AOCpremove: name = smprint("%016ullx:0000000000000000", pid); meta = q2m(-1, p2q(-1, name, 0), 0); if(meta == 0) { o->oflag = 0x40; free(name); break; } getmetaint(-1, meta, "child", &x); if(x == 0) { rmdlist(meta, x); rmq(x, meta); freeblock(meta); rmp(name); } else { o->oflag |= 0x40; } free(name); break; case AOCgetattr: rlen = len = osdgetattr(o, len, pid, oid); break; case AOCsetattr: rlen = len = osdsetattr(o, len, pid, oid); break; case AOCccreate: case AOCcremove: case AOCclist: default: o->oflag = 0x40; break; } memmove(ah->dst, ah->src, Eaddrlen); ah->verflag |= AFrsp; if(o->oflag & 0x40) { ah->verflag |= AFerr; ah->error = AEarg; } o->oflag |= 0x80; hnputs(o->olen, len); n = rlen + 4 + sizeof(Aoehdr); if(n < 60) n = 60; if(iowrite(io, fd, pkt, n) != n) { fprint(2, "response write failed: %r\n"); return -1; } return 0; } static int bladereply(Vblade *v, int i, int fd, uchar *pkt) { int n; Aoehdr *h; h = (Aoehdr*)pkt; switch(h->cmd){ case ACata: n = serveata(pkt, v, mtutab[i]); n += Aoehsz+Aoeatasz; break; case ACconfig: n = serveconfig(pkt, v, mtutab[i]); if(n >= 0) n += Aoehsz+Aoecfgsz; break; case ACmask: n = servemask(pkt, v, mtutab[i]); break; case ACosd: if(v == vblade) return serveosd(ioprocs[i], pkt, fd, mtutab[i]); else return 0; break; default: n = servebad(pkt, v, mtutab[i]); break; } if(n == -1) return -1; replyhdr(h, v); if(n < 60){ memset(pkt+n, 0, 60-n); n = 60; } if(iowrite(ioprocs[i], fd, h, n) != n){ fprint(2, "vblade: write to %s failed: %r\n", ethertab[i]); return -1; } return 0; } static int filter(Vblade *v, uchar *ea) { int i; uchar *u; if(v->nmask == 0) return 0; u = v->mask; for(i = 0; i < v->nmask; i++) if(memcmp(u + i*Eaddrlen, ea, Eaddrlen) == 0) return 0; return -1; } static void serve(void *a) { int i, j, popcnt, vec, n, s, efd; uchar *pkt, *bcpkt; Aoehdr *h; Vblade *v; i = (int)(uintptr)a; efd = efdtab[i*Flast+Fdata]; pkt = pkttab[i]; bcpkt = bctab[i]; n = 60; h = (Aoehdr*)pkt; bcastpkt(pkt, 0xffff, 0xff, i); goto start; for(;;){ n = ioread(ioprocs[i], efd, pkt, Maxpkt); start: if(shutdown) threadexits(nil); if(n < 60 || h->verflag & AFrsp) continue; s = nhgets(h->major); popcnt = 0; vec = 0; for(j = 0; j < nblade; j++){ v = vblade+j; if(v->shelf == s || s == 0xffff) if(v->slot == h->minor || h->minor == 0xff) if(v->nmask == 0 || filter(v, h->src) == 0){ popcnt++; vec |= 1<0){ memcpy(bcpkt, pkt, n); bladereply(vblade + j, i, efd, bcpkt); }else{ bladereply(vblade + j, i, efd, pkt); break; } } } } static void aoeannounce(Vblade *vb) { uchar *pkt; int i; pkt = θmalloc(Maxpkt); for(i = 0; i < etheridx; ++i) { bcastpkt(pkt, 0xffff, 0xff, i); bladereply(vb, i, efdtab[i*Flast+Fdata], pkt); } } void starttarget(int major, int minor, uvlong nsect) { Vblade *vp; vp = vblade + nblade; vp->maxlba = nsect; vp->nmask = 0; vp->mask = nil; vp->shelf = major; vp->slot = minor; vp->clen = 0; ++nblade; aoeannounce(vp); } void rmtarget(int major, int minor) { int i; for(i = 0; i < nblade && (vblade[i].shelf != major || vblade[i].slot != minor); ++i) ; if(i >= nblade) return; for(; i < nblade - 1; ++i) vblade[i] = vblade[i+1]; memset(vblade + i, 0, sizeof (Vblade)); --nblade; } static void scanluns(void) { uvlong x; uvlong qpath, meta; for(qpath = super.firstlun; qpath; ) { meta = q2m(-1, qpath, 0); if(meta == 0) { fprint(2, "No metadata for %ulld\n", qpath); break; } getmetaint(-1, meta, "length", &x); vblade[nblade].maxlba = x >> 9; if(getmetaint(-1, meta, "nmask", &x) == MTnone) vblade[nblade].nmask = 0; else vblade[nblade].nmask = x; if(vblade[nblade].nmask != 0) { if(getmeta(-1, meta, "masks", (MVal *)&x) == MTnone) vblade[nblade].nmask = 0; else vblade[nblade].mask = getblob(-1, x, nil); } getmetaint(-1, meta, "aoemajor", &x); vblade[nblade].shelf = x; getmetaint(-1, meta, "aoeminor", &x); vblade[nblade].slot = x; if(vblade[nblade].config = getmetastr(-1, meta, "config")) vblade[nblade].clen = strlen(vblade[nblade].config); else vblade[nblade].clen = 0; ++nblade; getmetaint(-1, meta, "nextlun", &qpath); } } static void launch(char *tab[], int fdtab[]) { int i; for(i = 0; tab[i]; i++){ ioprocs[i] = ioproc(); if(aoeopen(ioprocs[i], tab[i], fdtab+Flast*i) < 0) sysfatal("network open: %r"); threadcreate(serve, (void*)(uintptr)i, 32*1024); } } void initaoe(void) { int i; for(i = 0; i < etheridx; i++) mtutab[i] = getmtu(ethertab[i]); scanluns(); launch(ethertab, efdtab); } void haltaoe(void) { int i; for(i = 0; ethertab[i]; ++i) { if(ioprocs[i]) { iointerrupt(ioprocs[i]); closeioproc(ioprocs[i]); } } }