ref: f05b8af71e41c37d868986b5147879fc5a437dbe
parent: 12802b94c69faade31c7196b7f4fb7ef34182cd3
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Mar 30 15:23:26 EDT 2022
devsd: cache SDunit pointer in Chan.aux, improve error handling Avoid calling sdgetdev() for every I/O. Instead, put the SDunit pointer for #S/sdXX/* files in Chan.aux and keep a reference to SDev between sdopen()/sdclose(). This avoids having to do the sdindex() lookup and qlock(),incref(),decref() on every read/write operation. Removal of SDev's is quite rare and only can happen with pcmcia ide controllers, and i assume that for that we can assume thet fileservers having been exited properly and closed their files before we attempt to remove a device. The rest is improving waserror() codepaths, making sure we release the locks for any of the interface callbacks (verify/online). Also get rid of tas() and instead only change the unit's rawopen flag while holding raw qlock.
--- a/sys/src/9/port/devsd.c
+++ b/sys/src/9/port/devsd.c
@@ -293,12 +293,9 @@
qunlock(&sdev->unitlock);
return nil;
}
-
- if((unit = malloc(sizeof(SDunit))) == nil){
- qunlock(&sdev->unitlock);
- return nil;
- }
sdev->unitflg[subno] = 1;
+
+ unit = smalloc(sizeof(SDunit));
snprint(buf, sizeof buf, "%s%x", sdev->name, subno);
kstrdup(&unit->name, buf);
kstrdup(&unit->user, eve);
@@ -305,7 +302,9 @@
unit->perm = 0555;
unit->subno = subno;
unit->dev = sdev;
-
+
+ if(waserror())
+ goto Error;
if(sdev->enabled == 0)
sdev->enabled = sdev->ifc->enable == nil || sdev->ifc->enable(sdev);
@@ -315,6 +314,8 @@
* sdunit[] array.
*/
if(sdev->enabled == 0 || unit->dev->ifc->verify(unit) == 0){
+ poperror();
+ Error:
qunlock(&sdev->unitlock);
free(unit->name);
free(unit->user);
@@ -321,6 +322,7 @@
free(unit);
return nil;
}
+ poperror();
sdev->unit[subno] = unit;
}
qunlock(&sdev->unitlock);
@@ -395,7 +397,7 @@
// }
static int
-sd2gen(Chan* c, int i, Dir* dp)
+sd2gen(Chan* c, SDunit *unit, int i, Dir* dp)
{
Qid q;
uvlong l;
@@ -402,15 +404,8 @@
SDfile *e;
SDpart *pp;
SDperm *perm;
- SDunit *unit;
- SDev *sdev;
- int rv, t;
+ int t;
- sdev = sdgetdev(DEV(c->qid));
- assert(sdev);
- unit = sdev->unit[UNIT(c->qid)];
-
- rv = -1;
switch(i){
case Qctl:
mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl),
@@ -421,8 +416,7 @@
perm->perm = 0640;
}
devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);
- rv = 1;
- break;
+ return 1;
case Qraw:
mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw),
@@ -433,8 +427,7 @@
perm->perm = DMEXCL|0600;
}
devdir(c, q, "raw", 0, perm->user, perm->perm, dp);
- rv = 1;
- break;
+ return 1;
case Qpart:
pp = &unit->part[PART(c->qid)];
@@ -444,8 +437,8 @@
if(emptystr(pp->user))
kstrdup(&pp->user, eve);
devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
- rv = 1;
- break;
+ return 1;
+
case Qextra:
t = PART(c->qid);
if(t >= unit->nefile)
@@ -456,12 +449,10 @@
if(emptystr(e->user))
kstrdup(&e->user, eve);
devdir(c, q, e->name, 0, e->user, e->perm, dp);
- rv = 1;
- break;
+ return 1;
}
- decref(&sdev->r);
- return rv;
+ return -1;
}
static int
@@ -574,13 +565,14 @@
return 1;
}
- if((sdev = sdgetdev(DEV(c->qid))) == nil){
- devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
- return 1;
- }
-
+ if((sdev = sdgetdev(DEV(c->qid))) == nil)
+ return -1;
unit = sdev->unit[UNIT(c->qid)];
qlock(&unit->ctl);
+ if(waserror()){
+ r = -1;
+ goto ReleaseUnit;
+ }
/*
* Check for media change.
@@ -595,23 +587,22 @@
i = s+Qunitbase;
if(i < Qpart){
- r = sd2gen(c, i, dp);
- qunlock(&unit->ctl);
- decref(&sdev->r);
- return r;
+ r = sd2gen(c, unit, i, dp);
+ poperror();
+ goto ReleaseUnit;
}
i -= Qpart;
if(unit->part == nil || i >= unit->npart){
r = efilegen(c, unit, i, dp);
- qunlock(&unit->ctl);
- decref(&sdev->r);
- return r;
+ poperror();
+ goto ReleaseUnit;
}
+ poperror();
+
pp = &unit->part[i];
if(!pp->valid || unit->sectors == 0){
- qunlock(&unit->ctl);
- decref(&sdev->r);
- return 0;
+ r = 0;
+ goto ReleaseUnit;
}
l = (pp->end - pp->start) * (uvlong)unit->secsize;
mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
@@ -619,20 +610,23 @@
if(emptystr(pp->user))
kstrdup(&pp->user, eve);
devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
- qunlock(&unit->ctl);
- decref(&sdev->r);
- return 1;
+ r = 1;
+ goto ReleaseUnit;
case Qraw:
case Qctl:
case Qpart:
case Qextra:
- if((sdev = sdgetdev(DEV(c->qid))) == nil){
- devdir(c, q, "unavailable", 0, eve, 0, dp);
- return 1;
- }
+ if((sdev = sdgetdev(DEV(c->qid))) == nil)
+ return -1;
unit = sdev->unit[UNIT(c->qid)];
qlock(&unit->ctl);
- r = sd2gen(c, TYPE(c->qid), dp);
+ if(!waserror()){
+ r = sd2gen(c, unit, TYPE(c->qid), dp);
+ poperror();
+ } else {
+ r = -1;
+ }
+ ReleaseUnit:
qunlock(&unit->ctl);
decref(&sdev->r);
return r;
@@ -668,15 +662,17 @@
if((sdev=sdgetdev(idno)) == nil)
error(Enonexist);
- if(sdgetunit(sdev, subno) == nil){
+ if(waserror()){
decref(&sdev->r);
- error(Enonexist);
+ nexterror();
}
-
+ if(sdgetunit(sdev, subno) == nil)
+ error(Enonexist);
c = devattach(sddevtab.dc, spec);
mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR);
c->dev = (sdev->idno << UnitLOG) + subno;
decref(&sdev->r);
+ poperror();
return c;
}
@@ -698,46 +694,48 @@
SDpart *pp;
SDunit *unit;
SDev *sdev;
- uchar tp;
c = devopen(c, omode, 0, 0, sdgen);
- if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
+ if(TYPE(c->qid) < Qunitbase)
return c;
-
+ if(waserror()){
+ c->flag &= ~COPEN;
+ nexterror();
+ }
sdev = sdgetdev(DEV(c->qid));
if(sdev == nil)
error(Enonexist);
-
+ if(waserror()){
+ decref(&sdev->r);
+ nexterror();
+ }
unit = sdev->unit[UNIT(c->qid)];
-
switch(TYPE(c->qid)){
case Qctl:
+ case Qextra:
c->qid.vers = unit->vers;
break;
case Qraw:
- c->qid.vers = unit->vers;
- if(tas(&unit->rawinuse) != 0){
- c->flag &= ~COPEN;
- decref(&sdev->r);
+ qlock(&unit->raw);
+ if(unit->rawinuse){
+ qunlock(&unit->raw);
error(Einuse);
}
unit->state = Rawcmd;
+ c->qid.vers = unit->vers;
+ qunlock(&unit->raw);
break;
case Qpart:
qlock(&unit->ctl);
- if(waserror()){
- qunlock(&unit->ctl);
- c->flag &= ~COPEN;
- decref(&sdev->r);
- nexterror();
- }
pp = &unit->part[PART(c->qid)];
c->qid.vers = unit->vers+pp->vers;
qunlock(&unit->ctl);
- poperror();
break;
}
- decref(&sdev->r);
+ poperror();
+ poperror();
+ /* keep the reference to unit->dev (sdev) */
+ c->aux = unit;
return c;
}
@@ -745,25 +743,20 @@
sdclose(Chan* c)
{
SDunit *unit;
- SDev *sdev;
- if(c->qid.type & QTDIR)
- return;
if(!(c->flag & COPEN))
return;
-
+ if(TYPE(c->qid) < Qunitbase)
+ return;
+ unit = c->aux;
switch(TYPE(c->qid)){
- default:
- break;
case Qraw:
- sdev = sdgetdev(DEV(c->qid));
- if(sdev){
- unit = sdev->unit[UNIT(c->qid)];
- unit->rawinuse = 0;
- decref(&sdev->r);
- }
+ qlock(&unit->raw);
+ unit->rawinuse = 0;
+ qunlock(&unit->raw);
break;
}
+ decref(&unit->dev->r);
}
#define iskaddr(a) ((uintptr)(a) > KZERO)
@@ -776,21 +769,12 @@
uchar *b;
SDpart *pp;
SDunit *unit;
- SDev *sdev;
ulong max, nb, offset;
uvlong bno;
- sdev = sdgetdev(DEV(c->qid));
- if(sdev == nil){
- decref(&sdev->r);
- error(Enonexist);
- }
- unit = sdev->unit[UNIT(c->qid)];
- if(unit == nil)
- error(Enonexist);
-
- nchange = 0;
+ unit = c->aux;
qlock(&unit->ctl);
+ nchange = 0;
while(waserror()){
/* notification of media change; go around again */
if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
@@ -800,7 +784,6 @@
/* other errors; give up */
qunlock(&unit->ctl);
- decref(&sdev->r);
nexterror();
}
pp = &unit->part[PART(c->qid)];
@@ -829,7 +812,6 @@
if(write)
error(Eio);
qunlock(&unit->ctl);
- decref(&sdev->r);
poperror();
return 0;
}
@@ -848,21 +830,14 @@
b = (uchar*)a;
allocd = 0;
}else{
- while((b = sdmalloc(nb*unit->secsize)) == nil){
- if(!waserror()){
- resrcwait("no memory for sdbio");
- poperror();
- }
+ while((b = sdmalloc(nb*unit->secsize)) == nil)
+ resrcwait("no memory for sdbio");
+ if(waserror()){
+ sdfree(b);
+ nexterror();
}
allocd = 1;
}
- if(waserror()){
- if(allocd)
- sdfree(b);
- if(!locked)
- decref(&sdev->r); /* gadverdamme! */
- nexterror();
- }
if(write){
if(hard){
@@ -897,16 +872,16 @@
if(allocd)
memmove(a, b+offset, len);
}
- if(allocd)
- sdfree(b);
- poperror();
+ if(allocd){
+ sdfree(b);
+ poperror();
+ }
if(locked){
qunlock(&unit->ctl);
poperror();
}
- decref(&sdev->r);
return len;
}
@@ -933,19 +908,17 @@
}
data = nil;
- while(n > 0 && (data = sdmalloc(n)) == nil){
- if(!waserror()){
+ if(n > 0){
+ while((data = sdmalloc(n)) == nil)
resrcwait("no memory for sdrio");
- poperror();
+ if(waserror()){
+ r->data = nil;
+ sdfree(data);
+ nexterror();
}
+ if(r->write)
+ memmove(data, a, n);
}
- if(waserror()){
- sdfree(data);
- r->data = nil;
- nexterror();
- }
- if(r->write && n > 0)
- memmove(data, a, n);
r->data = data;
r->dlen = n;
@@ -966,13 +939,16 @@
if(rv != SDok)
error(Eio);
- if(!r->write && r->rlen > 0)
- memmove(a, data, r->rlen);
- poperror();
- sdfree(data);
r->data = nil;
-
- return r->rlen;
+ if(n > 0){
+ if(n < r->rlen)
+ n = r->rlen;
+ if(!r->write && n > 0)
+ memmove(a, data, n);
+ sdfree(data);
+ poperror();
+ }
+ return n;
}
/*
@@ -1187,36 +1163,21 @@
}
static long
-extrarw(int write, Chan *c, void *a, long n, vlong off)
+extrarw(Chan *c, int write, void *a, long n, vlong off)
{
- int i;
+ SDunit *unit = c->aux;
SDrw *f;
- SDev *sdev;
- SDunit *unit;
+ int i;
- sdev = sdgetdev(DEV(c->qid));
- if(sdev == nil)
- error(Enonexist);
- if(waserror()){
- decref(&sdev->r);
- nexterror();
- }
- unit = sdev->unit[UNIT(c->qid)];
if(unit->vers != c->qid.vers)
error(Echange);
- unit = sdev->unit[UNIT(c->qid)];
i = PART(c->qid);
if(i >= unit->nefile)
error(Enonexist);
- f = unit->efile[i].r;
- if(write)
- f = unit->efile[i].w;
- if(i >= unit->nefile || f == nil)
+ f = write ? unit->efile[i].w : unit->efile[i].r;
+ if(f == nil)
error(Eperm);
- n = f(unit, c, a, n, off);
- poperror();
- decref(&sdev->r);
- return n;
+ return f(unit, c, a, n, off);
}
static char*
@@ -1244,17 +1205,29 @@
m = 64*1024; /* room for register dumps */
p = buf = smalloc(m);
e = p + m;
+ if(waserror()){
+ free(buf);
+ nexterror();
+ }
qlock(&devslock);
+ if(waserror()){
+ qunlock(&devslock);
+ nexterror();
+ }
for(i = 0; i < nelem(devs); i++){
sdev = devs[i];
- if(sdev && sdev->ifc->rtopctl)
+ if(sdev == nil)
+ continue;
+ if(sdev->ifc->rtopctl)
p = sdev->ifc->rtopctl(sdev, p, e);
- else if(sdev)
+ else
p = deftopctl(sdev, p, e);
}
qunlock(&devslock);
+ poperror();
n = readstr(off, a, n, buf);
free(buf);
+ poperror();
return n;
case Qtopdir:
@@ -1262,16 +1235,20 @@
return devdirread(c, a, n, 0, 0, sdgen);
case Qctl:
- sdev = sdgetdev(DEV(c->qid));
- if(sdev == nil)
- error(Enonexist);
-
- unit = sdev->unit[UNIT(c->qid)];
m = 16*1024; /* room for register dumps */
- p = smalloc(m);
- l = snprint(p, m, "inquiry %.48s\n",
- (char*)unit->inquiry+8);
+ p = buf = smalloc(m);
+ e = p + m;
+ if(waserror()){
+ free(buf);
+ nexterror();
+ }
+ unit = c->aux;
qlock(&unit->ctl);
+ if(waserror()){
+ qunlock(&unit->ctl);
+ nexterror();
+ }
+ p = seprint(p, e, "inquiry %.48s\n", (char*)unit->inquiry+8);
/*
* If there's a device specific routine it must
* provide all information pertaining to night geometry
@@ -1278,39 +1255,33 @@
* and the garscadden trains.
*/
if(unit->dev->ifc->rctl)
- l += unit->dev->ifc->rctl(unit, p+l, m-l);
+ p += unit->dev->ifc->rctl(unit, p, e - p);
if(unit->sectors == 0)
sdinitpart(unit);
if(unit->sectors){
if(unit->dev->ifc->rctl == nil)
- l += snprint(p+l, m-l,
- "geometry %llud %lud\n",
+ p = seprint(p, e, "geometry %llud %lud\n",
unit->sectors, unit->secsize);
pp = unit->part;
for(i = 0; i < unit->npart; i++){
if(pp->valid)
- l += snprint(p+l, m-l,
- "part %s %llud %llud\n",
+ p = seprint(p, e, "part %s %llud %llud\n",
pp->name, pp->start, pp->end);
pp++;
}
}
qunlock(&unit->ctl);
- decref(&sdev->r);
- l = readstr(offset, a, n, p);
- free(p);
+ poperror();
+ l = readstr(offset, a, n, buf);
+ free(buf);
+ poperror();
return l;
case Qraw:
- sdev = sdgetdev(DEV(c->qid));
- if(sdev == nil)
- error(Enonexist);
-
- unit = sdev->unit[UNIT(c->qid)];
+ unit = c->aux;
qlock(&unit->raw);
if(waserror()){
qunlock(&unit->raw);
- decref(&sdev->r);
nexterror();
}
if(unit->state == Rawdata){
@@ -1337,15 +1308,14 @@
free(r);
} else
i = 0;
- poperror();
qunlock(&unit->raw);
- decref(&sdev->r);
+ poperror();
return i;
case Qpart:
return sdbio(c, 0, a, n, off);
case Qextra:
- return extrarw(0, c, a, n, off);
+ return extrarw(c, 0, a, n, off);
}
}
@@ -1413,7 +1383,7 @@
subtopctl:
if(waserror()){
- if(sdev)
+ if(sdev != nil)
decref(&sdev->r);
nexterror();
}
@@ -1421,24 +1391,19 @@
ifc->wtopctl(sdev, cb);
else
error(Ebadctl);
+ if(sdev != nil)
+ decref(&sdev->r);
poperror();
poperror();
- if(sdev)
- decref(&sdev->r);
free(cb);
break;
case Qctl:
cb = parsecmd(a, n);
- sdev = sdgetdev(DEV(c->qid));
- if(sdev == nil)
- error(Enonexist);
- unit = sdev->unit[UNIT(c->qid)];
-
+ unit = c->aux;
qlock(&unit->ctl);
if(waserror()){
qunlock(&unit->ctl);
- decref(&sdev->r);
free(cb);
nexterror();
}
@@ -1466,7 +1431,6 @@
else
error(Ebadctl);
qunlock(&unit->ctl);
- decref(&sdev->r);
poperror();
free(cb);
break;
@@ -1475,14 +1439,10 @@
proto = SDcdb;
ataproto = 0;
atacdb = 0;
- sdev = sdgetdev(DEV(c->qid));
- if(sdev == nil)
- error(Enonexist);
- unit = sdev->unit[UNIT(c->qid)];
+ unit = c->aux;
qlock(&unit->raw);
if(waserror()){
qunlock(&unit->raw);
- decref(&sdev->r);
nexterror();
}
switch(unit->state){
@@ -1528,14 +1488,13 @@
req->write = 1;
n = sdrio(req, a, n);
}
- poperror();
qunlock(&unit->raw);
- decref(&sdev->r);
+ poperror();
break;
case Qpart:
return sdbio(c, 1, a, n, off);
case Qextra:
- return extrarw(1, c, a, n, off);
+ return extrarw(c, 1, a, n, off);
}
return n;
@@ -1562,13 +1521,10 @@
unit = sdev->unit[UNIT(c->qid)];
}
qlock(&unit->ctl);
-
- d = nil;
if(waserror()){
qunlock(&unit->ctl);
if(sdev != nil)
decref(&sdev->r);
- free(d);
nexterror();
}
@@ -1594,6 +1550,10 @@
error(Eperm);
d = smalloc(sizeof(Dir)+n);
+ if(waserror()){
+ free(d);
+ nexterror();
+ }
n = convM2D(dp, n, &d[0], (char*)&d[1]);
if(n == 0)
error(Eshortstat);
@@ -1607,11 +1567,12 @@
error(Eperm);
if(d[0].mode != ~0UL)
perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
- poperror();
qunlock(&unit->ctl);
if(sdev != nil)
decref(&sdev->r);
free(d);
+ poperror();
+ poperror();
return n;
}
@@ -1682,6 +1643,7 @@
if(sdev->ifc->clear)
sdev->ifc->clear(sdev);
+
free(sdev);
return 0;
}
@@ -1717,7 +1679,7 @@
if(e->name == nil)
kstrdup(&e->name, s);
if(e->user == nil)
- kstrdup(&e->user, u);
+ kstrdup(&e->user, u);
e->perm = perm;
e->r = r;
e->w = w;