Getting the z/OS standard image to work.

I had a lot of challenges getting the zD&T replacement (the standard image) to work. I do not know if this is the same image that every one else gets, or if mine was “a special” one. Some things did not work, somethings were not best practice.

I also wanted to use the data from my previous systems, my PDS, my Unix file systems, my keyrings etc. I also wanted to future proof migrating to the next code drop from IBM.

Summary of actions

Below is a list of the things I did to get the system up and working as I expected it to look.

I’ve grouped them by area. In the main body of the document, they are in the approximate order of execution

Problems

Customising

Before you start using it

Missing download and setting the IBMUSER password

The files on the IBM Passport Advantage site are incomplete. The documentation tells you do download the ZDTDPY volume, edit it to set the password, and boot the system. This download was not on the download site.

I had an old z/OS system I could use and so could reset the password. See Help, I cannot logon to my z/OS system

It is not difficult to write a C program to prompt for a password on the z/OS console – and have the value not displayed. See How do I enter a password on the z/OS console for my program?

I needed to configure my laptop

The IP address of z/OS is 172.26.1.2. I configured my startup script to have

#  define route from my laptop to my server
sudo ip route add 10.1.1.0/24 via 10.1.0.3

# define route from my laptop to z/OS on the server
sudo ip route add 172.26.1.0/24 via 10.1.0.3

# connect to the server
ssh -X colin@10.1.0.3

The sample devmap is wrong, it does not provide 3270’s

The system would not IPL with a console, the output came out printer like.

I edited the devmap file:

  • add the 3270port 3270. Without this you do not get any 3270’s defined, and you get a line printer like console.
  • Change the processors to match what your server has. My dongle has support for 3 CPUs – but I can define 3-1 ZIIPs
  • Check the memory to match you configuration
  • I removed the IPL and put it in my shell script.

The top of my devmap is

[system]
processors 5 cp cp cp ziip ziip # number of processors
memory 10G
system_name VS01

3270port 3270 # port number for TN3270 connections

First IPL

The IPL parameters are configured to start up lots of subsystems I didn’t want to use I used

ipl DE27 parm DE28AU

Logon with userid IBMUSER and the password you configured.

Configure parmlib

The sys0.iplparm points to loadxx members. You need a load member with USER.PARMLIB in it (such as LOADAU)

  • Copy LOADAU to LOADCP
  • In LOADCP change SYSPARM to SYSPARM AU,CP
  • In user.parmlib create IEASYSCP (CP matching the CP above)
  • add your parameters, such as OMVS=(CP) for IP(V6) support

You can IPL with this

ipl DE27 parm DE28CP

If this fails to IPL, to back to parm DE28AU

Add userids

The userid IBMUSER is all powerful. I prefer using a less powerful userid.

I wanted to save my userids from the previous system. I wrote code makeRACF. With this you run a program on your old system, and specify a userid or dataset prefix. The program then generates the RACF commands to recreate the userid or resource.

Because the TSO configuration is different from the previous zD&T systems I had to configure the definitions

TSO (ACCTNUM ('ACCT001') - 
COMMAND ('ex ''colin.zlogon.clist''') -
PROC (PROC001 ) -
SIZE (2096128) -
MAXSIZE (2096128) -
USERDATA (0000) -
UNIT (3390))

I created some definitions to my userid COLIN access to resources on the new system

ALTUSER COLIN SPECIAL AUDITOR OPERATIONS                             
ALTUSER COLIN DFLTGRP(SYS1)
ALTUSER COLIN tso( ACCTNUM('ACCT001') -
CoMMAND('ISPF') PROC(PROC001 ) -
SIZE(2096128) MAXSIZE(2096128) USERDATA(0000) UNIT(SYSDA))
permit ACCT001 class(ACCTNUM) id(COLIN ) access(READ )
permit ACCT# class(ACCTNUM) id(COLIN ) access(READ )
permit JCL class(TSOAUTH)id(COLIN) access(REAd)
permit CONSOLE class(TSOAUTH)id(COLIN) access(REAd)
permit PROC001 class(TSOPROC)id(COLIN) access(REAd)
permit ISPFPROC class(TSOPROC)id(COLIN) access(REAd)
setropts raclist(TSOAUTH) refresh
setropts raclist(ACCTNUM) refresh
setropts raclist(TSOPROC) refresh
PERMIT *.** CLASS(JESSPOOL) ID(COLIN) ACCESS(ALTER)
SETR RACLIST(JESSPOOL) REFRESH

I created JCL for these definitions, so for system refreshes, I just rerun the jobs.

I did not use the UNIX facility to allocate a (random) UID. I specified the UID I had before.

On the ZFS with my files, I needed the uid of the file owner to be the same as my users uid. If z/OS allocated me a uid, I would not be able to access my files. I would then have to go through and change the owner of them.

I recreated userids COLIN and START1.

You need to see what groups the userids belonged to, and you may need to recreate the groups, or just us what are already defined.

Import user catalogs

I have user catalogs for all of my data sets. These catalogs need to be imported into the master catalog

//IBMUSERT JOB 1,MSGCLASS=H                                           
//S1 EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
IMPORT CONNECT -
OBJECTS -
(('A4USR1.ICFCAT' VOLUME(A4USR1) DEVICETYPE(3390) -
))
/*

How do you find out what user catalogs you have?

On the old system.

//IBMUSERT JOB 1,MSGCLASS=H                               
//S1 EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//DD1 DD DISP=SHR,VOL=SER=D5SYS1,UNIT=3390
//SYSIN DD *
LISTCAT CATALOG(CATALOG.Z31B.MASTER) USERCATALOG ALL FILE(DD1)
/*

or

//IBMUSERT JOB 1,MSGCLASS=H                               
//S1 EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
LISTCAT USERCATALOG ALL
/*

The ALL Parameter also lists the Aliases using the user catalog.

Define aliases to map high level qualifier to a user catalog.

Once you have imported the catalogs you can define the data set aliases

//IBMUSERT JOB 1,MSGCLASS=H                                     
//S1 EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DEFINE ALIAS (NAME(BACKUP) RELATE('A4USR1.ICFCAT') )
DEFINE ALIAS (NAME(COLIN ) RELATE('A4USR1.ICFCAT') )
/*

What aliases do I have?

//IBMUSERT JOB 1,MSGCLASS=H                                         
//S1 EXEC PGM=IDCAMS,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
LISTCAT ALIAS
/*

Define user directories

For each file system, and each user, they need a directory defined. The standard image uses automount to create a ZFS for each entry in /u. If my RACF profile says my home directory is /u/colin, it will create a ZFS for this. If /u/colin already existed, it will not be used.

I created entries in /usr. If you try to make a directory, it may fail because /usr is mounted read only.

From userid IBMUSER to into Unix ( TSO OMVS)

  • mkdir /usr/colin
  • If this fails use
    • chmount -w /usr … do your work … chmount -r /usr
  • mkdir /usr/tmp
  • mkdir /usr/tmp/zowet
  • mkdir /usr/tmp/zowet/colin Userid COLIN has HOME= /usr/tmp/zowet/colin
  • You may need to change the ownership of the directory
    • chown -R colin:sys1 mkdir /usr/tmp/zowet/colin
  • If you need to…
    • chmount -r /usr

Mount the ZFS

Once I had imported the catalogs, and defined the aliases I could try to mount my ZFS

I created USER.PARMLIB(BPXPRMUS) and added

MOUNT FILESYSTEM('COLIN.ZFS.ZOWE.TEMP') TYPE(ZFS) 
MOUNTPOINT('/usr/tmp/zowet') MODE(RDWR)
PARM('AGGRGROW') AUTOMOVE

MOUNT FILESYSTEM('COLIN.ZOPEN.ZFS') TYPE(ZFS)
MOUNTPOINT('/usr/zopen') MODE(RDWR)
PARM('AGGRGROW') AUTOMOVE

The activate using the operator command

T OMVS=(US)

I was then able to logon to my newly created userid COLIN, and go into z/OS Unix.

Configure VTAM to give you greater than 80 *24 screen size

VTAM configuration

  • Edit SYS1.VTAMLST(EXLOCAL). You have to edit this because NET does not have USER.VTAMLST configured.
  • Create EXLOCALO from it (for backup)
  • change DLOGMOD to have value D4B32XX3,
  • create an entry for CUADDR=061,

Clean up

  • Edit SYS1.VTAMLST(ATCCON00). Remove IVPLCLI,IVPLCLT because the devices they reference do not exist.

If your changes to EXLOCAL do not work, use

V NET,ACT,ID=EXLOCALO

TCPIP

The provided TCPIP procedure creates certificates etc and does other work. It creates a new CA certificate, I need to export it, and sent it to my machines which connect in, and to all my keyrings.

I want to use the set up I have, so my TCPIP V6 Procedure is

USER.PROCLIB(TCPIP)

//TCPIP    PROC PARMS='CTRACE(CTIEZB00)' 
//TCPIP EXEC PGM=EZBTCPIP,PARM='&PARMS',REGION=0M,TIME=1440
//SYSPRINT DD SYSOUT=*
//SYSERR DD SYSOUT=*
//SYSERROR DD SYSOUT=*
//ERRORFIL DD SYSOUT=*
//SYSDEBUG DD SYSOUT=*
//PROFILE DD DISP=SHR,DSN=USER.TCPPARMS(PROFILE)
//SYSTCPD DD DISP=SHR,DSN=TCPIP.TCPPARMS(TCPDATA)

Support TCPIP V6

The TCPIP as shipped does not support IP V6. You need to create a BPXPRMxx member and activate it

You need a BPXPRMv6 member in user.parmlib

FILESYSTYPE TYPE(CINET) 
ENTRYPOINT(BPXTCINT)
SUBFILESYSTYPE NAME(TCPIP)
TYPE(CINET)
ENTRYPOINT(EZBPFINI)
DEFAULT
NETWORK DOMAINNAME(AF_INET6)
DOMAINNUMBER(19)
MAXSOCKETS(50000)
TYPE(CINET)

In USER.PARMLIB(IEASYSXX) use BPX=(V6).

In USER.TCPPARMS(PROFILE) I have

...
DATASETPREFIX TCPIP

TCPCONFIG TTLS
INCLUDE USER.TCPPARMS(IPV6)

...

and the IPV6 member has

IPCONFIG6 MULTIPATH

TCPIP Resolver

See Why is the wrong TCPIP Resolver proc being used?

Create USER.PROCLIB(RESOLVER)

//* TCPIP RESOLVER - COLINS 
//*
//RESOLVER PROC PARMS=CTRACE(CTIRES00)
//*
//EZBREINI EXEC PGM=EZBREINI,REGION=0M,TIME=1440,
// PARM=('&PARMS',
// 'ENVAR("RESOLVER_TRACE=/var/log/resolver"/')
//SETUP DD DISP=SHR,DSN=COLIN.TCPPARMS(GBLRESOL),FREE=CLOSE
//SYSTCPT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//*

Create COLIN.TCPPARMS(GBLRESOL) with

Copy

  DEFAULTTCPIPDATA('COLIN.TCPPARMS(GBLTDATA)') 
GLOBALTCPIPDATA('COLIN.TCPPARMS(RESOLVE)')
# GLOBALTCPIPDATA(/etc/resolv.conf)
;
# -----------------------------------------------------------------
# Default zPDT Linux Base to z/OS Tunnel (Stand-Alone)
# -----------------------------------------------------------------
;
# GLOBALIPNODES(/etc/hosts)
GLOBALIPNODES('COLIN.TCPPARMS(HOSTS)')
....

Change the operator console PFKeys (to add the shutdown command)

See How do I change the PFKeys on the console?

Copy SYS1.PARMLIB(PFKTAB00) to USER.PARMLIB

  • Change PF12 to be PFK(12) CMD(“%NETV SHUTSYS”) CON(Y)
  • Change any other keys you fancy.

Fix SMF

Message HSF0066W

I was getting

HSF0066W Required exit IEFU86 for SMF subsystem SYS not enabled. Some data may be missing in SDSF event log.

Copy SYS1.PARMLIB(SMFPRM00) to USER.PARMLIB(SMFPRM00) add IEFU86

SYS(EXITS(IEFACTRT,IEFUJI,IEFU83,IEFU84,IEFU85,IEFUJV,IEFU86)), 
SUBSYS(STC,EXITS(IEFU83,IEFU84,IEFU85,IEFU29,IEFU86),
INTERVAL(SMF,SYNC))

Message IEE391A

IEE391A SMF ENTER DUMP FOR DATA SET ON VOLSER OPEVS1 DSN=SYS1.VS01.MAN1

Create in USER.PROCLIUB(SMFCLEAR)

//SMFCLEAR PROC MAN='SYS1.VS01.MAN1' 
//*
//* CLEAR SMF DATASET -
//* SMF MAN DATASET DUMPED REQUIRED MESSAGE RECIEVED
//* OR ISSUE SWITCH, I SMF, THEN THAT FILE WILL BE CLEARED
//*
//*
//DUMP1 EXEC PGM=IFASMFDP,REGION=1M
//INDD1 DD DSN=&MAN,DISP=SHR
//DUMPOUT DD DUMMY
//SYSPRINT DD SYSOUT=D
//SYSIN DD *
INDD(INDD1,OPTIONS(CLEAR))

Then you can use either of

S SMFCLEAR
S SMFCLEAR,MAN='SYS1.VS01.MAN2'

SETSMF command not enabled

I could not issue

setsmf recording(logstream)
setsmf recording(dataset)

setsmf recording(logstream)

commands, to be able to change the SMF LOGSTREAM.

I created USER.PARMLIB(SMFPRM00) from SYS1.PARMLIB and added AUTHSETSMF – it defaults to NONE.

...
DEFAULTLSNAME(IFASMF.VS01.DATA)
AUTHSETSMF
NOPROMPT,
REC(PERM),
,,,

Configure SYSLOGD

Define the started task

//IBMUSERT JOB 1,MSGCLASS=H 
//S1 EXEC PGM=IKJEFT01,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
RDEFINE STARTED SYSLOGD.* STDATA(USER(IBMUSER))
SETR RACLIST(STARTED) REFRESH

SYSLOGD is used by many Unix processes for recording errors and other information.

Create USER.PROCLIB(SYSLOGD)

//SYSLOGD PROC 
//* Licensed Materials - Property of IBM *
//* "Restricted Materials of IBM" *
//* 5650-ZOS *
//* Copyright IBM Corp. 1992, 2013 *
//* Read parms from /etc/syslog.conf
//CONFHFS EXEC PGM=SYSLOGD,REGION=4096K,TIME=NOLIMIT,
// PARM='ENVAR(''CEE_ENVFILE_S=DD:STDENV'')/-c -i '
//STDENV DD DISP=SHR,DSN=USER.PROCLIB(SYSLOGDD)
//SYSPRINT DD SYSOUT=*
//SYSIN DD DUMMY
//SYSERR DD SYSOUT=*
//SYSOUT DD SYSOUT=*
//CEEDUMP DD SYSOUT=*

Create USER.PROCLIB(SYSLOGDD)

I have

*.INETD*.*.*       /var/log/inetd.log 
auth.* /var/log/auth.log
mail.* /var/log//mail -F 640 -D 770
local1.err /var/log/local1.log
*.err /var/log/errors.log
# *.CPAGENT.*.* /var/log/CPAGENT.log
*.CPATTLS.*.* /var/log/CPATTLS
*.TTLS*.*.* /var/log/TTLS.log
*.Pagent.*.* /var/log/Pagent.log
*.TCPIP.*.debug /var/log/TCPIPdebug.log
*.TCPIP.*.warning /var/log/TCPIP.log
*.TCPIP.*.err /var/log/TCPIPerr.log
*.TCPIP.*.info /var/log/TCPIPinfo.log
*.SYSLOGD*.*.* /var/log/syslogd.log
*.TN3270*.*.* /var/log/tn3270.log
*.SSHD*.*.* /var/log/SSHD.log
*.FTPD*.*.* /var/log/FTPD.log
daemon.debug /var/log/SSHDdebug.log
*.TCPIP.*.none;
*.err /var/log/errors
*.CPAGENT.*.* /var/log/CPAGENT.log
*.TRMD1.*.info /var/log/TRMD1I.log
*.DMD.*.* /var/log/DMD.log

You can use this as a basis and change it as needed.

Configure SSHD

The SSHD procedure in SYS1.PROCLIB, invokes a shell script which then spawns the SSHD code with a name like SSHD.

I use

//SSHD    PROC 
//SSHD EXEC PGM=BPXBATCH,REGION=0M,TIME=NOLIMIT,
// PARM='PGM /usr/sbin/sshd -f /etc/ssh/sshd_config '
//* PARM='PGM /bin/sh -c /etc/ssh/sshd.sh'
//* STDIN AND STDOUT ARE BOTH DEFAULTED TO /dev/null
//STDERR DD PATH='/tmp/sshd.stderr',PATHOPTS=(OWRONLY,OCREAT,OAPPEND),
// PATHMODE=(SIRWXU)
//STDOUT DD PATH='/tmp/sshd.stdout',PATHOPTS=(OWRONLY,OCREAT,OAPPEND),
// PATHMODE=(SIRWXU)

Note that SSHD uses the /etc/ssh/sshd_config directory. You should back this up regulary. When IBM replaces the image this would be replace

After thought, I could always use -f /usr/colin/ssh/

Edit the configuration file and add either userids or groups.

# Allow specific user IDs 
AllowUsers IBMUSER COLIN
AllowGroups SYS1 IZUADMIN

If you add groups and not userids, you need to connect the userid to a group.

RACF changes

You can issue some racf commands on the z/OS console for example

<RVARY

To change this character (<) copy SYS1.PARMLIB(IEFSSN00) to USER.PARMLIB(IEFSSN01) and change the entry for RACF.

Define IXGLOGR as a started task to eliminate security messages

//IBMIXL  JOB 1,MSGCLASS=H 
//STEPNAME EXEC PGM=IKJEFT01
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
* IXGLOGR EXISTS AS A GROUP - IT REALLY SHOULD BE A USERID
ADDUSER IXGLUSER
CONNECT IXGLUSER GROUP(IXGLOGR)
RDEFINE STARTED IXGLOGR.* STDATA(USER(IXGLUSER) +
PRIVILEGED(YES) TRUSTED(YES) GROUP(IXGLOGR ))
SETROPTS RACLIST(STARTED) REFRESH
/*

Add missing groups

To protect datasets such as SYS1.*, the high level qualifier should be defined as a group. I have JCL ADDGROUP

//IBMKEY2 JOB 1,MSGCLASS=H 
//STEPNAME EXEC PGM=IKJEFT01
//SYSTSIN DD *
ADDGROUP SYS1
ADDGROUP ADCD
ADDGROUP AOK
ADDGROUP AOP
ADDGROUP AZD
ADDGROUP BBL
ADDGROUP CATALOG
ADDGROUP CBC
ADDGROUP CEE
ADDGROUP CFZ
ADDGROUP CNJ
ADDGROUP COUPLE
ADDGROUP CSD
ADDGROUP CSF
ADDGROUP CSQARC1
ADDGROUP CSQARC2
ADDGROUP EUVF
ADDGROUP FEU
ADDGROUP FEU1
ADDGROUP FFST
ADDGROUP GDDM
ADDGROUP GIM
ADDGROUP GLD
ADDGROUP GSK
ADDGROUP GTFNO
ADDGROUP GTFRACF
ADDGROUP HAP
ADDGROUP HLA
*DDGROUP IBMUSER
ADDGROUP ICQ
ADDGROUP IOE
ADDGROUP ISF
ADDGROUP ISP
ADDGROUP IXGLOGR
ADDGROUP IZU
ADDGROUP IZUSVR
ADDGROUP NETVIEW
ADDGROUP NFS
ADDGROUP SMPE
ADDGROUP STCJMON
ADDGROUP SYT1
ADDGROUP TCPIP
ADDGROUP USER
ADDGROUP ZFS
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=* g

Protect system data sets

You should define profiles for all datasets. I had a a member ADDSD.

//IBMKEY2 JOB 1,MSGCLASS=H 
//STEPNAME EXEC PGM=IKJEFT01
//SYSTSIN DD *
ADDSD 'SYS1.**' GENERIC UACC(READ) WARNING
PERMIT 'SYS1.**' ACCESS(ALTER) ID(SYS1)
ADDSD 'ADCD.**' GENERIC UACC(READ) WARNING
ADDSD 'AOK.**' GENERIC UACC(READ) WARNING
ADDSD 'AOP.**' GENERIC UACC(READ) WARNING
ADDSD 'AZD.**' GENERIC UACC(READ) WARNING
ADDSD 'BBL.**' GENERIC UACC(READ) WARNING
ADDSD 'CATALOG.**' GENERIC UACC(READ) WARNING
ADDSD 'CBC.**' GENERIC UACC(READ) WARNING
ADDSD 'CEE.**' GENERIC UACC(READ) WARNING
ADDSD 'CFZ.**' GENERIC UACC(READ) WARNING
ADDSD 'CNJ.**' GENERIC UACC(READ) WARNING
ADDSD 'COUPLE.**' GENERIC UACC(READ) WARNING
ADDSD 'CSD.**' GENERIC UACC(READ) WARNING
ADDSD 'CSF.**' GENERIC UACC(READ) WARNING
ADDSD 'CSQARC1.**' GENERIC UACC(READ) WARNING
ADDSD 'CSQARC2.**' GENERIC UACC(READ) WARNING
ADDSD 'EUVF.**' GENERIC UACC(READ) WARNING
ADDSD 'FEU.**' GENERIC UACC(READ) WARNING
ADDSD 'FEU1.**' GENERIC UACC(READ) WARNING
ADDSD 'FFST.**' GENERIC UACC(READ) WARNING
ADDSD 'GDDM.**' GENERIC UACC(READ) WARNING
ADDSD 'GIM.**' GENERIC UACC(READ) WARNING
ADDSD 'GLD.**' GENERIC UACC(READ) WARNING
ADDSD 'GSK.**' GENERIC UACC(READ) WARNING
ADDSD 'GTFNO.**' GENERIC UACC(READ) WARNING
ADDSD 'GTFRACF.**' GENERIC UACC(READ) WARNING
ADDSD 'HAP.**' GENERIC UACC(READ) WARNING
ADDSD 'HLA.**' GENERIC UACC(READ) WARNING
ADDSD 'IBMUSER.**' GENERIC UACC(READ) WARNING
ADDSD 'ICQ.**' GENERIC UACC(READ) WARNING
ADDSD 'IOE.**' GENERIC UACC(READ) WARNING
ADDSD 'ISF.**' GENERIC UACC(READ) WARNING
ADDSD 'ISP.**' GENERIC UACC(READ) WARNING
ADDSD 'IXGLOGR.**' GENERIC UACC(READ) WARNING
ADDSD 'IZU.**' GENERIC UACC(READ) WARNING
ADDSD 'IZUSVR.**' GENERIC UACC(READ) WARNING
ADDSD 'NETVIEW.**' GENERIC UACC(READ) WARNING
ADDSD 'NFS.**' GENERIC UACC(READ) WARNING
ADDSD 'SMPE.**' GENERIC UACC(READ) WARNING
ADDSD 'STCJMON.**' GENERIC UACC(READ) WARNING
ADDSD 'SYT1.**' GENERIC UACC(READ) WARNING
ADDSD 'TCPIP.**' GENERIC UACC(READ) WARNING
ADDSD 'USER.**' GENERIC UACC(READ) WARNING
ADDSD 'ZFS.**' GENERIC UACC(READ) WARNING
PERMIT 'ADCD.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'AOK.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'AOP.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'AZD.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'BBL.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CATALOG.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CBC.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CEE.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CFZ.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CNJ.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'COUPLE.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CSD.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CSF.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CSQARC1.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'CSQARC2.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'EUVF.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'FEU.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'FEU1.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'FFST.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GDDM.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GIM.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GLD.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GSK.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GTFNO.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'GTFRACF.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'HAP.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'HLA.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'IBMUSER.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'ICQ.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'IOE.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'ISF.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'ISP.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'IXGLOGR.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'IZU.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'IZUSVR.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'NETVIEW.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'NFS.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'SMPE.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'STCJMON.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'SYT1.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'TCPIP.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'USER.**' ACCESS(ALTER) ID(SYS1)
PERMIT 'ZFS.**' ACCESS(ALTER) ID(SYS1)
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*

You should have started tasks defined

Started tasks should be defined, so end users cannot just create a Started Task, and run it as an authorised task.

Define a default

//IBMKEY2 JOB 1,MSGCLASS=H 
//STEPNAME EXEC PGM=IKJEFT01
//SYSTSIN DD *
RDEFINE STARTED *.* OWNER(IBMUSER) +
DATA('GENERIC DEFINITION - COLIN') +
STDATA( USER(=MEMBER)
SETROPTS RACLIST(STARTED) REFRESH

Export certificates and keyrings

I have member EXPRING. this runs the LRING Rexx which creates a data set containing certificates used by the userid. They are stored in &USERID..CERTS.START1

//IBMKEYR JOB 1,MSGCLASS=H 
//STEPNAME EXEC PGM=IKJEFT01,PARM='LRING START1',REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSEXEC DD DISP=SHR,DSN=USER.Z31B.CLIST
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD DUMMY

Import certificates and keyrings

Use the Rexx program to export certificates from your old system, and import them into the new system.

Import

//IBMKEYR JOB 1,MSGCLASS=H
//STEPNAME EXEC PGM=IKJEFT01,PARM='IRING COLIN.CERTS.START1',
// REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSEXEC DD DISP=SHR,DSN=USER.Z31B.CLIST,UNIT=3390,VOL=SER=B3CFG1
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD DUMMY

RRS Error messages

At the start up of RRS I got

ATR132I RRS LOGSTREAM CONNECT HAS FAILED FOR
– OPTIONAL LOGSTREAM ATR.VS01.ARCHIVE.
– RC=00000008, RSN=0000080B

See here

Issue the operator command

SETRRS ARCHIVELOGGING,DISABLE 

ICSF

ICSF

I have my own (I)CSF data sets, containing my keys. My Started Task JCL is the same as the default, but with a different member

//CSF  PROC PRM=CP 
//CSF EXEC PGM=CSFINIT,PARM=&PRM,REGION=0M,TIME=1440,MEMLIMIT=NOLIMIT

You could use the provided JCL, then stop and restart CSF

P CSF
S CSF,PRM=CP

The PARM=CP points to a member CSFPRMCP in USER.PARMLIB. Mine has

CKDSN(COLIN.SCSFCKDS) 
PKDSN(COLIN.SCSFPKDS)
TKDSN(COLIN.SCSFTKDS) qq
DOMAIN(0)
SSM(YES)
KEYARCHMSG(YES)

If this member does not exist you get an abend

IEF764I CSF CSF IEFPARM CSFMIOPD HCR77F0 PARMLIB READ FAILED - MEMBER CSFPRMCP NOT FOUND.        
CSFO0016 ERROR OCCURRED OPENING OPTIONS FILE. MEMBER CSFPRMCP IN DDNAME IEFPARM RC=12 RS=1.
...
DUMP TITLE=COMPON=CSF...ABEND=S018F,REASON=0000001B

Logrec EREP

When LOGREC fills up, you get a retained message on the console.

You can print the contents of the EREP file using

//PRINTLOG JOB (ACCT),'PRINT LOGREC',CLASS=A,MSGCLASS=H           
//STEP EXEC PGM=IFCEREP1,PARM='CARD'
//SERLOG DD DISP=SHR,DSN=VSPROV.VS01.LOGREC
//DIRECTWK DD UNIT=SYSDA,SPACE=(CYL,10,,CONTIG)
//EREPPT DD SYSOUT=A,DCB=BLKSIZE=133
//TOURIST DD SYSOUT=A,DCB=BLKSIZE=133
//ZERLOG DD SYSOUT=A,DCB=BLKSIZE=133
//SYSIN DD *
PRINT=PS
ACC=N
ZERO=Y
ENDPARM
/*

and clear it using a procedure in USER.PROCLIB(CLLOGREC)

//CLLOGREC  PROC 
//STEP1 EXEC PGM=IFCDIP00
//SERERDS DD DISP=OLD,DSN=VSPROV.VS01.LOGREC,
// UNIT=3390,VOL=SER=OPEVS1

and the started task definition in STLOGREC

//IBMUSERT JOB 1,MSGCLASS=H 
//S1 EXEC PGM=IKJEFT01,REGION=0M
//SYSPRINT DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
RDEFINE STARTED CLLOGREC.* STDATA(USER(IBMUSER))
RDEFINE STARTED PRLOGREC.* STDATA(USER(IBMUSER))
SETR RACLIST(STARTED) REFRESH

JAVA message and SMFLIM

I was getting messages

JVMJ9VM015W Initialization error for library j9shr29(11): JVMJ9VM009E J9VMDllMain failed
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

See JVMJ9VM015W Initialization error for library j9shr29(11): JVMJ9VM009E J9VMDllMain failed

I created USER.PARMLIB(SMFLIM00) with

REGION JOBNAME(JCACHER) JOBMSG(ISSUE) MAXSHARE(80000) 

SMF logstream data sets are too small

Im getting message allocating data sets like IXGLOGR.IFASMF.VS01.DATA… every couple of minutes.

The log stream is define with

LOGSTREAM NAME(IFASMF.VS01.DATA) STRUCTNAME() LS_DATACLAS()
LS_MGMTCLAS() LS_STORCLAS() HLQ(IXGLOGR) MODEL(NO) LS_SIZE(500)
STG_MGMTCLAS() STG_STORCLAS() STG_DATACLAS() STG_SIZE(500)
LOWOFFLOAD(0) HIGHOFFLOAD(80) STG_DUPLEX(YES) DUPLEXMODE(UNCOND)
RMNAME() DESCRIPTION() RETPD(2) AUTODELETE(YES) OFFLOADRECALL(YES)
DASDONLY(YES) DIAG(NO) LOGGERDUPLEX() EHLQ(NO_EHLQ) GROUP()
MAXBUFSIZE(65532)

Where LS_SIZE(500) is 45 tracks.

I used JCL

//IBMLOG JOB 1,MSGCLASS=H                                   
//LOGDEF EXEC PGM=IXCMIAPU,REGION=4M
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DATA TYPE(LOGR) REPORT(YES)
UPDATE LOGSTREAM NAME(IFASMF.VS01.DATA)
LS_SIZE(15000)
/*

I could not run this, because the log stream was in use.

I had to create an USER.PARMLIB(SMFPRMNO) with

ACTIVE, 
DSNAME(SYS1.VS01.MAN1,
SYS1.VS01.MAN2),
RECORDING(DATASET)
DEFAULTLSNAME(IFASMF.VS01.DATA)
...

Then use

T SMF=NO

The run the command to update the logstream

and then switch back

T SMF=00

What’s next?

That’s as far as I’ve got. As I do more I’ll update this document.

Java persistent shared classes cache on z/OS

With Java shared classes cache, by default on z/OS saves the data in shared memory. You can use the snapshot command to save a copy on disk, and use the restore command after IPL to recreate it. For my zPDT system running z/OS on a Linux server this many seconds of start up time.

In more recent Java versions, the Shared Classes Cache has supported the persistent option, where shared virtual storage is mapped to a file – and so updating memory, updates the file.

I had a few problems getting this to work, and there was no documentation on the use of the persistent option.

When I enabled it, for example with

 -Xshareclasses:name=zoweGW,cacheDirPerm=0777,cacheDir=/u/tmp/zowec/,persistent 

I got

JVMJ9VM015W Initialization error for library j9shr29(11): JVMJ9VM009E J9VMDllMain failed

JVMSHRC245E Error mapping shared class cache file 
JVMSHRC336E Port layer error code = -155
JVMSHRC337E Platform error message: EDC5132I Not enough memory.
JVMSHRC840E Failed to start up the shared cache.
JVMJ9VM015W Initialization error for library j9shr29(11): JVMJ9VM009E J9VMDllMain failed
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

I had to change the SMFLIMxx parmlib member to fix this.

Display the current SMFLIM configuration

You can display your current SMFLIMxx configuration using

d smflim
d smflim,r

The d smflim,r gave me

...
Member and rule number SMFLIMCP 0003
User:
ZWESVUSR
Attributes:
EXECUTE: NOCHANGE
JOBMSG: ISSUE
MAXSHARE: 9000000
...

Which shows the rule for user ZWEVSUR came from the third rule in SMFLIMCP. It sets MAXSHARE, and other parameters.

Update the member

I updated my SMFLIMCP member to be

REGION USER(COLIN) JOBMSG(ISSUE) MAXSHARE(90000) 

activated it using t SMFLIM=(CP,C2) where CP2,C2 is my list of SMFLIM members. Note: The T SMFLIM command, replaces all of the definitions with what is in the list, so you need to specify the whole list, not just the changed member.

The definitions become active immediately, you do not need to logoff and logon, or resubmit a job.

When the Java job had started, it created a file C290M21F1A64P_hw_G43L00 in the specified directory.

When persistent was not specified, files were stored in the javasharedresources subdirectory.

Should I use this persistent option?

You have the choice of using the persistent option in the -Xshareclasses…persistent parameters, or not to specify it. If you do not use the persistent option you need to save the shared memory across IPLs, by using -Xshareclasses:…,snapshotCache and restoring it after an IPL using -Xshareclasses:…restoreFromSnapshot. I used this method, and added a steps to my started tasks, one to restore (if the cache exists already, it does nothing), and one at the end, to save it.

How does the performance compare?

On my zPDT system which is not meant to be used for performance evaluations, they both had similar durations, and used similar amounts of CPU, though non persistent was usually slight better.

Funny…

I also go message

JVMSHRC561E Failed to initialize the shared classes cache, there is not enough space in the file system. Available free disk space bytes = 516144128, requested bytes = 536870912.

Which was a surprise as I thought I had enough free disk space.

Saving a copy of the Java Shared classes to disk

On z/OS the Java shared classes use shared virtual storage. Data is added to the shared classes as the application process classes, so successive Java applications can use this shared data.

You can harden this to disk, so it is available across an IPL, by using the Java shared classes snapshotCache command, and run a restoreSnapshortCache after the IPL (or as part of your application start up).

What happens when you snapshot a cache?

You use a command like

/usr/lpp/java/J17.0_64/bin/java -Xshareclasses:cacheDir=/u/tmp/zowec,name=zoweGW,snapshotCache

This creates a file in the “cacheDir” like

 828 -rwxrwxrwx   1 ZWESVUSR ZWEADMIN 10485760 C290M17F1A64S_zoweGW_G43L00              

Where the file is owned by userid that created the shared cache, and its group. User ZWESVUSR, and group:ZWEADMIN. The release of Java is in the file names… C290M17.

If you do not have authority to create such as file the snapshot request will fail.

You might want to consider putting a snapshot job step into your Java applications JCL, so you always save the latest copy.

Why can’t Java find my class?

I had specified a classpath to load a class loading program, but my program could not be found.

I specified the Java options -XshowSettings.

The value of java.class.path had just one .jar, and did not include my classpath!

I found in some Oracle documentation

When you use -jar, the specified JAR file is the source of all user classes, and other class path settings are ignored. If you’re using JAR files, then see jar.

Simple – once you know…

How to fix it

I added my class to the Jar

/usr/lpp/javaJ21.0_64/bin/jar uf /u/tmp/zowep/components/gateway/bin/gateway-service.jar -C /u/tmp/java CCLoader.class

My class was found – and it worked!

How to take (and process) a RACF GTF trace with Java

When trying to resolve a certificate problem in a Java program, see here, I tried unsuccessfully to take a RACF trace to see what calls were being issued, and what reason codes were being returned.

The RACF GTF had no entries for the Java program!

Start RACF trace

My started task was called OZUSRV4. I had to specify a jobname to RACF trace of OZUSRV4* because Java spawns address spaces, and it was a spawned address space that did all of the Java work. If your started task is 8 characters long – just specify the 8 character name.

The trace command was the RACF SET TRACE command, where # is my RACF subsystem recognition character.

#SET TRACE(CALLABLE(TYPE(41))JOBNAME(OZUSVR4*))

Where type(41) is for IRRSDL00 which performs the R_datalib, keyring processing.

Start GTF

S GTF.GTF
R 1,trace=usrp
R 2,USR=(F44) 
R 3,END
R 4,U 

Run the test

I ran my started task, and stopped the RACF trace

#SET TRACE(CALLABLE(NONE))JOBNAME(OZUSVR4*)) 
#set list

The output of the #set list command included

TRACE OPTIONS                   - NOIMAGE                                    
                                - NOAPPC                                     
                                - NOSYSTEMSSL                                
                                - NORRSF                                     
                                - NORACROUTE                                 
                                - NOCALLABLE                                 
                                - NOPDCALLABLE                               
                                - NODATABASE                                 
                                - NOGENERICANCHOR                            
                                - NOASID                                     
                                - JOBNAME                                    
                                   OZUSVR4*                                  
                                - NOCLASS                                    
                                - NOUSERID                                   
SUBSYSTEM USERID                - START1                                     

So the traces are off…. but it still has a reference to OZUSVR4 – strange.

Process the GTF file.

I used IPCS to look at the GTF file

  • =0 and specify the GTF file name
  • =6 dropd to drop any saved status from last time that dataset was used
  • gtf usr(all) It displays the output in an editor like window.
  • report view displays it in ISPF editor, view mod.
  • You can the do things like
    • x all
    • f ‘RACF Reason code’ all

To display the records with non zero return codes.

The output is very chatty – and it was hard to find the data I wanted from data with a hex dump of the string “OFFSET” etc. For example

Trace Identifier:             00000036                           
Record Eyecatcher:            RTRACE                             
Trace Type:                   OMVSPRE                            
Ending Sequence:              ........                           
Calling address:              00000000  79403A2D                 
Requestor/Subsystem:          ........  ........                 
Primary jobname:              OZUSVR44                           
Primary asid:                 00000035                           
Primary ACEEP:                00000000  008FC8A0                 
Home jobname:                 OZUSVR44                           
Home asid:                    00000035                           
Home ACEEP:                   00000000  008FC8A0                 
Task address:                 00000000  008CF298                 
Task ACEEP:                   00000000  00000000                 
Time:                         DDD4C11D  776E2A40                 
Error class:                  ........                           
Service number:               00000029                           
RACF Return code:             00000000                           
RACF Reason code:             00000000                           
Return area address:          00000000  00000000                 
Parameter count:              0000002B    
...                       
Area length:                  00000008                                                                                
                                                                                                                      
Area value:                                                                                                  
D6C6C6E2  C5E30050                               | OFFSET.&                         |  
                                                                                                                      
Area length:                  00000007                                                                                
                                                                                                                      
Area value:                                                                                                           
06E2E3C1  D9E3F1                                 | .START1                          |  

I wrote a REXX exec which post processes the output and removes what I think is irrelevant data.

An example of what I think is useful is below. Non zero return codes have ! in column 1

! Return code: 00000008 8 
! Reason code: 00000004 4  4 Parameter list error occurred. 
-  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
! Return code: 00000008 8 
! Reason code: 0000002C 44 44 No certificate found with the specified status 
-  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
Area value: 
00000050  10AFC67C  ...
...
  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
Area value:          | .START1                          | 
06E2E3C1  D9E3F1                                                
Area value:          | .MQRING                          | 
06D4D8D9  C9D5C7                                                

You can download the rexx exec from

You need to upload it to a CLIST available to ISPF.

Solving certificate problems in Java on z/OS

I spent many any hour trying to understand why z/OSMF was getting a message saying certificate not found in keyring, when it was always there when I checked it.

I tried Java trace options but they did not help. I have my own Java program, and that gave me a message from IRRSDL00 (the callable service to access keyrings). But when I did a RACF GTF trace to get see what was going on I got no entries in the trace. Weird. Once I solved the problems, the solution was obvious.

My Java program reported

java.io.IOException: The private key of NEWTECCTEST is not available or no authority to access the private key

z/OSMF report

[ERROR ] CWPKI0024E: The NISTECCTEST certificate alias specified by the attribute serverKeyAlias is either not found in KeyStore safkeyring://START1/MQRING or it is invalid.

The problem and the solution

The message The private key … is not available or no authority to access the private key. Has a hint as to the problem. The documentation is hidden away. It was not as bad as

It was on display in the bottom of a locked filing cabinet stuck in a disused lavatory with a sign on the door saying ‘Beware of the Leopard.”

but it is not easy to find. It says

Applications can call the R_datalib callable service (IRRSDL00) to extract the private keys from certain certificates after they have access to the key ring. A private key is returned only when the following conditions are met:

  1. For RACF real key rings:
    • User certificates An application can extract the private key from a user certificate if the following conditions are met:
      • The certificate is connected to the key ring with the PERSONAL usage option.
      • One of the following two conditions is true:
        • The caller’s user ID is the user ID associated with the certificate if the access to the key ring is through the checking on IRR.DIGTCERT.LISTRING in the FACILITY CLASS, or
        • The caller’s user ID has READ or UPDATE authority to the <ringOwner>.<ringName>.LST resource in the RDATALIB class. READ access enables retrieving one’s own private key, UPDATE access enables retrieving other’s.

I had a keyring START1.MQRING and the start task userid had read access to it. Within the keyring was the certificate NISTECCTEST owner by userid START1. The started task userid needs UPDATE access to the keyring to be able to access the private key belonging to a different userid.

Reasons for “not found” reason code

Under the covers the callable server IRRSDL00 is called. The reason code are documented here. You might get SAF return code 8, RACF return code 8, RACF reason code 44.

  • The certificate was not in the keyring
  • It was NOTRUST
  • It had expired
  • The CA for the certificate was not in the keyring,
  • The userid did not have update access to the keyring when there are private certificates from other userids.

What options can I specify for Java on z/OS?

You can use the following command to list them all.

java -X -help 

On Java 8 SR 8 this gave me

The following options are non-standard and subject to change without notice. 
                                                                                                       
  -Xbootclasspath:<path>    set bootstrap classpath to <path> 
  -Xbootclasspath/p:<path>  prepend <path> to bootstrap classpath 
  -Xbootclasspath/a:<path>  append <path> to bootstrap classpath 
                                                                                                       
  -Xrun<library>[:options]  load native agent library 
                            (deprecated in favor of -agentlib) 
                                                                                                       
  -Xshareclasses[:options]  Enable class data sharing (use help for details) 
                                                                                                       
  -Xint           run interpreted only (equivalent to -Xnojit -Xnoaot) 
  -Xnojit         disable the JIT 
  -Xnoaot         do not run precompiled code 
  -Xquickstart    improve startup time by delaying optimizations 
  -Xfuture        enable strictest checks, anticipating future default
  -verbose[:(class|gcterse|gc|dynload|sizes|stack|debug)] 
                                                                                                       
  -Xtrace[:option,...]  control tracing use -Xtrace:help for more details 
                                                                                                       
  -Xcheck[:option[:...]]  control checking use -Xcheck:help for more details 
                                                                                                       
  -Xhealthcenter  enable the Health Center agent 
                                                                                                       
  -Xdiagnosticscollector enable the Diagnotics Collector 
                                                                                                       
  -XshowSettings                show all settings and continue 
  -XshowSettings:system 
                      (Linux Only) show host system or container 
                      configuration and continue 
  -XshowSettings:all            show all settings and continue 
  -XshowSettings:vm             show all vm related settings and continue 
  -XshowSettings:properties     show all property settings and continue 
  -XshowSettings:locale         show all locale related settings and continue 
                                                                                                         
Arguments to the following options are expressed in bytes. 
Values suffixed with "k" (kilo) or "m" (mega) will be factored accordingly. 
                                                                                                         
  -Xmca<x>        set RAM class segment increment to <x> 
  -Xmco<x>        set ROM class segment increment to <x> 
  -Xmn<x>         set initial/maximum new space size to <x> 
  -Xmns<x>        set initial new space size to <x> 
  -Xmnx<x>        set maximum new space size to <x> 
  -Xmo<x>         set initial/maximum old space size to <x> 
  -Xmos<x>        set initial old space size to <x> 
  -Xmox<x>        set maximum old space size to <x> 
  -Xmoi<x>        set old space increment to <x> 
  -Xms<x>         set initial memory size to <x> 
  -Xmx<x>         set memory maximum to <x> 
  -Xmr<x>         set remembered set size to <x> 
  -Xmrx<x>        set maximum size of remembered set to <x> 
  -Xmso<x>        set OS thread stack size to <x> 
  -Xiss<x>        set initial java thread stack size to <x> 
  -Xssi<x>        set java thread stack increment to <x> 
  -Xss<x>         set maximum java thread stack size to <x> 
  -Xscmx<x>       set size (or soft max size if option -XX:SharedCacheHardLimit= is 
                  present) of new shared class cache to <x> 
                                                                                                        
   -Xscminaot<x>   set minimum shared classes cache space reserved for AOT data to <x> 
   -Xscmaxaot<x>   set maximum shared classes cache space allowed for AOT data to <x> 
   -Xmine<x>       set minimum size for heap expansion to <x> 
   -Xmaxe<x>       set maximum size for heap expansion to <x> 
                                                                                                        
 Arguments to the following options are expressed as a decimal from 0 to 1. 
 A value of 0.3 represents a request of 30% 
                                                                                                        
   -Xminf<x>       minimum percentage of heap free after GC 
   -Xmaxf<x>       maximum percentage of heap free after GC

 Arguments to the following options are expressed a decimal numbers. 
                                                                                                                
   -Xgcthreads<x>                set number of GC threads 
   -Xnoclassgc                   disable dynamic class unloading 
   -Xclassgc                     enable dynamic class unloading 
   -Xalwaysclassgc               enable dynamic class unloading on every GC 
   -Xnocompactexplicitgc         disable compaction on a system GC 
   -Xcompactexplicitgc           enable compaction on every system GC 
   -Xcompactgc                   enable compaction 
   -Xnocompactgc                 disable compaction 
   -Xlp                          enable large page support 
   -Xrunjdwp:<options>           enable debug, JDWP standard options 
   -Xjni:<options>               set JNI options 
                                                                                                                  

I noticed that some products using Java have the nice option

-Xoptionsfile=/var/xxxf/configuration/colin_override.cfg

Where the file has a list of JVM options one on each line.

This option is not generally available.

Using enclaves in a Java program – capturing elapsed and CPU time used by a Java transaction.

Ive blogged about using enclaves from a C program.  There is an interface from Java which uses this C interface.

Is is relatively easy to use enclave services from a java program, as there are java classes for most of the functions, available from JZOS toolkit.  For example the WorkloadManager class is defined here.

Below is a program I used to get the Work Load Manager(WLM) services working.

import java.util.concurrent.TimeUnit;
import com.ibm.jzos.wlm.ServerClassification;
import com.ibm.jzos.wlm.WorkUnit;
import com.ibm.jzos.wlm.WorkloadManager;
public class main
{
// run it with /usr/lpp/java/J8.0_64/bin/java main
public static void main(String[] args) throws Exception
{
WorkloadManager wlmToken = new WorkloadManager("JES", "SM3");
ServerClassification serverC = wlmToken.createServerClassification();
serverC.setTransactionName("TCI3");
for ( int j = 0;j<1000;j++)
{
WorkUnit wU = new WorkUnit(serverC, "MAINCP");
wU.join();
float f;
for (int i = 0;i<1000000;i++)
{
f=ii2;
TimeUnit.MICROSECONDS.sleep(20*1000); // 200 milliseconds
}
wU.leave();
wU.delete(); // end the workload
}
wlmToken.disconnect();
}
}

The WLM statements are explained below.

WorkloadManager wlmToken = new WorkloadManager(“JES”, “SM3”);

This connects to the Work Load Manager and returns a connection token.    This needs to be done once per JVM.  You can use any relevant subsystem type, I used JES, and a SubsystemInstance (SI) of SM3. As a test, I created a new  subsystem category in WLM called DOG, and used that.  I defined ServerInstance SI with a value of SM3 within DOG and it worked.

z/OS uses uses subsystems such as JES for jobs submitted into JES2, and STC for Started task.

ServerClassification serverC = m.createServerClassification();

If your application is going to classify the transaction to determine the WLM service class and reporting  class you need this.  You create it, then add the classification criteria to it, see the following section.

Internally this passes the connection token wlmToken to the createServerClassification function.

serverC.setTransactionName(“TCI3”);

This passes information to WLM to determine the best service class and reporting class.  Within Subsystem CAT, Subsystem Instance SM1, I had a sub rule TransactionName (TN) with a value TCI3.  I defined the service class and a reporting class.

WorkUnit wU = new WorkUnit(serverC, “MAINCP”);

This creates the Independent (business transaction) enclave.  I have not see the value MAINCP reported in any reports.   This invokes the C run time function CreateWorkUnit(). The CreateWorkUnit function requires a STCK value of when the work unit started.  The Java code does this for you and passes the STCK through.

wU.join();

This connect the current task to the enclave, and any CPU it uses will be recorded against the enclave. 

wU.leave();

Disconnect the current task from the enclave.  After this call any CPU used by the thread will be recorded against the address space.

wU.delete();

The Independent enclave(Business transaction) has finished. WLM records the elapsed time and resources used for the business transaction.

m.disconnect();

The program disconnects from WLM.

Reporting class output.

I used RMF to print the SMF 72 records for this program.   The Reporting class for this program had

-TRANSACTIONS--  TRANS-TIME HHH.MM.SS.FFFFFF 
AVG        0.29  ACTUAL                36320 
MPL        0.29  EXECUTION             35291 
ENDED       998  QUEUED                 1028 
END/S      8.31  R/S AFFIN                 0 
#SWAPS        0  INELIGIBLE                0 
EXCTD         0  CONVERSION                0 
                 STD DEV               18368 
                                             
----SERVICE----   SERVICE TIME  ---APPL %--- 
IOC           0   CPU   12.543  CP      0.01 
CPU       10747   SRB    0.000  IIPCP   0.01 
MSO           0   RCT    0.000  IIP    10.44 
SRB           0   IIT    0.000  AAPCP   0.00 
TOT       10747   HST    0.000  AAP      N/A 

From this we can see that for the interval

  1. 998 transactions ended.  (Another report interval had 2 transactions ending)
  2. the response time was an average of 36.3 milliseconds
  3. a total of 12.543 seconds of CPU was used.
  4. it spent 10.44 % of the time on a ZIIP.
  5. 0.01 % of the time it was executing ZIIP eligible work on a CP as there was no available ZIIP.

Additional functions.

The functions below

  • ContinueWorkUnit – for dependent enclave
  • JoinWorkUnit – as before
  • LeaveWorkUnit – as before
  • DeleteWorkUnit – as before

can be used to record CPU against the dependent (Address space) enclave.  There is no WLM classify for a dependent enclave.

Java threads and WLM

A common application pattern is to use connection pooling.  For example the connect/disconnect to a database or MQ is expensive.  If you have a pool of threads, which connect, and start connected, an application can request a thread and get a thread which has already been connected to the resource manager.

It should be a simple matter of changing the interface from

connectionPool.getConnection()

to

connectionPool.getConnection(WorkUnit wU)
{ connection = connectionPool.getConnection()
 connection.join(wU)
}

and add a connection.leave(wU) to the releaseConnection.

Magic methods to decode Java MQ constants to strings.

I had been struggling with MQ and java, and decoding what the return codes numbers were, and found some well gem methods here.

String reasonCode = MQConstants.lookup(2035, “MQRC_.*”);  gave MQRC_NOT_AUTHORIZED

and

String decode  = MQConstants.decodeOptions(gmo.options,”MQGMO_.*”);  gave me

MQGMO_WAIT | MQGMO_SYNCPOINT_IF_PERSISTENT | MQGMO_FAIL_IF_QUIESCING

I wish I had these a couple of years ago – it would have saved me a lot of time!

 

The methods are

static java.lang.String decodeOptions(int optionsP,
java.lang.String optionPattern)

This helper method takes an integer representing a set of IBM MQ options for an MQI structure, and converts them into a string displaying the constants that the options represent.
static int getIntValue(java.lang.String name)

Returns the value of the named MQSeries constant as an int.
static java.lang.Object getValue(java.lang.String name)

Returns the value of the named MQSeries constant.
static java.lang.String lookup(int value,
java.lang.String filter)

Returns the MQSeries constant name or names for the supplied int value.
static java.lang.String lookup(java.lang.Object value,
java.lang.String filter)

Returns the MQSeries constant name or names for the supplied value of type Integer, String, byte[], or char[].
static java.lang.String lookupCompCode(int reason)

Convenience method for finding the constant name for a completion code.
static java.lang.String lookupReasonCode(int reason)

Convenience method for finding the constant name for a reason code.
static void main(java.lang.String[] args)

MDBs activation specs and @things in the java program

While struggling with getting MDBs working, and looking at examples, I saw examples where they defined JMS resources within the java program using @….  statements, and could not see how they worked.  These are called annotations. The documentation on the web assumes you know about annotations  when explaining annotations!  They, in fact, are pretty simple, let me explain.

Annotations start with an @ character, and the information can be stored within the .class file as meta-data.  Programs can extract and use this meta data.

You can have java code like
@Resource(lookup="java:customerMQ")
private javax.jms... myMQ;

A program, for example,  your program, an analysis program or a web server, can issue request like

  • load class information
  • from the meta data list all fields with @resource defined.
  • do things with the list

One example would be to specify a JNDI lookup of java:customerMQ and return it into the field myMQ.

Another example from the IBM documentation

@MessageDriven(
  name = "JMSSampleMDB",
  activationConfig = 
  {
    @ActivationConfigProperty(
       propertyName  = "destinationType", 
       propertyValue = "javax.jms.Queue"),
 
    @ActivationConfigProperty(
       propertyName  = "destination", 
	propertyValue = "jndi_INPUT_Q")                         
   }
)

The resource adapter has code which does

  • load your MDB program
  • get the MessageDriven stuff.
    • within this, locate the activationConfig records
      • within these, locate the ActivationConfigProperty propertyName and propertyValue, and merge the data with the data in the ejb-jar.xml file.

 

With the definitions in your java program, and the definitions in the MDB configuration you can configure a complete set of options for MDB.  I think the definitions in the java program override the MDB configuration.

How do I see what data there is?

You can extract this meta-data using a method like (see here)

public void getAnnotations(Class inclass){
    for(Field field : inclass.getDeclaredFields()){
        Class type = field.getType();
        String name = field.getName();
        field.getDeclaredAnnotations(); //do something with these
    }

Use the javap command to display the data.

To display the annotations you can usethe command, where ….class is the name of your class file.

javap -v .....class

My java program had

import javax.annotation.Resource;
.....
@Resource(lookup = "java:app/jms/myappTopic")
String colin = "ZZZZZ";

The javap command gave

java.lang.String colin;
  descriptor: Ljava/lang/String;
  flags:
  RuntimeVisibleAnnotations:
  0: #14(#15=s#16)
...
#14 = Utf8 Ljavax/annotation/Resource;
#15 = Utf8 lookup
#16 = Utf8 java:app/jms/myappTopic

from which we get

java.lang.String colin ... 
  javax/annotation/Resource (lookup = java:app/jms/myappTopic).

which matches the source code.

Different annotation types are confusing.

As well as providing meta-information on variables and classes, java also uses annotations to modify the java compiler behaviour.   For example

  • By putting @Deprecated infront of a method, the method can be flagged when used, as deprecated, and you should not use it
  • @SuppressWarnings(“unchecked”) tells the java compiler NOT to produce an error message for the unchecked condition.  See here for a list of warning conditions.