A cckd file contains track images, which may be compressed or uncompressed, and overhead blocks which are headers, lookup tables, and free space. Compressed track images may be compressed by zlib or bzip2.
Track images are addressed by track number using a two table
lookup method: track number divided by 256 (trk >> 8)
indexes into the primary lookup table, which contains the file offset
to the secondary lookup table; the remainder of track number
divided by 256 (trk & 0xff) indexes into the corresponding
secondary lookup table, which contains the offset and
length of the track image.
There is a single primary lookup table and a variable number of secondary lookup tables. The maximum number of secondary lookup tables is the number of tracks for the device type divided by 256, rounded up. For example, a 3390-3 contains 50085 tracks and would require at most 196 secondary lookup tables.
A cckd file can take significantly less file space than a regular CKD file because
Shadow files are implemented using the same file structure as base cckd files. By default, there can be up to 8 shadow files in use at any time for an emulated CKD device. The base file is designated file [0] and the shadow files are files [1] up to file [8]. The highest numbered file in use at a given time is the current file, where all writes will occur. Track reads start with the current file and proceed down until a file is found that actually contains the track image.
A shadow file, then, contains all the changes made to the emulated CKD dasd since its creation, until the creation of the next shadow file. The moment of the shadow file's creation can be thought of as taking a snapshot of the current emulated CKD dasd at that time, because if the shadow file is later removed, then the emulated CKD dasd will revert to the state it was at when the snapshot was taken.
Using shadow files, you can keep the base CKD file on a read-only device such as cdrom, or change the base CKD file attributes to read-only, ensuring that this file can never be corrupted.
Hercules console commands are provided to add a new shadow file, remove the current shadow file (with or without backward merge), compress the curent shadow file, and display the shadow file status and statistics.
CKDDASD_DEVHDR
block. The eye-catcher at the beginning is different to distinguish
the file:
CCKDDASD_DEVHDR block. This contains the
version-release-mod level of the file, options, space statistics,
and total number of cylinders for the device. Next is
the primary lookup table or the L1TAB. Each 4 byte
entry in the L1TAB contains the file offset to a secondary
lookup table (or L2TAB) or 0x00000000 (indicating that
the secondary lookup table is null), or 0xffffffff (indicating
that the previous file should be searched instead).L1TAB is dependent on the number
of tracks on the emulated device.
CKDDASD_DEVHDR |
CCKDDASD_DEVHDR |
L1TAB |
Following the L1TAB,
in no particular order, are L2TABs, compressed track
images, and free spaces.
L2TABs contain 256 8-byte
entries,and each are, consequently, 2048 bytes in length. Each entry
contains the offset and length of a track image. If
the offset is 0x00000000 then the track image is null;
if the offset is 0xffffffff then the previous file should be
searched instead.
L2TAB entry
offset4 bytes |
length2 bytes |
[unused]2 bytes |
A compressed track image contains the following two fields:
HA5 bytes |
track image (compressed or uncompressed)length-5 bytes |
The HA contains 0CCHH, that is, a byte of zeroes, 2 bytes indicating
the cylinder of the track, and 2 bytes indicating the head of the track
on the cylinder. Both CC and HH are stored in
big-endian byte order. The track is computed by
trk = (((CC[0] << 8) + CC[1]) * trks_per_cyl) + (HH[0] << 8) + HH[1]
HA is always 0x00 (at least in emulated
CKD files), this byte as stored in the file actually indicates the compression
algorithm used for the remainder of the track image
(0 = no compression, 1 = zlib compression, 2 = bzip2 compression).
The hi-order bit (0x80) may also be on, indicating the track image was written
under stress.
Free space contains a 4-byte offset to the next free space, a 4-byte length of the free space, and zero or more bytes of residual data.
offset4 bytes |
length4 bytes |
residual(length - 8) bytes |
The minimum length of a free space is 8 bytes.
Since free space is ordered by file offset and no two free spaces are adjacent,
offset in the free space entry is always greater than the current free space
offset + the current free space length, unless the offset is zero,
which indicates the free space chain is terminated.
The free space chain is read when the file is opened for read-write and
written when the file is closed; while the file is opened, the free space chain is
maintained in storage.
The interface
All Hercules emulated devices have standard interface routines described
by the DEVHND structure. These routines are
| init | Device initialization (attach) |
| exec | Device execute channel command |
| close | Device close (detach) |
| query | Device query |
| start | Device channel program start |
| end | Device channel program end |
| resume | Device channel program resume |
| suspend | Device channel program suspend |
Emulated CKD DASD devices have two additional routines:
| ckdrdtrk | Read CKD track image |
| ckdupdtrk | Update CKD track image |
ckdrdtrk is called whenever a SEEK
type channel command is executed and ckdupdtrk is
called whenever any of the various WRITE channel
commands modifies the current track image.
The cckd code implements the following routines:
cckddasd_init_handler |
cckd device initialization (attach) |
cckddasd_close_device | cckd device close (detach) |
cckd_start | cckd channel program start/resume |
cckd_end | cckd channel program end/suspend |
The cache
The implementation is cache table driven. The cache table contains 16 to 1024 entries, each representing a track image, and is shared by all cckd devices. Each entry contains a pointer to a track image buffer which is 64K bytes. That is, every 16 entries represents 1M of buffer space. The size of the cache can be changed by a configuration file statement or by a hercules console command.
Each entry can be in one (or certain combinations) of the following states:
| active | A channel program is active for the device
and the track image is the last SEEKed
track image. |
| updated | The track image has been updated by a
WRITE command. |
| write | The track image is not active and has been updated and is eligible to be written. |
| reading | The track image is currently being read. |
| writing | The track image is currently being written. |
| inactive | The track image is not busy and is eligible to be stolen |
ckdrdtrk routine is called, and the track to be
read is not the active track, then a track switch event
occurs. The cache is scanned to see if it contains the track image. If
it does, then a cache hit occurs else a cache miss
occurs.
In the case of a cache hit, if the entry status is reading or writing then the code waits for the read or write to complete. If the entry is write-pending, then the entry is changed back to updated.
Otherwise, for a cache miss, the oldest inactive cache entry will then be stolen. If no inactive cache entry was found then the cache is flushed and the code will have to wait for an inactive cache entry to become available. This is called a cache wait event. When the cache is flushed, all cache entries that have been updated and are not active are set to write-pending and the writer thread is signalled. After an entry has been stolen the track image will then be read and uncompressed. If sequential access is detected then track readaheads will be scheduled.
L1 tables
The L1 tables, or primary lookup tables, contain the file offsets to each L2 table, or secondary lookup table. Each L1 table 4-byte entry represents 256 track images and there is an L1 table for the base file and each opened shadow file (if any). These tables are memory resident.
The L2 cache
The L2 tables, or secondary lookup tables contain the file offsets and lengths of 256 track images. Each table is 2K in length. These tables are cached in the l2cache, which is shared for all cckd devices. The cache can contain 128 (512K) entries to 1024 entries (2M). Each cckd device has one active l2cache entry implying that, architecturally speaking, there can be no more than 1024 cckd devices. If this is a problem for you then I'll buy you a beer ;-)
The size of the l2cache can be specified by a configuration statement or changed by a hercules console command. If a cache miss occurs and no inactive entries are found, then the cache is automatically extended (unless the 1024 entry barrier would be crossed).
L2 tables are read but never written. Instead, as track images are written, the individual 8-byte L2 entries are updated in the file.
Writing
Whenever the ckdupdtrk is called, indicating the active
track image has been updated, the updated flag bit is turned
on for the cache entry. However, the updated cache entries are never
scheduled to be written until a cache flush occurs (routine
cckd_flush_cache). A cache flush occurs whenever a cache
entry couldn't be stolen during read or at the beginning of
the garbage collection cycle.
When a cache flush occurs, all cache entries that are updated (but not active) get the write-pending bit turned on and one of the writer threads is signalled (or created).
The writer thread selects the oldest cache entry with the write-pending bit on and changes the status to writing. If there are other writes pending and other writer threads are waiting then they are signalled. Otherwise if there are writes pending and the maximum number of writer threads hasn't been created yet, then a new writer thread is created.
The writer thread, because it performs track image compression, is cpu intensive. Therefore, the writer thread resets its priority to 1 below the cpu thread(s) (except under Cygwin (Windows)). In periods of write stress then the level of compression is downgraded. Write stress occurs when more than a quarter of the cache entries are pending write, or when there are threads waiting for a cache entry, or when a thread is waiting for this track image to be written. When a track image is written under stress, a bit is turned on in the track image so that the garbage collector can later rewrite the track image properly compressed during a period of no stress.
A track image is always written to a new location in the file. After a successful write, its L2 entry is updated and then the space it previously occupied is freed.
The writer threads
The Garbage Collector
For some reason, this seems to be everyone's favorite routine. For me, it has to do with the fact that the garbage man only has to apparently work on Fridays ;-).
Simply, the garbage collector moves occupied spaces (track images and level 2 tables) towards the beginning of the file while moving free spaces towards the end of the file. When a free space reaches the end of the file, then the file is truncated, that is, reduced in size. Another important job the garbage collector performs is to combine free spaces to make a larger free space that will be more likely to satisfy a get space request. Finally, the garbage collector will cause track images that were written under stress to be rewritten (with optimal compression).
The garbage collector runs in a separate thread. There is a single garbage collector for all cckd devices. The collector waits for some number of seconds and then performs collection for each cckd device in turn. The wait interval and the aggressiveness parameter can be specified by a configuration file statement or by a hercules console command.
The garbage collector algorithm simply selects an occupied space after some free space, obtains a new space for that space, writes it to the new space, updates the meta-data for that space to point to the new space, frees the previously occupied space, and repeats the process until some number of bytes have been moved. In other words, the collector shifts the spaces around coherently such that in the event of a crash then the space occupies at least one space in the file (the original and possibly the new).
The garbage collector on each interval (or round ;-) flushes the cache and waits for all pending writes to complete. Therefore, the collector doesn't run while write stress is occurring.
hercules.cnf in place of the regular CKD file names.
You can also use the cckddump program on an os/390 system to build a compressed CKD file from a real disk that can be transferred to your Hercules machine and used right away.
Shadow files are automatically enabled for cckd files; you must explicitly enable them for regular CKD files. To enable shadowing for a CKD device, specify
0500 3390 ../mvs/disks/mvsres.500 sf=../mvs/shadows/mvsres_1.500
If you did not specify sf= for a cckd file, or you wish to change
the shadow file name for a cckd or regular file, but no shadow files are
in use, then you can issue the following command on the Hercules console:
Specifying a shadow_file_name does not explicitly create a shadow file if the base file or current shadow file is able to be opened read-write. Otherwise, if the base file and all existing shadow files (if any) can only be opened read-only, then a new shadow file is created.
To explicitly create a new shadow file, issue the following command on the Hercules console:
To remove the current shadow file, issue either of the following commands on the Hercules console:
To compress the current shadow file issue the following command on the Hercules console:
To display the status and statistics for a shadow-enabled file, issue the following command on the Hercules console:
|   | size | The total size of the file |
|   | free | The amount of free space in the file as a percentage of the file size |
|   | nbr | The number of free spaces in a file |
|   | st | File open status - ro=read-only; rd=read-only, but can be opened read-write; rw=read-write |
|   | reads | Number of times cckd_read_trkimg performed physical read i/o |
|   | writes | Number of times cckd_write_trkimg performed physical write i/o |
|   | l2reads | Number of times a secondary lookup table was read |
|   | hits | Number of times cckd_read_trk found a track image in the track cache when called by the i/o thread |
|   | switches | Number of times cckd_read_trk was called by the i/o thread (cckd_lseek) |
|   | readaheads | Number of track images read by the readahead threads |
|   | misses | Number of track images read by the readahead threads that were never referenced when the track cache entry was stolen |
hercules.cnf
file (or on the attach panel command).
| Regular | cckd | Function | |
| syncio syio nosyncio nosyio | X | X | Specifies whether or not synchronous I/O will be attempted for the device. For synchronous I/O, the channel program will be executed within the scope of the SIO or SSCH instruction as long as all data referenced by the channel program is already cached. If a ccw attempts to reference data that is not cached, then the channel program is restarted asynchronously at that ccw. Synchronous I/O reduces threading overhead, which may resut in a performance boost. The default is syncio for cckd files and nosyncio for regular ckd files. |
| lazywrite nolazywrite | X |   | Data written to a cached track image will not be immediately written, but will be written when a track switch occurs. Thus, only one write will occur for a track image while it is the active image. nolazywrite, the default, specifies that all writes are performed when requested. |
| fulltrackio fulltrkio ftio nofulltrackio nofulltrkio noftio | X |   | Specifies whether or not a full track will be read when a track switch occurs. Subsequent reads to this track image will not cause any physical I/Os. Turning on fulltrackio can considerably enhance CKD device response time. However, if you are sharing CKD disk images with more than 1 instance of Hercules at the same time when writes could occur, you should specify nofulltrackio. The default is fulltrackio. |
| readonly rdonly ro | X | X | Causes the CKD file image to be opened read-only. Attempts to write to the emulated device will cause an I/O error unless option fakewrite is also specified. If readonly is specified for shadowed file images, then the base file will be opened readonly and a shadow file will be created if one doesn't exist. |
| fakewrite fakewrt fw | X | X | Writes to a readonly file will be considered successful even though no write actually occurred. This option is only meaningful if readonly is also specified. Fakewrite is ignored for shadowed file images. |
| cache=n | X | X | Specifies the number of track images that will be cached. The default is the number of tracks per cylinder for the device. [For cckd files, the default is the number of tracks per cylinder plus the number of readahead threads]. If nofulltrackio is specified for a regular CKD file, then no caching occurs. Caching always occurs for cckd files, although you can set the cache value to 1. |
| sf=file_name | X | X | Specifies the name of the shadow file(s) for the emulated device. The name should have a spot where the shadow file number can be inserted into the name (see above). |
| l2cache=n | * | X | Specifies the number of Secondary Lookup Tables (l2tabs) that will be cached for the cckd or shadowed device. (Each l2tab is 2048 bytes). The default is 32. |
| dfwq=n | * | X | Specifies a threshold for the size of deferred-write-queue where processing will be throttled if the size exceeds this number. Each entry in the deferred- write-queue contains a pointer to a buffer whose size is max-track-size. The default is 64. |
| wt=n | * | X | Specifies the time in seconds that an updated track image will be written after its last reference. The garbage collector is responsible for scheduling these old track images to be updated. The default is 60 seconds. |
| ra=n | * | X | Specifies the number of readahead threads (and number of tracks to be read ahead) when sequential access to the emulated device is detected. That is, each track that is read ahead of time is read by a different thread. A value between 0 and 9 can be specified. Currently, readahead should be disabled for Windows32 due to an unknown error involving the pthreads implementation. Default for WIN32 is 0 otherwise the default is 2. |
| dfw=n | * | X | Specifies the number of deferred write threads. A number between 1 and 9 may be specified; the default is 1. It has not been shown that specifying a greater number results in any performance improvements. |
Generally, the defaults for all options (except sf=) should not be changed unless there is an explicit reason for doing so. If you use cckd files, then I strongly recommend that you start using shadow files. If you use regular CKD files, then you can use shadow files if you want to gain the snapshot benefit .
| Q. | What devices are supported ? | ||||||||
| A. |
2311, 2314, 3330, 3340, 3350, 3375, 3380, 3390 and 9345.
| ||||||||
| Q. | Is a 3390 model 9 supported ? | ||||||||
| A. |
Yes, maybe. A 3390-9 is a little over 8G in size.
A cckd file cannot exceed 2G on a system that does
not support large files, otherwise it cannot exceed
4G. If the data on the 3390-9 compresses to below
these limits then the answer is Yes.
| ||||||||
| Q. | How can I get rid of the free space in my files ? | ||||||||
| A. |
Once the total amount of free space falls below 6% of
the total file size, the garbage collector is not very
aggressive about eliminating free space. To remove
all free space from the file while Hercules is running
use the sfc console command. See
Using Shadow Files above.
Otherwise, you can use the cckdcomp utility.
See Utilities above.
| ||||||||
| Q. | How can I display the space statistics for a compressed file ? | ||||||||
| A. |
The statistics are displayed when the compressed file
is opened. Currently, there is no supplied method to
display these statistics at any other time. However,
it shouldn't be too hard to write a shell script
(similar to dasdlist) to display these
statistics. The statistics are contained in the
CCKDDASD_DEVHDR which is at offset 512
in the compressed file; the header is mapped in
hercules.h.
| ||||||||
| Q. | What is a "null track" anyway ? | ||||||||
| A. |
The term "null track" is just something I made up. It is
what is returned when a zero offset is found in either the
primary or secondary lookup table for the track. It contains
the folllowing fields:
| ||||||||
| Q. | I want to try bzip2 but I'm getting compiler errors. What am I doing wrong ? | ||||||||
| A. |
Probably bzip2 is not installed or is not installed
properly. You can obtain bzip2 from
here.
If bzip2 is installed, then you need to find the directory
where bzlib.h is installed and the
directory where libbz2.a is installed.
You can then add "-I bzlib.h-directory" to the
CFLAGS in the make file and add "-L libbz2.a-directory"
to the LFLAGS.
| ||||||||
| Q. | Which is better, zlib or bzip2 ? | ||||||||
| A. |
This is a religious question. I have no actual preference,
I just wanted to make a choice available.
| ||||||||
| Q. | Can other compression programs be used ? | ||||||||
| A. |
Yes. The program is architecturally structured so that other
compression algorithms can be added rather painlessly. This
will require, of course, an update to the source.
| ||||||||
| Q. | Can this compression scheme be used for FBA devices too ? | ||||||||
| A. |
I have not worked with FBA devices for over 20 years.
However, it seems to me that a similar program for FBA
devices should be simpler than this program for CKD devices
(none of those count/key/data fields mucking everything
up). Since an FBA block is 512 bytes, it might not
be efficient to have each block compressed individually;
it might be better to compress blocks in 32K or 64K chunks.
If someone asks very nicely, I may consider looking into it;-)
|
cckddump.hla) is an
os/390 assembler language program that creates a compressed CKD Dasd emulation
file from a real DASD volume. This program must be APF-authorized since
it modifies the DEB to be able to read all tracks from the real device.
The program executes 16 or so instructions while in supervisor state/key 0;
otherwise the program runs entirely in problem state/key 8.
It is not the prettiest assembler language program I've ever written, and
there are plenty of enhancements that I originally intended to put into the
program that I haven't yet; once I got the program working good enough, I
spent the rest of my time writing the fun stuff, the Hercules part.
The real CKD Dasd volume that is dumped must be an ECKD device (ie support 'Locate Record' and 'Read Track' CCWs); this shouldn't be a problem because I don't think any os/390 release supports a non-ECKD device. The output file must be a DASD file; its characteristics are LRECL=4096, BLKSIZE=4096, RECFM=F. The program only dumps allocated tracks (plus track 0) and only dumps tracks up to DS1LSTAR for DSORG=PS and DSORG=PO files. The program will call zlib to compress the track images if the zlib routines have been linked with the program; however, I don't think the program will be advantageous if it can't call zlib.
#endif, add the following lines:
# pragma map(compress,"COMPRESS")
# pragma map(compress2,"COMPRES2")
# pragma map(uncompress,"UNCOMPRE")
// JOB //CC JCLLIB ORDER=(CBC.SCBCPRC) //* //ADLER32 EXEC EDCC,INFILE='prefix.ZLIB.C(ADLER32)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(ADLER32),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //COMPRESS EXEC EDCC,INFILE='prefix.ZLIB.C(COMPRESS)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(COMPRESS),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //CRC32 EXEC EDCC,INFILE='prefix.ZLIB.C(CRC32)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(CRC32),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //DEFLATE EXEC EDCC,INFILE='prefix.ZLIB.C(DEFLATE)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(DEFLATE),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //EXAMPLE EXEC EDCC,INFILE='prefix.ZLIB.C(EXAMPLE)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(EXAMPLE),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //GZIO EXEC EDCC,INFILE='prefix.ZLIB.C(GZIO)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(GZIO),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //INFBLOCK EXEC EDCC,INFILE='prefix.ZLIB.C(INFBLOCK)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(INFBLOCK),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //INFCODES EXEC EDCC,INFILE='prefix.ZLIB.C(INFCODES)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(INFCODES),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //INFFAST EXEC EDCC,INFILE='prefix.ZLIB.C(INFFAST)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(INFFAST),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //INFLATE EXEC EDCC,INFILE='prefix.ZLIB.C(INFLATE)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(INFLATE),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //INFTREES EXEC EDCC,INFILE='prefix.ZLIB.C(INFTREES)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(INFTREES),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //INFUTIL EXEC EDCC,INFILE='prefix.ZLIB.C(INFUTIL)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(INFUTIL),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //TREES EXEC EDCC,INFILE='prefix.ZLIB.C(TREES)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(TREES),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //UNCOMPR EXEC EDCC,INFILE='prefix.ZLIB.C(UNCOMPR)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(UNCOMPR),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H //* //ZUTIL EXEC EDCC,INFILE='prefix.ZLIB.C(ZUTIL)', // CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)', // OUTFILE='prefix.ZLIB.OBJ(ZUTIL),DISP=SHR' //USERLIB DD DISP=SHR,DSN=prefix.ZLIB.H
// JOB //PLKED EXEC PGM=EDCPRLK //SYSMSGS DD DISP=SHR,DSN=CEE.SCEEMSGP(EDCPMSGE) //SYSLIB DD DISP=SHR,DSN=prefix.ZLIB.OBJ // DD DISP=SHR,DSN=CEE.SCEEOBJ //SYSOUT DD SYSOUT=* //SYSPRINT DD SYSOUT=* //SYSIN DD DISP=SHR,DSN=prefix.ZLIB.OBJ(ADLER32) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(COMPRESS) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(CRC32) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(DEFLATE) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(GZIO) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(INFBLOCK) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(INFCODES) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(INFFAST) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(INFLATE) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(INFTREES) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(INFUTIL) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(TREES) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(UNCOMPR) // DD DISP=SHR,DSN=prefix.ZLIB.OBJ(ZUTIL) //SYSMOD DD DISP=SHR,DSN=prefix.ZLIB.OBJ(ZLIB)
// JOB //C EXEC PGM=ASMA90 //SYSLIB DD DISP=SHR,DSN=SYS1.MACLIB // DD DISP=SHR,DSN=SYS1.MODGEN //SYSPRINT DD SYSOUT=* //SYSIN DD DISP=SHR,DSN=prefix.cckddump.source(CCKDDUMP) //SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(1,1)) //SYSLIN DD DISP=(,PASS),DSN=&&OBJ,UNIT=SYSDA,SPACE=(CYL,(1,1)) // LRECL=80,BLKSIZE=3200,RECFM=FB //L EXEC PGM=HEWL //SYSPRINT DD SYSOUT=* //SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(1,1)) //SYSLIB DD DISP=SHR,DSN=CEE.SCEESPC // DD DISP=SHR,DSN=CEE.SCEELKED //ZLIB DD DISP=SHR,DSN=prefix.ZLIB.OBJ //SYSLMOD DD DISP=SHR,DSN=apfauth.load //SYSLIN DD DISP=(OLD,DELETE),DSN=&&OBJ // DD * INCLUDE ZLIB(ZLIB) INCLUDE SYSLIB(EDCXHOTL) INCLUDE SYSLIB(EDCXHOTU) INCLUDE SYSLIB(EDCXHOTT) ORDER MAIN(P) ENTRY MAIN SETCODE AC(1) NAME CCKDDUMP(R)
// JOB //S1 EXEC PGM=CCKDDUMP //STEPLIB DD DISP=SHR,DSN=apfauth.load //SYSPRINT DD SYSOUT=*,RECFM=VB,LRECL=255,BLKSIZE=4096 //SYSUT1 DD DISP=OLD,UNIT=SYSDA,VOL=SER=volser //SYSUT2 DD DISP=(,CATLG),DSN=prefix.volser.cckd, // UNIT=SYSDA,SPACE=(TRK,(7500,1500),RLSE), // LRECL=4096,BLKSIZE=4096,RECFM=F
greg smith
Last updated 1 May 2002