venti: allow plan 9 partitions as disk subnames

This commit is contained in:
Russ Cox 2008-07-03 22:37:17 -04:00
parent cb29a5fce6
commit 304ab920ad

View file

@ -19,6 +19,8 @@
u32int maxblocksize; u32int maxblocksize;
int readonly; int readonly;
int findsubpart(Part *part, char *name);
static int static int
strtoullsuf(char *p, char **pp, int rad, u64int *u) strtoullsuf(char *p, char **pp, int rad, u64int *u)
{ {
@ -56,17 +58,21 @@ strtoullsuf(char *p, char **pp, int rad, u64int *u)
} }
static int static int
parsepart(char *name, char **file, u64int *lo, u64int *hi) parsepart(char *name, char **file, char **subpart, u64int *lo, u64int *hi)
{ {
char *p; char *p;
*file = estrdup(name); *file = estrdup(name);
if((p = strrchr(*file, ':')) == nil){ *lo = 0;
*lo = 0; *hi = 0;
*hi = 0; *subpart = nil;
if((p = strrchr(*file, ':')) == nil)
return 0;
*p++ = 0;
if(isalpha(*p)){
*subpart = p;
return 0; return 0;
} }
*p++ = 0;
if(*p == '-') if(*p == '-')
*lo = 0; *lo = 0;
else{ else{
@ -93,11 +99,13 @@ initpart(char *name, int mode)
{ {
Part *part; Part *part;
Dir *dir; Dir *dir;
char *file; char *file, *subname;
u64int lo, hi; u64int lo, hi;
if(parsepart(name, &file, &lo, &hi) < 0) if(parsepart(name, &file, &subname, &lo, &hi) < 0){
werrstr("cannot parse name %s", name);
return nil; return nil;
}
trace(TraceDisk, "initpart %s file %s lo 0x%llx hi 0x%llx", name, file, lo, hi); trace(TraceDisk, "initpart %s file %s lo 0x%llx hi 0x%llx", name, file, lo, hi);
part = MKZ(Part); part = MKZ(Part);
part->name = estrdup(name); part->name = estrdup(name);
@ -124,7 +132,7 @@ initpart(char *name, int mode)
fprint(2, "warning: %s opened for reading only\n", name); fprint(2, "warning: %s opened for reading only\n", name);
} }
part->offset = lo; part->offset = lo;
dir = dirfstat(part->fd); dir = dirstat(file); /* no dirfstat; need name to identify disk devices */
if(dir == nil){ if(dir == nil){
freepart(part); freepart(part);
seterr(EOk, "can't stat partition='%s': %r", file); seterr(EOk, "can't stat partition='%s': %r", file);
@ -155,6 +163,11 @@ initpart(char *name, int mode)
part->fsblocksize = sfs.f_bsize; part->fsblocksize = sfs.f_bsize;
} }
#endif #endif
if(subname && findsubpart(part, subname) < 0){
werrstr("cannot find subpartition %s", subname);
freepart(part);
return nil;
}
free(dir); free(dir);
return part; return part;
} }
@ -464,206 +477,106 @@ readfile(char *name)
return b; return b;
} }
/*
* Search for the Plan 9 partition with the given name.
* This lets you write things like /dev/ad4:arenas
* if you move a disk from a Plan 9 system to a FreeBSD system.
*
* God I hope I never write this code again.
*/
#ifndef PLAN9PORT #define MAGIC "plan9 partitions"
static int static int
sdreset(Part *part) tryplan9part(Part *part, char *name)
{ {
char *name, *p; uchar buf[512];
int i, fd, xfd[3], rv; char *line[40], *f[4];
static QLock resetlk; int i, n;
Dir *d, *dd; vlong start, end;
fprint(2, "sdreset %s\n", part->name); /*
name = emalloc(strlen(part->filename)+20); * Partition table in second sector.
strcpy(name, part->filename); * Could also look on 2nd last sector and last sector,
p = strrchr(name, '/'); * but those disks died out long before venti came along.
if(p) */
p++; if(readpart(part, 512, buf, 512) != 512)
else
p = name;
strcpy(p, "ctl");
d = dirstat(name);
if(d == nil){
free(name);
return -1; return -1;
}
/* /* Plan 9 partition table is just text strings */
* We don't need multiple people resetting the disk. if(strncmp((char*)buf, "part ", 5) != 0)
*/ return -1;
qlock(&resetlk);
if((fd = open(name, OWRITE)) < 0)
goto error;
dd = dirfstat(fd);
if(d && dd && d->qid.vers != dd->qid.vers){
fprint(2, "sdreset %s: got scooped\n", part->name);
/* Someone else got here first. */
if(access(part->filename, AEXIST) >= 0)
goto ok;
goto error;
}
/* buf[511] = 0;
* Write "reset" to the ctl file to cause the chipset n = getfields((char*)buf, line, 40, 1, "\n");
* to reinitialize itself (specific to sdmv driver). for(i=0; i<n; i++){
* Ignore error in case using other disk. if(getfields(line[i], f, 4, 1, " ") != 4)
*/ break;
fprint(2, "sdreset %s: reset ctl\n", part->name); if(strcmp(f[0], "part") != 0)
write(fd, "reset", 5); break;
if(strcmp(f[1], name) == 0){
if(access(part->filename, AEXIST) >= 0) start = 512*strtoll(f[2], 0, 0);
goto ok; end = 512*strtoll(f[3], 0, 0);
if(start < end && end <= part->size){
/* part->offset += start;
* Re-run fdisk and prep. Don't use threadwaitchan part->size = end - start;
* to avoid coordinating for it. Reopen ctl because return 0;
* we reset the disk. }
*/
strcpy(p, "ctl");
close(fd);
if((fd = open(name, OWRITE)) < 0)
goto error;
strcpy(p, "data");
xfd[0] = open("/dev/null", OREAD);
xfd[1] = dup(fd, -1);
xfd[2] = dup(2, -1);
fprint(2, "sdreset %s: run fdisk %s\n", part->name, name);
if(threadspawnl(xfd, "/bin/disk/fdisk", "disk/fdisk", "-p", name, nil) < 0){
close(xfd[0]);
close(xfd[1]);
close(xfd[2]);
goto error;
}
strcpy(p, "plan9");
for(i=0; i<=20; i++){
sleep(i*100);
if(access(part->filename, AEXIST) >= 0)
goto ok;
if(access(name, AEXIST) >= 0)
goto prep;
}
goto error;
prep:
strcpy(p, "ctl");
close(fd);
if((fd = open(name, OWRITE)) < 0)
goto error;
strcpy(p, "plan9");
xfd[0] = open("/dev/null", OREAD);
xfd[1] = dup(fd, -1);
xfd[2] = dup(2, -1);
fprint(2, "sdreset %s: run prep\n", part->name);
if(threadspawnl(xfd, "/bin/disk/prep", "disk/prep", "-p", name, nil) < 0){
close(xfd[0]);
close(xfd[1]);
close(xfd[2]);
goto error;
}
for(i=0; i<=20; i++){
sleep(i*100);
if(access(part->filename, AEXIST) >= 0)
goto ok;
}
error:
fprint(2, "sdreset %s: error: %r\n", part->name);
rv = -1;
if(fd >= 0)
close(fd);
goto out;
ok:
fprint(2, "sdreset %s: all okay\n", part->name);
rv = 0;
goto out;
out:
free(name);
qunlock(&resetlk);
return rv;
}
static int
reopen(Part *part)
{
int fd;
fprint(2, "reopen %s\n", part->filename);
if((fd = open(part->filename, ORDWR)) < 0){
if(access(part->filename, AEXIST) < 0){
sdreset(part);
fd = open(part->filename, ORDWR);
}
if(fd < 0){
fprint(2, "reopen %s: %r\n", part->filename);
return -1; return -1;
} }
} }
if(fd != part->fd){ return -1;
dup(fd, part->fd);
close(fd);
}
return 0;
} }
typedef struct Spawn Spawn; #define GSHORT(p) (((p)[1]<<8)|(p)[0])
struct Spawn #define GLONG(p) ((GSHORT(p+2)<<16)|GSHORT(p))
typedef struct Dospart Dospart;
struct Dospart
{ {
Channel *c; uchar flag; /* active flag */
int fd[3]; uchar shead; /* starting head */
char *file; uchar scs[2]; /* starting cylinder/sector */
char **argv; uchar type; /* partition type */
uchar ehead; /* ending head */
uchar ecs[2]; /* ending cylinder/sector */
uchar offset[4]; /* starting sector */
uchar size[4]; /* length in sectors */
}; };
static void
spawnproc(void *v)
{
int i, *fd;
Spawn *s;
rfork(RFFDG);
s = v;
fd = s->fd;
for(i=0; i<3; i++)
dup(fd[i], i);
if(fd[0] > 2)
close(fd[0]);
if(fd[1] > 2 && fd[1] != fd[0])
close(fd[1]);
if(fd[2] > 2 && fd[2] != fd[1] && fd[2] != fd[0])
close(fd[2]);
procexec(s->c, s->file, s->argv);
}
static int int
threadspawnl(int fd[3], char *file, char *argv0, ...) findsubpart(Part *part, char *name)
{ {
int pid; int i;
Spawn s; uchar buf[512];
u64int size;
Dospart *dp;
/* See if this is a Plan 9 partition. */
if(tryplan9part(part, name) >= 0)
return 0;
s.c = chancreate(sizeof(void*), 0); /* Otherwise try for an MBR and then narrow to Plan 9 partition. */
memmove(s.fd, fd, sizeof(s.fd)); if(readpart(part, 0, buf, 512) != 512)
s.file = file;
s.argv = &argv0;
vtproc(spawnproc, &s);
pid = recvul(s.c);
if(pid < 0)
return -1; return -1;
close(fd[0]); if(buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
if(fd[1] != fd[0]) return -1;
close(fd[1]); dp = (Dospart*)(buf+0x1BE);
if(fd[2] != fd[1] && fd[2] != fd[0]) size = part->size;
close(fd[2]); for(i=0; i<4; i++){
return pid; if(dp[i].type == '9'){
part->offset = 512LL*GLONG(dp[i].offset);
part->size = 512LL*GLONG(dp[i].size);
if(tryplan9part(part, name) >= 0)
return 0;
part->offset = 0;
part->size = size;
}
/* Not implementing extended partitions - enough is enough. */
}
return -1;
} }
#endif