ZDSFS
Filesystems |
---|
Virtual Filesystems |
Disk Filesystems |
CD/DVD Filesystems |
Network Filesystems |
Flash Filesystems |
ZDSFS is the normal filesystem used on virtually all DASD disks.
VTOC
The filesystem uses DSCBs to hold the information of all files in the VTOC table (Volume's Table Of Contents). This table is found after the DASD's IPL which usually means the VTOC is at record 3, cylinder 0 and head 0.
To find the sequence of format 1 entries the OS has to read 0, 0, 3. Place the first 20 bytes into a buffer then obtain the location of the format 1 DSCBs:
void GetCHRFromVTOC(void *buffer) {
uint16_t cyl, head;
uint8_t rec;
memcpy(&cyl, buffer + 15, 2); /* 15-16 */
memcpy(&head, buffer + 17, 2); /* 17-18 */
memcpy(&rec, buffer + 19, 1); /* 19-19 */
return;
}
Format 1 DSCB
Name | Size | Usage |
---|---|---|
DS1NAM | 44 | Name of dataset |
DS1FMTID | 1 | Format Id |
UNUSED | 80 | |
EXT_TYPE | 1 | |
SEQUENCE_NUMBER |
1 | |
START_CC | 2 | Starting cylinder |
START_HH | 2 | Starting head |
END_CC | 2 | Ending cylinder |
END_HH | 2 | Ending head |
This entry describes a dataset (file) general information, including location and name. This is generally what most people will search for.
The entries are ordered in a chain-like structure, where a formatId=0 entry denotes the end of said chain.
// NOTE: This code assumes EBCDIC is being used
void CheckDSCB(struct DSCB1 *dscb, const char *name) {
if(dscb1.ds1fmtid == '1') {
dscb1.ds1fmtid = ' ';
if(!memcmp(&dscb1.ds1dsnam, name, strlen(name))) {
// Dataset found
cyl = dscb1.start_cc;
head = dscb1.start_hh;
rec = 1;
kprintf("DATASET %s @ CYL=%i,HEAD=%i,RECORD=%i\n", name, (int)cyl, (int)head, (int)rec);
// The kernel now should use Cyl, Head and the Rec locations provided to read the dataset
kpanic("TODO: Use cyl, head and rec to read the file\n");
}
} else if(dscb1.ds1dsnam[0] == '\0') {
// Not found
kpanic("Could not find file %s!", name);
}
}
Finding the files is just a matter of reading records until reaching the end of the head, then incrementing heads and after reading the last head in the cylinder, incrementing cylinders. This also has to be done for reading files.
This is mostly specific to DASD devices but it's provided for clarity.
// NOTE: This code assumes EBCDIC is being used
void FindFile(const char *name) {
while(errcnt < 4) {
r = DasdReadCHR(hdl, &cyl, &head, &rec, &dscb1, sizeof(dscb1));
if(r < 0) {
++errcnt;
if(errcnt == 1) {
// If we have an error reading this record skip to the next
++rec;
} else if(errcnt == 2) {
// Next record failed?, now we need to change heads
rec = 1;
++head;
} else if(errcnt == 3) {
// Switch cylinders if we can't read new heads either
rec = 1;
head = 0;
++cyl;
}
continue;
}
errcnt = 0;
if(r >= (int)sizeof(dscb1)) {
CheckDSCB(&dscb1, name);
}
// Go to next record
++rec;
}
}
See also
Source code
- https://sourceforge.net/p/pdos/gitcode/ci/master/tree/s370/pdosutil.c#l25 Find a file from ZDSFS
External links
- https://www.ibm.com/docs/en/zos/2.3.0?topic=components-data-set-control-block-dscb-types DSCB types
- https://www.ibm.com/docs/en/zos/2.3.0?topic=dscbs-how-found Obtaining format 1 entries