?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Device Management' ??
MODULE dmm$logger;
?? RIGHT := 110 ??

{
{  PURPOSE:
{
{    This module contains the code which is responsible for accumulating
{    and processing transactions against the volume resident tables
{    maintained by device management.
{
{  DESIGN:
{
{    The transactions against the volume files are accumulated in a
{    device log for the volume and then periodically processed.
{
?? NEWTITLE := 'Global Declarations Referenced By This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc oss$mainframe_paged_literal
*copyc jmc$special_dispatch_priorities
*copyc cyd$cybil_structure_definitions
*copyc osd$cybil_structure_definitions
*copyc mme$condition_codes
*copyc cmt$request_block
*copyc dmt$active_volume_table_index
*copyc dmt$allocation_log
*copyc dmt$assigned_ms_vol_attributes
*copyc dmt$avt_search_key
*copyc dmt$dat_change
*copyc dmt$device_log_entries
*copyc dmt$device_position
*copyc dmt$dfl_change
*copyc dmt$error_condition_codes
*copyc dmt$log_flaw_init_data
*copyc dmt$mainframe_assigned
*copyc dmt$mat_change_request
*copyc dmt$ms_device_allocation_table
*copyc dmt$ms_login_table
*copyc ost$wait
*copyc rmt$recorded_vsn
*copyc sft$file_space_limit_kind
*copyc syt$system_core_condition
?? POP ??
*copyc gff$old_file_hash
*copyc cmp$change_state_info_table
*copyc cmp$pc_get_logical_unit
*copyc dmp$allocate_file_space_r1
*copyc dmp$close_file
*copyc dmp$complete_sft_delete
*copyc dmp$dat_purge_file
*copyc dmp$generate_gfn_hash
*copyc dmp$get_avt_logging_info
*copyc dmp$get_disk_file_descriptor_p
*copyc dmp$get_fau_entry
*copyc dmp$get_fmd_by_index
*copyc dmp$get_mat_pointer
*copyc dmp$locate_volume_label
*copyc dmp$lock_avt_entry
*copyc dmp$open_dat
*copyc dmp$open_dflt
*copyc dmp$open_file
*copyc dmp$open_login_table
*copyc dmp$search_avt_by_rvsn
*copyc dmp$set_eoi
*copyc dmp$unlock_avt_entry
*copyc dpp$put_critical_message
*copyc gfp$get_fde_p
*copyc gfp$get_locked_fde_p
*copyc gfp$unlock_fde_p
*copyc mmp$free_pages
*copyc mmp$open_file_by_sfid
*copyc mmp$write_modified_pages
*copyc osp$append_status_parameter
*copyc osp$begin_system_activity
*copyc osp$clear_mainframe_sig_lock
*copyc osp$end_system_activity
*copyc osp$fatal_system_error
*copyc osp$fetch_locked_variable
*copyc osp$file_access_condition
*copyc osp$increment_locked_variable
*copyc osp$set_locked_variable
*copyc osp$set_mainframe_sig_lock
*copyc osp$set_status_abnormal
*copyc osp$test_set_main_sig_lock
*copyc pmp$delay
*copyc syp$continue_to_cause
*copyc syp$disestablish_cond_handler
*copyc syp$establish_condition_handler
*copyc tmp$ready_system_task1
*copyc tmp$set_task_priority
*copyc cmv$logical_pp_table_p
*copyc cmv$post_deadstart
*copyc dmv$active_volume_table
*copyc dmv$allocation_log
*copyc dmv$debug_options
*copyc dmv$idle_system
*copyc dmv$internal_task_exec_counts
*copyc dmv$internal_tasks_initiated
*copyc dmv$mat_change_count_max
*copyc dmv$mat_change_list
*copyc dmv$recycle_device_log
*copyc dmv$recycled_log
*copyc gfv$null_sfid
*copyc osv$mainframe_pageable_heap
*copyc osv$mainframe_wired_heap
*copyc osv$recover_at_all_costs
*copyc i#move
*copyc i#call_monitor
?? TITLE := '  Global Variables', EJECT ??

  VAR
    dmv$test_recovery: [STATIC, XDCL] boolean := FALSE,

    dmv$flush_dev_log_pages_count: [STATIC, XDCL, oss$mainframe_pageable] integer := 0,

    device_log_check_byte: [STATIC, READ, oss$mainframe_paged_literal] 0 .. 0ff(16) := 0a5(16),

    log_entry_data_size: [STATIC, READ, oss$mainframe_paged_literal] array [dmt$dl_entry_kind] of
          0 .. 0ff(16) :=
{dmc$invalid_dl_entry           } [0,
{dmc$dl_allocate                } #SIZE (dmt$dl_allocate_block),
{dmc$dl_first_sft_delete        } #SIZE (dmt$dl_sft_delete_block),
{dmc$dl_second_sft_delete       } #SIZE (dmt$dl_sft_delete_block),
{dmc$dl_third_sft_delete        } #SIZE (dmt$dl_sft_delete_block),
{dmc$dl_create                  } #SIZE (dmt$dl_create_block),
{dmc$dl_return_dau              } #SIZE (dmt$dl_return_dau_block),
{dmc$dl_disk_tables_updated     } 0,
{dmc$dl_attach_file             } #SIZE (dmt$dl_attach_file_block),
{dmc$dl_detach_file             } #SIZE (dmt$dl_attach_file_block),
{dmc$dl_initialize              } #SIZE (dmt$dl_initialize_block),
{dmc$dl_last_update_entry       } 0,
{dmc$dl_purge_file              } #SIZE (dmt$dl_purge_file_block),
{dmc$dl_second_purge_file       } #SIZE (dmt$dl_purge_file_block),
{dmc$dl_release_dau             } #SIZE (dmt$dl_release_dau_block),
{dmc$dl_release_dfl             } #SIZE (dmt$dl_release_dfl_block),
{dmc$dl_return_dfl              } #SIZE (dmt$dl_return_dfl_block),
{dmc$dl_software_flawed         } #SIZE (dmt$dl_software_flaw_block),
{dmc$dl_start_update            } 0,
{dmc$dl_update_disk_tables      } 0,
{dmc$dl_update_file_length      } #SIZE (dmt$dl_file_length_block),
{dmc$dl_update_fmd_length       } #SIZE (dmt$dl_fmd_length_block),
{dmc$dl_file_damaged            } #SIZE (dmt$dl_file_damaged_block),
{dmc$dl_reallocate              } #SIZE (dmt$dl_reallocate_block),
{dmc$dl_trim_file               } #SIZE (dmt$dl_trim_file_block),
{dmc$dl_deallocate_file_fragment} #SIZE (dmt$dl_deallocate_fragment_blk),
{dmc$dl_continue_purge          } #SIZE (dmt$dl_release_dau_block),
{dmc$dl_sa_on_dl_entry          } 0,
{dmc$dl_sa_after_process_dl     } 0,
{dmc$dl_sa_bef_next_dfl_change  } 0,
{dmc$dl_sa_aft_next_dfl_change  } 0,
{dmc$dl_sa_bef_next_dat_change  } 0,
{dmc$dl_sa_aft_next_dat_change  } 0,
{dmc$dl_sa_bef_logging_dtu      } 0,
{dmc$dl_sa_bef_mf_table_update  } 0,
{dmc$dl_sa_aft_mf_table_update  } 0,
{dmc$dl_ra_on_dl_entry          } 0,
{dmc$dl_ra_after_process_dl     } 0,
{dmc$dl_ra_bef_next_dfl_change  } 0,
{dmc$dl_ra_aft_next_dfl_change  } 0,
{dmc$dl_ra_bef_next_dat_change  } 0,
{dmc$dl_ra_aft_next_dat_change  } 0,
{dmc$dl_ra_bef_logging_dtu      } 0,
{dmc$dl_recycle_dau             } #SIZE (dmt$dl_return_dau_block)];

?? EJECT ??

  VAR
    dmv$continue_purge_limit: [STATIC, XDCL, oss$mainframe_pageable] integer := 1500;

  VAR
    dmv$min_sorted_entries: [STATIC, XDCL, oss$mainframe_pageable] integer := 0ffffffffffff(16),
    dmv$max_sorted_entries: [STATIC, XDCL, oss$mainframe_pageable] integer := 0,
    dmv$running_total_entries: [STATIC, XDCL, oss$mainframe_pageable] integer := 0,
    dmv$running_total_sorts: [STATIC, XDCL, oss$mainframe_pageable] integer := 0,

    dmv$last_volume_downed_status: [STATIC, XDCL, oss$mainframe_pageable] ost$status := [TRUE],

    dmv$minimum_log_count: [STATIC, XDCL, oss$mainframe_pageable] integer := 2,

    dmv$skipped_evacuate,
    dmv$skipped_update: [STATIC, XDCL, oss$mainframe_pageable] integer := 0,
    dmv$running_total_iterations: [STATIC, XDCL, oss$mainframe_pageable] integer := 0,
    dmv$running_total_exchanges: [STATIC, XDCL, oss$mainframe_pageable] integer := 0;

  VAR
    dmv$dat_change_errors: [STATIC, XDCL, oss$mainframe_pageable] dmt$dat_change_errors := [0, * ],
    dmv$dfl_change_errors: [STATIC, XDCL, oss$mainframe_pageable] dmt$dfl_change_errors := [0, * ];

?? TITLE := '  dmp$change_dfl_damage', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$change_dfl_damage
    (    avt_index: dmt$active_volume_table_index;
         add_damage: dmt$file_damage;
         remove_damage: dmt$file_damage;
         dfl_index: dmt$device_file_list_index;
         flush_device_log: boolean;
         global_file_name: dmt$global_file_name;
     VAR status: ost$status);

    VAR
      avt_entry_found: boolean,
      device_log: dmt$device_log,
      log_entry: dmt$dl_entry,
      flush_status: ost$status,
      info: dmt$avt_logging_info;

    log_entry.kind := dmc$dl_file_damaged;
    log_entry.file_damaged_block.global_file_name := global_file_name;
    log_entry.file_damaged_block.dfl_index := dfl_index;
    log_entry.file_damaged_block.add_damage := add_damage;
    log_entry.file_damaged_block.remove_damage := remove_damage;

    dmp$process_device_log_entry (avt_index, log_entry, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF flush_device_log THEN
      dmp$get_avt_logging_info (avt_index, info, avt_entry_found);
      IF NOT avt_entry_found THEN
        osp$set_status_abnormal (dmc$device_manager_ident, dme$avt_entry_not_found,
              'unable to locate avt entry - dmp$change_dfl_damge', status);
        RETURN; {----->
      IFEND;

      IF info.device_log_sfid = gfv$null_sfid THEN
        osp$set_status_abnormal (dmc$device_manager_ident, dme$logging_unavailable, 'dmp$change_dfl_damge',
              status);
        RETURN; {----->
      IFEND;

      open_device_log (info.device_log_sfid, TRUE, device_log, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

{ Volume_down (status) will be returned if the volume is down and will be treated
{ as an exception condition by the higher level callers of the following
{ procedure.

      mmp$write_modified_pages (device_log, #SIZE (device_log^), osc$wait, flush_status);

      dmp$close_file (device_log, status);
      IF status.normal AND NOT flush_status.normal THEN
        status := flush_status;
      IFEND;
    IFEND;

  PROCEND dmp$change_dfl_damage;
?? TITLE := '  dmp$dev_mgmt_table_update', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$dev_mgmt_table_update;

    VAR
      status: ost$status,
      ok: boolean,
      avt_index: dmt$active_volume_table_index;

    osp$begin_system_activity;

    dmv$process_device_log_count := (dmv$process_device_log_count + 1) MOD
          UPPERVALUE (dmv$process_device_log_count);

    FOR avt_index := LOWERBOUND (dmv$active_volume_table.table_p^)
          TO UPPERBOUND (dmv$active_volume_table.table_p^) DO

      IF NOT dmv$active_volume_table.table_p^ [avt_index].entry_available THEN

        IF dmc$mainframe_mounted IN dmv$active_volume_table.table_p^ [avt_index].mass_storage.status THEN
          dmp$verify_access (avt_index, ok);
          IF ok THEN

            update_volume_tables (avt_index, status);
            IF NOT status.normal THEN
              osp$fatal_system_error ('unable to update tables from log - dmp$dev_mgmt_table_update',
                    ^status);
            IFEND;

          ELSE
            dmv$skipped_update := dmv$skipped_update + 1;
          IFEND;
        IFEND;
      IFEND;

    FOREND;

    osp$end_system_activity;

  PROCEND dmp$dev_mgmt_table_update;
?? TITLE := '  dmp$enable_update', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$enable_update
    (    avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

    status.normal := TRUE;
    IF NOT dmv$test_recovery THEN
      RETURN; {----->
    IFEND;

    dmp$lock_avt_entry (avt_index);

    IF (NOT dmv$active_volume_table.table_p^ [avt_index].entry_available) THEN
      dmv$active_volume_table.table_p^ [avt_index].mass_storage.disk_table_status :=
            dmv$active_volume_table.table_p^ [avt_index].mass_storage.disk_table_status -
            $dmt$ms_volume_table_status [dmc$table_update_inhibited];
    ELSE
      osp$set_status_abnormal (dmc$device_manager_ident, dme$avt_entry_not_found,
            'bad volume selected - DMMLOG', status);
    IFEND;

    dmp$unlock_avt_entry (avt_index);

  PROCEND dmp$enable_update;
?? TITLE := '  dmp$evacuate_active_device_log', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$evacuate_active_device_log
    (    avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

    VAR
      info: dmt$avt_logging_info,
      production_logging: boolean,
      current_position_in_log: integer,
      device_log: dmt$device_log,
      p_dat: ^dmt$ms_device_allocation_table,
      p_dflt: ^dmt$ms_device_file_list_table,
      ok: boolean,
      dummy_boolean: boolean,
      status_p: ^ost$status;

    status.normal := TRUE;

    dmp$verify_access (avt_index, ok);
    IF NOT ok THEN
      dmv$skipped_evacuate := dmv$skipped_evacuate + 1;
      RETURN; {----->
    IFEND;

    current_position_in_log := 0;

    dmp$split_allocation_log (FALSE, status);
    IF NOT status.normal THEN
      osp$fatal_system_error ('split al error', ^status);
    IFEND;

    osp$set_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);

  /tables_locked/
    BEGIN
      dmp$get_avt_logging_info (avt_index, info, dummy_boolean);

      open_device_log (info.device_log_sfid, FALSE, device_log, status);
      IF NOT status.normal THEN
        EXIT /tables_locked/; {----->
      IFEND;

      dmp$open_dat (info.dat_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_sequential,
            p_dat, status);
      IF NOT status.normal THEN
        EXIT /tables_locked/; {----->
      IFEND;

      dmp$open_dflt (info.dfl_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_sequential,
            p_dflt, status);
      IF NOT status.normal THEN
        EXIT /tables_locked/; {----->
      IFEND;

      production_logging := TRUE;
      empty_device_log (info.login_table_sfid, device_log, info.mainframe_assigned, p_dat, p_dflt, avt_index,
            TRUE, production_logging, current_position_in_log, status);

      IF status.normal THEN
        status_p := ^status;
      ELSE
        PUSH status_p;
      IFEND;

      dmp$close_file (device_log, status_p^);
      IF NOT status.normal THEN
        PUSH status_p;
      IFEND;

      dmp$close_file (p_dat, status_p^);
      IF NOT status.normal THEN
        PUSH status_p;
      IFEND;

      dmp$close_file (p_dflt, status_p^);

    END /tables_locked/;

    osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);

  PROCEND dmp$evacuate_active_device_log;
?? TITLE := '  dmp$evacuate_old_device_log', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$evacuate_old_device_log
    (    avt_index: dmt$active_volume_table_index;
         old_mainframe_assigned: dmt$mainframe_assigned;
         login_table_sfid: gft$system_file_identifier;
         device_log_sfid: gft$system_file_identifier;
         p_allocation_log_info: ^dmt$allocation_log_info;
     VAR status: ost$status);

    VAR
      recovery_logging: boolean,
      production_logging: boolean,
      old_log_position: integer,
      avt_index_found: boolean,
      p_dat: ^dmt$ms_device_allocation_table,
      p_dflt: ^dmt$ms_device_file_list_table,
      log_entry: dmt$dl_entry,
      device_log: [XDCL] dmt$device_log,
      p_login_table: [XDCL] ^dmt$ms_mainframe_login_table,
      p_dat_changes: ^dmt$dat_changes,
      p_dfl_changes: ^dmt$dfl_changes,
      number_dat_changes: integer,
      number_dfl_changes: integer,
      info: dmt$avt_logging_info,
      login_index: dmt$login_table_entry_index,
      recovery_dat_update_required: boolean,
      recovery_testing_aborts: dmt$dl_recovery_testing_aborts;

    status.normal := TRUE;

    recovery_testing_aborts := dmc$dl_no_abort;

    osp$set_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);

    dmp$get_avt_logging_info (avt_index, info, avt_index_found);

    dmp$open_dat (info.dat_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_sequential, p_dat,
          status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    dmp$open_dflt (info.dfl_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_sequential,
          p_dflt, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    open_device_log (device_log_sfid, FALSE, device_log, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    dmp$open_login_table (login_table_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend,
          mmc$as_sequential, p_login_table, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    login_index := old_mainframe_assigned.log_in_index;

    IF p_login_table^.body [login_index].recovery_status = dmc$lt_being_recovered THEN
      p_login_table^.body [login_index].recovery_status := dmc$lt_being_rec_log_complete;
      mmp$write_modified_pages (p_login_table, #SIZE (p_login_table^), osc$wait, status);
      IF NOT status.normal THEN
        IF osp$file_access_condition (status) THEN
          status.normal := TRUE;
        ELSE
          RETURN; {----->
        IFEND;
      IFEND;
    IFEND;

    find_place_in_log (old_mainframe_assigned, device_log, old_log_position, p_login_table,
          recovery_dat_update_required, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF p_allocation_log_info <> NIL THEN
      extract_log_entries_from_al (p_allocation_log_info, device_log, login_table_sfid, p_login_table,
            login_index, avt_index, old_log_position, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

      mmp$write_modified_pages (device_log, #SIZE (device_log^), osc$wait, status);

      p_login_table^.body [login_index].recovery_status := dmc$lt_being_rec_alloc_complete;
      mmp$write_modified_pages (p_login_table, #SIZE (p_login_table^), osc$wait, status);
      IF NOT status.normal THEN
        IF osp$file_access_condition (status) THEN
          status.normal := TRUE;
        ELSE
          RETURN; {----->
        IFEND;
      IFEND;
    IFEND;

    dmp$close_file (p_login_table, status);
    recovery_logging := TRUE;
    production_logging := FALSE;

    IF recovery_dat_update_required THEN
      p_dat_changes := NIL;
      p_dfl_changes := NIL;
      number_dat_changes := 0;
      number_dfl_changes := 0;
      process_device_log (avt_index, old_mainframe_assigned, p_dat, p_dflt, login_table_sfid, device_log,
            production_logging, p_dat_changes, number_dat_changes, p_dfl_changes, number_dfl_changes,
            recovery_testing_aborts, old_log_position, status);
      IF NOT status.normal THEN
        osp$fatal_system_error ('recovery dat update died', ^status);
      IFEND;
      log_entry.kind := dmc$dl_update_disk_tables;
      insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, old_log_position, status);
      process_dat_changes (p_dat, avt_index, number_dat_changes, recovery_logging, p_dat_changes, status);
      process_dfl_changes (p_dflt, avt_index, number_dfl_changes, recovery_logging, p_dfl_changes, status);
    IFEND;

    IF recovery_testing_aborts = dmc$dl_halt_before_logging_dtu THEN
      osp$fatal_system_error ('HALT FOR RECOVERY TEST', NIL);
    IFEND;

    log_entry.kind := dmc$dl_disk_tables_updated;
    insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, old_log_position, status);

    empty_device_log (login_table_sfid, device_log, old_mainframe_assigned, p_dat, p_dflt, avt_index, FALSE,
          production_logging, old_log_position, status);

    dmp$close_file (device_log, status);

    dmp$close_file (p_dat, status);

    dmp$close_file (p_dflt, status);

    osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);

  PROCEND dmp$evacuate_old_device_log;
?? TITLE := '  dmp$inhibit_update', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$inhibit_update
    (    avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

    status.normal := TRUE;
    IF NOT dmv$test_recovery THEN
      RETURN; {----->
    IFEND;

    dmp$lock_avt_entry (avt_index);

    IF (NOT dmv$active_volume_table.table_p^ [avt_index].entry_available) THEN
      dmv$active_volume_table.table_p^ [avt_index].mass_storage.disk_table_status :=
            dmv$active_volume_table.table_p^ [avt_index].mass_storage.disk_table_status +
            $dmt$ms_volume_table_status [dmc$table_update_inhibited];
    ELSE
      osp$set_status_abnormal (dmc$device_manager_ident, dme$avt_entry_not_found,
            'bad volume selected - DMMLOG', status);
    IFEND;

    dmp$unlock_avt_entry (avt_index);

  PROCEND dmp$inhibit_update;
?? TITLE := '  dmp$initialize_device_log', EJECT ??

  PROCEDURE [XDCL] dmp$initialize_device_log
    (    device_log_sfid: gft$system_file_identifier;
         avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

    VAR
      p_fde: ^gft$file_descriptor_entry,
      log_entry: dmt$dl_entry,
      device_log: dmt$device_log,
      aux_status: ost$status;

    status.normal := TRUE;

    dmv$active_volume_table.table_p^ [avt_index].mass_storage.current_position_offset_in_log := 0;
    dmv$active_volume_table.table_p^ [avt_index].mass_storage.allocated_log_size := 0;
    dmv$active_volume_table.table_p^ [avt_index].mass_storage.device_log_entry_count := 0;
    dmv$active_volume_table.table_p^ [avt_index].mass_storage.p_device_log := device_log_sfid;
    dmp$set_eoi (device_log_sfid, 0, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    gfp$get_locked_fde_p (device_log_sfid, p_fde);
    p_fde^.flags.wire_eoi_page := TRUE;
    gfp$unlock_fde_p (p_fde);

    open_device_log (device_log_sfid, FALSE, device_log, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    log_entry.kind := dmc$dl_last_update_entry;
    lock_log_and_insert_entry (log_entry, avt_index, device_log, status);

    log_entry.kind := dmc$dl_disk_tables_updated;
    lock_log_and_insert_entry (log_entry, avt_index, device_log, status);

    dmp$close_file (device_log, aux_status);
    IF status.normal AND NOT aux_status.normal THEN
      status := aux_status;
    IFEND;

  PROCEND dmp$initialize_device_log;
?? TITLE := '  dmp$process_device_log_entry', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$process_device_log_entry
    (    avt_index: dmt$active_volume_table_index,
         device_log_entry: dmt$dl_entry;
     VAR status: ost$status);

    VAR
      avt_entry_found: boolean,
      device_log: dmt$device_log,
      dfl_index: dmt$device_file_list_index,
      gfn: dmt$global_file_name,
      info: dmt$avt_logging_info,
      status_p: ^ost$status;

    status.normal := TRUE;

    dmp$get_avt_logging_info (avt_index, info, avt_entry_found);
    IF NOT avt_entry_found THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$avt_entry_not_found,
            'unable to locate avt entry - dmp$process_device_log_entry', status);
      RETURN; {----->
    IFEND;

    IF info.device_log_sfid = gfv$null_sfid THEN
      IF (device_log_entry.kind = dmc$dl_purge_file) THEN
        gfn := device_log_entry.purge_file_block.global_file_name;
        dfl_index := device_log_entry.purge_file_block.dfl_index;
        dmp$dat_purge_file (gfn, dfl_index, avt_index, status);
      IFEND;
      RETURN; {----->
    IFEND;

    open_device_log (info.device_log_sfid, TRUE, device_log, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    IF NOT dmv$idle_system THEN
      preallocate_device_log (device_log, info.device_log_sfid, avt_index, status);
      IF NOT status.normal THEN
        IF osp$file_access_condition (status) THEN
          status.normal := TRUE;
        ELSE
          {   problem is likely transitory -- continue
        IFEND;
      IFEND;
    IFEND;

    lock_log_and_insert_entry (device_log_entry, avt_index, device_log, status);

    IF status.normal THEN
      status_p := ^status;
    ELSE
      PUSH status_p;
    IFEND;

    dmp$close_file (device_log, status_p^);

  PROCEND dmp$process_device_log_entry;
?? TITLE := '  dmp$process_manual_flaw', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$process_manual_flaw
    (    recorded_vsn: rmt$recorded_vsn;
         dau_address: dmt$dau_address;
         end_dau_address: dmt$dau_address;
         flaw_operation_code: dmt$flaw_operation_code;
     VAR status: ost$status);

    VAR
      avt_index: dmt$active_volume_table_index,
      dl_entry: dmt$dl_entry,
      entry_found: boolean,
      index: dmt$dau_address;

    dl_entry.kind := dmc$dl_software_flawed;

    IF (flaw_operation_code = dmc$oc_flaw_define) THEN
      dl_entry.software_flaw_block.flaw_option := dmc$add_flaw;
    ELSE
      dl_entry.software_flaw_block.flaw_option := dmc$remove_flaw;
    IFEND;

    dmp$search_avt_by_rvsn (recorded_vsn, avt_index, entry_found);
    IF NOT entry_found THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$avt_entry_not_found, 'dmp$process_manual_flaw',
            status);
      RETURN; {----->
    IFEND;

    IF dmv$active_volume_table.table_p^ [avt_index].mass_storage.p_device_log = gfv$null_sfid THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$logging_unavailable, 'dmp$process_manual_flaw',
            status);
      RETURN; {----->
    IFEND;

    FOR index := dau_address TO end_dau_address DO
      dl_entry.software_flaw_block.dau_address := index;
      dmp$process_device_log_entry (avt_index, dl_entry, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;
    FOREND;

    dmp$evacuate_active_device_log (avt_index, status);

  PROCEND dmp$process_manual_flaw;

?? TITLE := '  dmp$set_lower_priority', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$set_lower_priority
    (    task: (split_al_task, administer_log_task, volume_space_management_task);
         taskid: ost$global_task_id);

    VAR
      status: ost$status;


    CASE task OF

    = split_al_task =
      tmp$set_task_priority (jmc$priority_split_alloc, 0, status);
      dmv$split_al_initiated := TRUE;

    = administer_log_task =
      tmp$set_task_priority (jmc$priority_administer_log, 0, status);
      dmv$administer_log_initiated := TRUE;

    = volume_space_management_task =
      tmp$set_task_priority (jmc$priority_volume_space_mgr, 0, status);
      dmv$vol_space_manage_initiated := TRUE;

    CASEND;

  PROCEND dmp$set_lower_priority;
?? TITLE := '  dmp$split_allocation_log', EJECT ??

  PROCEDURE [XDCL, #GATE] dmp$split_allocation_log
    (    flush_device_log_pages: boolean;
     VAR status: ost$status);

    VAR
      split_lock: [STATIC] ost$signature_lock,
      info: dmt$avt_logging_info,
      device_log: dmt$device_log,
      device_log_sfid: gft$system_file_identifier,
      avt_entry_found: boolean,
      lower_bound: dmt$active_volume_table_index,
      upper_bound: dmt$active_volume_table_index,
      volume_index: dmt$active_volume_table_index,
      p_volume_device_log_open: ^array [ * ] of boolean,
      p_volume_device_log_pva: ^array [ * ] of dmt$device_log,
      entries_in_log,
      last_entries_in_log,
      real_entries_in_log: integer,
      i: dmt$allocation_log_index,
      successful: boolean,
      dl_entry: dmt$dl_entry,
      local_status: ost$status,
      avt_index: dmt$active_volume_table_index;

    osp$begin_system_activity;

    status.normal := TRUE;

    dmv$split_allocation_log_count := (dmv$split_allocation_log_count + 1) MOD
          UPPERVALUE (dmv$split_allocation_log_count);

    device_log := NIL;
    entries_in_log := 0;
    real_entries_in_log := 0;
    last_entries_in_log := 0;

    upper_bound := UPPERBOUND (dmv$active_volume_table.table_p^);
    lower_bound := LOWERBOUND (dmv$active_volume_table.table_p^);

    PUSH p_volume_device_log_open: [lower_bound .. upper_bound];
    PUSH p_volume_device_log_pva: [lower_bound .. upper_bound];

    FOR volume_index := lower_bound TO upper_bound DO
      p_volume_device_log_open^ [volume_index] := FALSE;
      p_volume_device_log_pva^ [volume_index] := NIL;
    FOREND;

    osp$set_mainframe_sig_lock (split_lock);

  /split_lock_set/
    BEGIN

      osp$fetch_locked_variable (dmv$allocation_log.number, entries_in_log);

      WHILE entries_in_log <> 0 DO

        FOR i := 1 TO entries_in_log DO
          avt_index := dmv$allocation_log.entries [dmv$allocation_log.first].avt_index;
          IF NOT p_volume_device_log_open^ [avt_index] THEN
            dmp$get_avt_logging_info (avt_index, info, avt_entry_found);
            IF NOT avt_entry_found THEN
              osp$set_status_abnormal (dmc$device_manager_ident, dme$avt_entry_not_found,
                    'unable to locate avt entry - dmp$split_allocation_log', status);
              EXIT /split_lock_set/; {----->
            IFEND;

            device_log_sfid := info.device_log_sfid;

            open_device_log (device_log_sfid, TRUE, device_log, status);
            IF NOT status.normal THEN
              EXIT /split_lock_set/; {----->
            IFEND;

            p_volume_device_log_pva^ [avt_index] := device_log;
            p_volume_device_log_open^ [avt_index] := TRUE;
          ELSE
            device_log := p_volume_device_log_pva^ [avt_index];
          IFEND;

          CASE dmv$allocation_log.entries [dmv$allocation_log.first].kind OF

          = dmc$al_allocate =
            dl_entry.kind := dmc$dl_allocate;
            dl_entry.allocate_block := dmv$allocation_log.entries [dmv$allocation_log.first].allocate_block;

          = dmc$al_initialize =
            dl_entry.kind := dmc$dl_initialize;
            dl_entry.initialize_block := dmv$allocation_log.entries [dmv$allocation_log.first].
                  initialize_block;

          = dmc$al_return_dau =
            dl_entry.kind := dmc$dl_return_dau;
            dl_entry.return_dau_block := dmv$allocation_log.entries [dmv$allocation_log.first].
                  return_dau_block;

          = dmc$al_software_flawed =
            dl_entry.kind := dmc$dl_software_flawed;
            dl_entry.software_flaw_block := dmv$allocation_log.entries [dmv$allocation_log.first].
                  software_flaw_block;

          = dmc$al_reallocate =
            dl_entry.kind := dmc$dl_reallocate;
            dl_entry.reallocate_block := dmv$allocation_log.entries [dmv$allocation_log.first].
                  reallocate_block;

          = dmc$al_trim_file =
            dl_entry.kind := dmc$dl_trim_file;
            dl_entry.trim_file_block := dmv$allocation_log.entries [dmv$allocation_log.first].trim_file_block;

          ELSE
            osp$set_status_abnormal (dmc$device_manager_ident, dme$invalid_device_log_kind,
                  'bad entry in allocation_log - DMMLOG', status);
          CASEND;

          osp$fetch_locked_variable (dmv$allocation_log.number, real_entries_in_log);

          REPEAT
            entries_in_log := real_entries_in_log - 1;
            last_entries_in_log := real_entries_in_log;
            osp$set_locked_variable (dmv$allocation_log.number, last_entries_in_log, entries_in_log,
                  real_entries_in_log, successful);
          UNTIL successful;

          dmv$allocation_log.first := (dmv$allocation_log.first + 1) MOD dmc$max_allocation_log_entries;

          lock_log_and_insert_entry (dl_entry, avt_index, device_log, status);
          IF NOT status.normal THEN
            osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_process_al_entry,
                  'unable to process allocation log entry - DMMLOG', status);
            EXIT /split_lock_set/; {----->
          IFEND;

          device_log := NIL;

        FOREND;

      WHILEND;

    END /split_lock_set/;

    osp$clear_mainframe_sig_lock (split_lock);

    FOR volume_index := lower_bound TO upper_bound DO
      IF p_volume_device_log_open^ [volume_index] THEN
        device_log := p_volume_device_log_pva^ [volume_index];
        IF flush_device_log_pages THEN
          mmp$write_modified_pages (device_log, #SIZE (device_log^), osc$wait, status);
          IF NOT status.normal THEN
            IF osp$file_access_condition (status) THEN
              status.normal := TRUE;
            IFEND;
          IFEND;
        IFEND;
        dmp$close_file (device_log, local_status);
        IF local_status.normal THEN
          p_volume_device_log_open^ [volume_index] := FALSE;
        ELSEIF status.normal THEN
          status := local_status;
        IFEND;
      IFEND;
    FOREND;

    IF flush_device_log_pages THEN
      dmv$flush_dev_log_pages_count := (dmv$flush_dev_log_pages_count + 1) MOD
            UPPERVALUE (dmv$flush_dev_log_pages_count);
    IFEND;

    osp$end_system_activity;

  PROCEND dmp$split_allocation_log;
?? EJECT, TITLE := 'dmp$utility_flush_logs' ??

  PROCEDURE [XDCL, #GATE] dmp$utility_flush_logs;

    VAR
      avt_index: dmt$active_volume_table_index,
      continue: boolean,
      count: 0 .. 100,
      entries: boolean,
      info: dmt$avt_logging_info,
      valid_entry: boolean;

    continue := TRUE;
    count := 1;

    WHILE continue AND (count < 100) DO
      count := count + 1;
      continue := FALSE;

      dmp$dev_mgmt_table_update;

      FOR avt_index := LOWERBOUND (dmv$active_volume_table.table_p^)
            TO UPPERBOUND (dmv$active_volume_table.table_p^) DO

        dmp$get_avt_logging_info (avt_index, info, valid_entry);
        IF valid_entry THEN
          entries := (NOT info.volume_unavailable) AND (NOT info.logging_process_damaged) AND
                (info.log_entry_count > dmv$minimum_log_count);
          IF entries THEN
            continue := TRUE;
          IFEND;
        IFEND;

      FOREND;
    WHILEND;

  PROCEND dmp$utility_flush_logs;
?? RIGHT := 110 ??

  PROCEDURE [XDCL] dmp$verify_access
    (    avti: dmt$active_volume_table_index;
     VAR ok: boolean);

    VAR
      label: ^dmt$ms_volume_label,
      pa: array [1 .. 3] of dmt$physical_device_attribute,
      pmat: ^dmt$mainframe_allocation_table,
      status: ost$status;

    IF dmv$active_volume_table.table_p^ [avti].mass_storage.volume_unavailable THEN
      ok := FALSE;
      RETURN; {----->
    IFEND;

    ok := TRUE;
    dmp$get_mat_pointer (avti, pmat);
    pa [1].keyword := dmc$bytes_per_mau;
    pa [1].bytes_per_mau := pmat^.bytes_per_mau;
    pa [2].keyword := dmc$maus_per_cylinder;
    pa [2].maus_per_cylinder := pmat^.daus_per_position * pmat^.maus_per_dau;
    pa [3].keyword := dmc$maus_per_dau;
    pa [3].maus_per_dau := pmat^.maus_per_dau;

    PUSH label: [[REP dmc$default_volume_label_size OF cell]];

    dmp$locate_volume_label (dmv$active_volume_table.table_p^ [avti].logical_unit_number, ^pa, label^,
          status);
    ok := status.normal AND (NOT dmv$active_volume_table.table_p^ [avti].mass_storage.volume_unavailable);

  PROCEND dmp$verify_access;
?? TITLE := '  change_mat', EJECT ??

  PROCEDURE change_mat
    (    avt_index: dmt$active_volume_table_index;
         mat_change_count: dmt$mat_change_count;
         p_mat_changes: ^dmt$mat_changes;
         available_dat_space: dmt$dau_address);

    VAR
      mat_change_request: dmt$mat_change_request;

{Update the statistic if necessary (this code may be removed when we know more about how big we get)
    IF mat_change_count > dmv$mat_change_list.list_size_used_max THEN
      dmv$mat_change_list.list_size_used_max := mat_change_count;
    IFEND;

    mat_change_request.request_code := syc$rc_apply_mat_changes;
    mat_change_request.avt_index := avt_index;
    mat_change_request.mat_change_type := dmc$add_mat_space;
    mat_change_request.mat_change_count := mat_change_count;
    mat_change_request.p_mat_changes := p_mat_changes;
    mat_change_request.available_dat_space := available_dat_space;

    i#call_monitor (^mat_change_request, #SIZE (mat_change_request));

  PROCEND change_mat;
?? TITLE := '  check_device_log', EJECT ??

  PROCEDURE check_device_log
    (    p_login_table: ^dmt$ms_mainframe_login_table;
         login_index: dmt$login_table_entry_index;
         p_device_log: dmt$device_log;
     VAR no_more_stuff_in_log: boolean);

    VAR
      device_log: dmt$device_log,
      p_entry_kind: ^dmt$dl_entry_kind,
      p_check_byte: ^0 .. 0ff(16);

    no_more_stuff_in_log := FALSE;
    device_log := p_device_log;
    p_entry_kind := #ADDRESS (#RING (device_log), #SEGMENT (device_log),
          p_login_table^.body [login_index].last_update_offset);

    RESET device_log TO p_entry_kind;

    NEXT p_entry_kind IN device_log;

    NEXT p_check_byte IN device_log;

    NEXT p_entry_kind IN device_log;
    IF p_entry_kind^ <> dmc$dl_update_disk_tables THEN
      RETURN; {----->
    IFEND;

    NEXT p_check_byte IN device_log;

    NEXT p_entry_kind IN device_log;
    IF p_entry_kind^ <> dmc$dl_disk_tables_updated THEN
      RETURN; {----->
    IFEND;

    no_more_stuff_in_log := TRUE;

  PROCEND check_device_log;
?? TITLE := '  do_dat_assign_dau', EJECT ??

  PROCEDURE do_dat_assign_dau
    (    p_dat: ^dmt$ms_device_allocation_table;
         dat_change: dmt$dat_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      dau: dmt$dau_address,
      dau_entry: dmt$ms_device_allocation_unit,
      dau_entry_p: ^dmt$ms_device_allocation_unit,
      dfl_index: dmt$device_file_list_index,
      file_hash: dmt$file_hash,
      first_dau: dmt$dau_address,
      flawed: boolean,
      last_dau: dmt$dau_address,
      mainframe: dmt$mainframe_assigned,
      ok: boolean;

    dmp$generate_gfn_hash (dat_change.assign_dau_block.global_file_name, file_hash);
    first_dau := dat_change.dau_address;
    last_dau := first_dau + dat_change.assign_dau_block.daus_per_allocation - 1;
    dfl_index := dat_change.assign_dau_block.dfl_index;
    mainframe := dat_change.assign_dau_block.mainframe_assigned;

    { Validate DAT change.

    ok := (last_dau < p_dat^.header.number_of_entries);

    IF NOT ok THEN
      process_dat_change_error (avt_index, dat_change, 0, p_dat^.body [0], recovery_logging);
      RETURN; {----->
    IFEND;

    FOR dau := first_dau TO last_dau DO
      dau_entry := p_dat^.body [dau];

      ok := valid_mainframe_dau (mainframe, dau_entry) OR recovery_logging AND
            valid_file_dau (dfl_index, file_hash, dau_entry);

      IF NOT ok THEN
        process_dat_change_error (avt_index, dat_change, dau, dau_entry, recovery_logging);
        RETURN; {----->
      IFEND;
    FOREND;

    { Process DAT change.

    FOR dau := first_dau TO last_dau DO
      dau_entry_p := ^p_dat^.body [dau];
      flawed := (dau_entry_p^.dau_status = dmc$dau_ass_to_file_swr_flawed) OR
            (dau_entry_p^.dau_status = dmc$dau_ass_to_mf_swr_flawed);

      IF flawed THEN
        dau_entry_p^.dau_status := dmc$dau_ass_to_file_swr_flawed;
      ELSE
        dau_entry_p^.dau_status := dmc$dau_assigned_to_file;
      IFEND;

      dau_entry_p^.file_hash := file_hash;
      dau_entry_p^.data_status := dmc$dau_data_not_initialized;

      IF (dau = first_dau) THEN
        IF dat_change.assign_dau_block.first_flag THEN
          dau_entry_p^.allocation_chain_position := dmc$first_and_last_allocation;
        ELSE
          dau_entry_p^.allocation_chain_position := dmc$last_allocation;
        IFEND;
        dau_entry_p^.high_dfl_index := dfl_index DIV dmc$dfl_index_converter;
        dau_entry_p^.low_dfl_index := dfl_index MOD dmc$dfl_index_converter
      ELSE
        dau_entry_p^.allocation_chain_position := dmc$part_of_allocation_unit;
      IFEND;
    FOREND;

  PROCEND do_dat_assign_dau;
?? TITLE := '  do_dat_reallocate_dau', EJECT ??

  PROCEDURE do_dat_reallocate_dau
    (    p_dat: ^dmt$ms_device_allocation_table;
         dat_change: dmt$dat_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      dau: dmt$dau_address,
      dau_entry: dmt$ms_device_allocation_unit,
      dau_entry_p: ^dmt$ms_device_allocation_unit,
      dfl_index: dmt$device_file_list_index,
      file_hash: dmt$file_hash,
      first_dau: dmt$dau_address,
      flawed: boolean,
      last_dau: dmt$dau_address,
      mainframe: dmt$mainframe_assigned,
      ok: boolean;

    dmp$generate_gfn_hash (dat_change.reallocate_dau_block.global_file_name, file_hash);
    first_dau := dat_change.dau_address;
    last_dau := first_dau + dat_change.reallocate_dau_block.daus_per_allocation - 1;
    dfl_index := dat_change.reallocate_dau_block.dfl_index;
    mainframe := dat_change.reallocate_dau_block.mainframe_assigned;

    { Validate DAT change.

    ok := (last_dau < p_dat^.header.number_of_entries);

    IF NOT ok THEN
      process_dat_change_error (avt_index, dat_change, 0, p_dat^.body [0], recovery_logging);
      RETURN; {----->
    IFEND;

    FOR dau := first_dau TO last_dau DO
      dau_entry := p_dat^.body [dau];

      ok := valid_mainframe_dau (mainframe, dau_entry) OR recovery_logging AND
            valid_file_dau (dfl_index, file_hash, dau_entry);

      IF NOT ok THEN
        process_dat_change_error (avt_index, dat_change, dau, dau_entry, recovery_logging);
        RETURN; {----->
      IFEND;
    FOREND;

    IF (dat_change.reallocate_dau_block.allocation_chain_position <> dmc$first_allocation) AND
          (dat_change.reallocate_dau_block.allocation_chain_position <> dmc$first_and_last_allocation) THEN
      dau_entry := p_dat^.body [dat_change.reallocate_dau_block.previous_dau_address];
      ok := valid_mainframe_dau (mainframe, dau_entry) OR valid_file_dau (dfl_index, file_hash, dau_entry);
      IF NOT ok THEN
        process_dat_change_error (avt_index, dat_change, dau, dau_entry, recovery_logging);
        RETURN; {----->
      IFEND;
    IFEND;

    IF (dat_change.reallocate_dau_block.allocation_chain_position = dmc$first_allocation) OR
          (dat_change.reallocate_dau_block.allocation_chain_position = dmc$middle_allocation) THEN
      dau_entry := p_dat^.body [dat_change.reallocate_dau_block.next_dau_address];
      ok := valid_mainframe_dau (mainframe, dau_entry) OR valid_file_dau (dfl_index, file_hash, dau_entry);
      IF NOT ok THEN
        process_dat_change_error (avt_index, dat_change, dau, dau_entry, recovery_logging);
        RETURN; {----->
      IFEND;
    IFEND;

    { Process DAT change.

    FOR dau := first_dau TO last_dau DO
      dau_entry_p := ^p_dat^.body [dau];
      flawed := (dau_entry_p^.dau_status = dmc$dau_ass_to_file_swr_flawed) OR
            (dau_entry_p^.dau_status = dmc$dau_ass_to_mf_swr_flawed);

      IF flawed THEN
        dau_entry_p^.dau_status := dmc$dau_ass_to_file_swr_flawed;
      ELSE
        dau_entry_p^.dau_status := dmc$dau_assigned_to_file;
      IFEND;

      dau_entry_p^.file_hash := file_hash;
      dau_entry_p^.data_status := dmc$dau_data_not_initialized;

      IF (dau = first_dau) THEN
        dau_entry_p^.allocation_chain_position := dat_change.reallocate_dau_block.allocation_chain_position;

        CASE dau_entry_p^.allocation_chain_position OF
        = dmc$first_and_last_allocation, dmc$last_allocation =
          dau_entry_p^.high_dfl_index := dfl_index DIV dmc$dfl_index_converter;
          dau_entry_p^.low_dfl_index := dfl_index MOD dmc$dfl_index_converter;

        = dmc$first_allocation, dmc$middle_allocation =
          dau_entry_p^.next_allocation_unit_dau := dat_change.reallocate_dau_block.next_dau_address;
        ELSE
        CASEND;
      ELSE
        dau_entry_p^.allocation_chain_position := dmc$part_of_allocation_unit;
      IFEND;
    FOREND;

  PROCEND do_dat_reallocate_dau;
?? TITLE := '  do_dat_delink_dau', EJECT ??

  PROCEDURE do_dat_delink_dau
    (    p_dat: ^dmt$ms_device_allocation_table;
         dat_change: dmt$dat_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      file_hash: dmt$file_hash,
      dau_entry_p: ^dmt$ms_device_allocation_unit,
      dau: dmt$dau_address,
      position: dmt$allocation_chain_position,
      ok: boolean;

    dmp$generate_gfn_hash (dat_change.delink_dau_block.global_file_name, file_hash);

    dau := dat_change.dau_address;
    dau_entry_p := ^p_dat^.body [dau];

{ Validate DAT change.
    ok := valid_file_dau (dat_change.delink_dau_block.dfl_index, file_hash, dau_entry_p^);

    IF ok THEN
      position := dau_entry_p^.allocation_chain_position;
      ok := NOT (position = dmc$part_of_allocation_unit);
    IFEND;

    IF NOT ok THEN
      process_dat_change_error (avt_index, dat_change, dau, dau_entry_p^, recovery_logging);
      RETURN; {----->
    IFEND;

    { Process DAT change.

    CASE position OF
    = dmc$first_and_last_allocation, dmc$last_allocation =
      { hash and dfl are ok, as checked by valid_file_dau
      { is likely a repeat during 'recovery'

    = dmc$first_allocation =
      dau_entry_p^.allocation_chain_position := dmc$first_and_last_allocation;
      dau_entry_p^.high_dfl_index := dat_change.delink_dau_block.dfl_index DIV dmc$dfl_index_converter;
      dau_entry_p^.low_dfl_index := dat_change.delink_dau_block.dfl_index MOD dmc$dfl_index_converter;

    = dmc$middle_allocation =
      dau_entry_p^.allocation_chain_position := dmc$last_allocation;
      dau_entry_p^.high_dfl_index := dat_change.delink_dau_block.dfl_index DIV dmc$dfl_index_converter;
      dau_entry_p^.low_dfl_index := dat_change.delink_dau_block.dfl_index MOD dmc$dfl_index_converter;

    = dmc$part_of_allocation_unit =
      { Should NEVER happen - called process_dat_change_error above.
    ELSE
    CASEND;

  PROCEND do_dat_delink_dau;
?? TITLE := '  do_dat_initialize', EJECT ??

  PROCEDURE do_dat_initialize
    (    p_dat: ^dmt$ms_device_allocation_table;
         dat_change: dmt$dat_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      ok: boolean,
      file_hash: dmt$file_hash,
      dau: dmt$dau_address,
      dau_entry: dmt$ms_device_allocation_unit;

    dmp$generate_gfn_hash (dat_change.initialize_block.global_file_name, file_hash);
    dau := dat_change.dau_address;
    dau_entry := p_dat^.body [dau];

    { Validate DAT change.

    ok := valid_file_dau (dat_change.initialize_block.dfl_index, file_hash, dau_entry) AND
          (dau_entry.allocation_chain_position <> dmc$part_of_allocation_unit);

    IF NOT ok THEN
      process_dat_change_error (avt_index, dat_change, dau, dau_entry, recovery_logging);
      RETURN; {----->
    IFEND;

    { Process DAT change.

    p_dat^.body [dau].data_status := dmc$dau_data_initialized;

  PROCEND do_dat_initialize;
?? TITLE := '  do_dat_recycle_dau', EJECT ??

  PROCEDURE do_dat_recycle_dau
    (    p_dat: ^dmt$ms_device_allocation_table;
         dat_change: dmt$dat_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean;
         p_mat_changes: ^dmt$mat_changes;
     VAR mat_change_count: dmt$mat_change_count {input/output} );

    VAR
      ok: boolean,
      first_dau: dmt$dau_address,
      last_dau: dmt$dau_address,
      dau: dmt$dau_address,
      mainframe: dmt$mainframe_assigned,
      allocation_style: dmt$allocation_styles,
      daus_per_allocation: dmt$daus_per_allocation;

    IF recovery_logging THEN
      do_dat_return_dau (p_dat, dat_change, avt_index, recovery_logging);
      RETURN; {----->
    IFEND;

    daus_per_allocation := dat_change.return_dau_block.daus_per_allocation;
    first_dau := dat_change.dau_address;
    last_dau := first_dau + daus_per_allocation - 1;
    mainframe := dat_change.return_dau_block.mainframe_assigned;

    { Validate DAT change.

    ok := (last_dau < p_dat^.header.number_of_entries);

    IF NOT ok THEN
      process_dat_change_error (avt_index, dat_change, 0, p_dat^.body [0], recovery_logging);
      RETURN; {----->
    IFEND;

    FOR dau := first_dau TO last_dau DO
      ok := valid_mainframe_dau (mainframe, p_dat^.body [dau]);

      IF NOT ok THEN
        process_dat_change_error (avt_index, dat_change, dau, p_dat^.body [dau], recovery_logging);
        RETURN; {----->
      IFEND;

      IF (p_dat^.body [dau].dau_status = dmc$dau_ass_to_mf_swr_flawed) THEN
        daus_per_allocation := 1;
      IFEND;
    FOREND;

    { Process DAT change.

    dau := first_dau;
    allocation_style := LOWERVALUE (allocation_style);

    WHILE (daus_per_allocation <> p_dat^.header.daus_per_allocation_style [allocation_style]) DO
      IF (allocation_style < UPPERVALUE (allocation_style)) THEN
        allocation_style := SUCC (allocation_style);
      ELSE
        process_dat_change_error (avt_index, dat_change, dau, p_dat^.body [dau], recovery_logging);
        RETURN; {----->
      IFEND;
    WHILEND;

    REPEAT
      IF (p_dat^.body [dau].dau_status = dmc$dau_ass_to_mf_swr_flawed) THEN
        p_dat^.body [dau].dau_status := dmc$dau_software_flawed;
      ELSE
        mat_change_count := mat_change_count + 1;
        p_mat_changes^ [mat_change_count].style := allocation_style;
        p_mat_changes^ [mat_change_count].dau_address := dau;

        IF mat_change_count = dmv$mat_change_count_max THEN
          change_mat (avt_index, mat_change_count, p_mat_changes, p_dat^.header.available);
          mat_change_count := 0;
        IFEND;
      IFEND;
      dau := dau + daus_per_allocation;
    UNTIL (dau > last_dau);

  PROCEND do_dat_recycle_dau;
?? TITLE := '  do_dat_release_dau', EJECT ??

  PROCEDURE do_dat_release_dau
    (    p_dat: ^dmt$ms_device_allocation_table;
         dat_change: dmt$dat_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      ok: boolean,
      file_hash: dmt$file_hash,
      first_dau: dmt$dau_address,
      last_dau: dmt$dau_address,
      dfl_index: dmt$device_file_list_index,
      mainframe: dmt$mainframe_assigned,
      dau_entry: dmt$ms_device_allocation_unit,
      dau: dmt$dau_address;

    dmp$generate_gfn_hash (dat_change.release_dau_block.global_file_name, file_hash);
    first_dau := dat_change.dau_address;
    last_dau := first_dau + dat_change.release_dau_block.daus_per_allocation - 1;
    dfl_index := dat_change.release_dau_block.dfl_index;
    mainframe := dat_change.release_dau_block.mainframe_assigned;

    { Validate DAT change.

    ok := (last_dau < p_dat^.header.number_of_entries);

    IF NOT ok THEN
      process_dat_change_error (avt_index, dat_change, 0, p_dat^.body [0], recovery_logging);
      RETURN; {----->
    IFEND;

    FOR dau := first_dau TO last_dau DO
      dau_entry := p_dat^.body [dau];
      ok := valid_file_dau (dfl_index, file_hash, dau_entry) OR
            recovery_logging AND valid_mainframe_dau (mainframe, dau_entry);
      IF NOT ok THEN
        process_dat_change_error (avt_index, dat_change, dau, dau_entry, recovery_logging);
        RETURN; {----->
      IFEND;
    FOREND;

    { Process DAT change.

    FOR dau := first_dau TO last_dau DO
      CASE p_dat^.body [dau].dau_status OF
      = dmc$dau_ass_to_file_swr_flawed =
        p_dat^.body [dau].dau_status := dmc$dau_ass_to_mf_swr_flawed;
        p_dat^.body [dau].mainframe_id := mainframe;
      = dmc$dau_assigned_to_file =
        p_dat^.body [dau].dau_status := dmc$dau_assigned_to_mainframe;
        p_dat^.body [dau].mainframe_id := mainframe;
      ELSE
      CASEND;
    FOREND;
  PROCEND do_dat_release_dau;
?? TITLE := '  do_dat_return_dau', EJECT ??

  PROCEDURE do_dat_return_dau
    (    p_dat: ^dmt$ms_device_allocation_table;
         dat_change: dmt$dat_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      ok: boolean,
      first_dau: dmt$dau_address,
      last_dau: dmt$dau_address,
      mainframe: dmt$mainframe_assigned,
      daus_returned: dmt$dau_address,
      dau: dmt$dau_address;

    first_dau := dat_change.dau_address;
    last_dau := first_dau + dat_change.return_dau_block.daus_per_allocation - 1;
    mainframe := dat_change.return_dau_block.mainframe_assigned;

    { Validate DAT change.

    ok := (last_dau < p_dat^.header.number_of_entries);

    IF NOT ok THEN
      process_dat_change_error (avt_index, dat_change, 0, p_dat^.body [0], recovery_logging);
      RETURN; {----->
    IFEND;

    FOR dau := first_dau TO last_dau DO
      ok := valid_mainframe_dau (mainframe, p_dat^.body [dau]) OR recovery_logging;

      IF NOT ok THEN
        process_dat_change_error (avt_index, dat_change, dau, p_dat^.body [dau], recovery_logging);
        RETURN; {----->
      IFEND;
    FOREND;

    { Process DAT change.

    daus_returned := 0;
    FOR dau := first_dau TO last_dau DO
      IF valid_mainframe_dau (mainframe, p_dat^.body [dau]) THEN
        CASE p_dat^.body [dau].dau_status OF
        = dmc$dau_ass_to_mf_swr_flawed =
          p_dat^.body [dau].dau_status := dmc$dau_software_flawed;
        = dmc$dau_assigned_to_mainframe =
          p_dat^.body [dau].dau_status := dmc$dau_usable;
          daus_returned := daus_returned + 1;
        ELSE
          ;
        CASEND;
      IFEND;
    FOREND;

    p_dat^.header.available := p_dat^.header.available + daus_returned;
  PROCEND do_dat_return_dau;
?? TITLE := '  do_dat_software_flawed', EJECT ??

  PROCEDURE do_dat_software_flawed
    (    p_dat: ^dmt$ms_device_allocation_table;
         dat_change: dmt$dat_change);

    VAR
      dau: dmt$dau_address;

    dau := dat_change.dau_address;

    IF (dat_change.software_flaw_block.flaw_option = dmc$add_flaw) THEN
      CASE p_dat^.body [dau].dau_status OF

      = dmc$dau_usable =
        p_dat^.body [dau].dau_status := dmc$dau_software_flawed;
        p_dat^.header.available := p_dat^.header.available - 1;

      = dmc$dau_assigned_to_mainframe =
        p_dat^.body [dau].dau_status := dmc$dau_ass_to_mf_swr_flawed;

      = dmc$dau_assigned_to_file =
        p_dat^.body [dau].dau_status := dmc$dau_ass_to_file_swr_flawed;

      ELSE
        ;
      CASEND;
    ELSE {remove flaw}
      CASE p_dat^.body [dau].dau_status OF

      = dmc$dau_software_flawed =
        p_dat^.body [dau].dau_status := dmc$dau_usable;
        p_dat^.header.available := p_dat^.header.available + 1;

      = dmc$dau_ass_to_mf_swr_flawed =
        p_dat^.body [dau].dau_status := dmc$dau_assigned_to_mainframe;

      = dmc$dau_ass_to_file_swr_flawed =
        p_dat^.body [dau].dau_status := dmc$dau_assigned_to_file;

      ELSE
        ;
      CASEND;
    IFEND;
  PROCEND do_dat_software_flawed;
?? TITLE := '  do_dat_update_dau', EJECT ??

  PROCEDURE do_dat_update_dau
    (    p_dat: ^dmt$ms_device_allocation_table;
         dat_change: dmt$dat_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      file_hash: dmt$file_hash,
      dau_entry: dmt$ms_device_allocation_unit,
      dau: dmt$dau_address,
      next_dau: dmt$dau_address,
      position: dmt$allocation_chain_position,
      ok: boolean;

    dmp$generate_gfn_hash (dat_change.update_dau_block.global_file_name, file_hash);

    dau := dat_change.dau_address;
    next_dau := dat_change.update_dau_block.next_dau_address;
    dau_entry := p_dat^.body [dau];

    { Validate DAT change.

    ok := (next_dau < p_dat^.header.number_of_entries) AND
          valid_file_dau (dat_change.update_dau_block.dfl_index, file_hash, dau_entry);

    IF ok THEN
      position := dau_entry.allocation_chain_position;
      ok := NOT (position = dmc$part_of_allocation_unit);
    IFEND;

    IF NOT ok THEN
      process_dat_change_error (avt_index, dat_change, dau, dau_entry, recovery_logging);
      RETURN; {----->
    IFEND;

    { Process DAT change.

    IF (position = dmc$first_and_last_allocation) THEN
      p_dat^.body [dau].allocation_chain_position := dmc$first_allocation;
    ELSEIF (position = dmc$last_allocation) THEN
      p_dat^.body [dau].allocation_chain_position := dmc$middle_allocation;
    IFEND;
    p_dat^.body [dau].next_allocation_unit_dau := next_dau;
  PROCEND do_dat_update_dau;
?? TITLE := '  do_dfl_attach_file', EJECT ??

  PROCEDURE do_dfl_attach_file
    (    p_dfl: ^dmt$ms_device_file_list_table;
         dfl_change: dmt$dfl_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      ok: boolean,
      dfl_entry: dmt$ms_device_file_list_entry;

    dfl_entry := p_dfl^.entries [dfl_change.dfl_index];

    { Validate DFL change.

    ok := valid_file_dfl (dfl_change.attach_file_block.global_file_name, dfl_entry);

    IF NOT ok THEN
      process_dfl_change_error (avt_index, dfl_change, dfl_entry, recovery_logging);
      RETURN; {----->
    IFEND;

    { Process DFL change.

    p_dfl^.entries [dfl_change.dfl_index].login_set := p_dfl^.entries [dfl_change.dfl_index].login_set +
          $dmt$dfl_login_set [dfl_change.attach_file_block.mainframe_assigned.log_in_index];
  PROCEND do_dfl_attach_file;
?? TITLE := '  do_dfl_create', EJECT ??

  PROCEDURE do_dfl_create
    (    p_dfl: ^dmt$ms_device_file_list_table;
         dfl_change: dmt$dfl_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      ok: boolean,
      gfn: dmt$global_file_name,
      mainframe: dmt$mainframe_assigned,
      file_hash: dmt$file_hash,
      dfl_entry: dmt$ms_device_file_list_entry;

    dfl_entry := p_dfl^.entries [dfl_change.dfl_index];
    gfn := dfl_change.create_block.global_file_name;
    mainframe := dfl_change.create_block.mainframe_assigned;

    { Validate DFL change.

    ok := valid_mainframe_dfl (mainframe, dfl_entry) OR recovery_logging AND valid_file_dfl (gfn, dfl_entry);

    IF NOT ok THEN
      process_dfl_change_error (avt_index, dfl_change, dfl_entry, recovery_logging);
      RETURN; {----->
    IFEND;

    { Process DFL change.

    dmp$generate_gfn_hash (gfn, file_hash);
    p_dfl^.entries [dfl_change.dfl_index].flags := dmc$dfle_assigned_to_file;
    p_dfl^.entries [dfl_change.dfl_index].global_file_name := gfn;
    p_dfl^.entries [dfl_change.dfl_index].daus_per_allocation_unit :=
          dfl_change.create_block.daus_per_allocation;
    p_dfl^.entries [dfl_change.dfl_index].file_kind := dfl_change.create_block.file_kind;
    p_dfl^.entries [dfl_change.dfl_index].file_hash := file_hash;
    p_dfl^.entries [dfl_change.dfl_index].file_byte_address := dfl_change.create_block.fmd_byte_address;
    p_dfl^.entries [dfl_change.dfl_index].end_of_information := 0;
    p_dfl^.entries [dfl_change.dfl_index].end_of_file := 0;
    p_dfl^.entries [dfl_change.dfl_index].fmd_length := 0;
    p_dfl^.entries [dfl_change.dfl_index].logical_length := 0;
    p_dfl^.entries [dfl_change.dfl_index].dau_chain_status := dmc$dau_chain_not_linked;
    p_dfl^.entries [dfl_change.dfl_index].first_dau_address := 0;
    p_dfl^.entries [dfl_change.dfl_index].login_set := $dmt$dfl_login_set [mainframe.log_in_index];
    p_dfl^.entries [dfl_change.dfl_index].damage := $dmt$file_damage [];
  PROCEND do_dfl_create;
?? TITLE := '  do_dfl_detach_file', EJECT ??

  PROCEDURE do_dfl_detach_file
    (    p_dfl: ^dmt$ms_device_file_list_table;
         dfl_change: dmt$dfl_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      ok: boolean,
      dfl_entry: dmt$ms_device_file_list_entry;

    dfl_entry := p_dfl^.entries [dfl_change.dfl_index];

    { Validate DFL change.

    ok := valid_file_dfl (dfl_change.attach_file_block.global_file_name, dfl_entry);

    IF NOT ok THEN
      process_dfl_change_error (avt_index, dfl_change, dfl_entry, recovery_logging);
      RETURN; {----->
    IFEND;

    { Process DFL change.

    p_dfl^.entries [dfl_change.dfl_index].login_set := p_dfl^.entries [dfl_change.dfl_index].login_set -
          $dmt$dfl_login_set [dfl_change.attach_file_block.mainframe_assigned.log_in_index];
  PROCEND do_dfl_detach_file;
?? TITLE := '  do_dfl_file_damaged', EJECT ??

  PROCEDURE do_dfl_file_damaged
    (    p_dfl: ^dmt$ms_device_file_list_table;
         dfl_change: dmt$dfl_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      ok: boolean,
      dfl_entry: dmt$ms_device_file_list_entry;

    dfl_entry := p_dfl^.entries [dfl_change.dfl_index];

    { Validate DFL change.

    ok := valid_file_dfl (dfl_change.file_damaged_block.global_file_name, dfl_entry);

    IF NOT ok THEN
      process_dfl_change_error (avt_index, dfl_change, dfl_entry, recovery_logging);
      RETURN; {----->
    IFEND;

    { Process DFL change.

    p_dfl^.entries [dfl_change.dfl_index].damage := p_dfl^.entries [dfl_change.dfl_index].damage -
          dfl_change.file_damaged_block.remove_damage + dfl_change.file_damaged_block.add_damage;

  PROCEND do_dfl_file_damaged;
?? TITLE := '  do_dfl_first_dau', EJECT ??

  PROCEDURE do_dfl_first_dau
    (    p_dfl: ^dmt$ms_device_file_list_table;
         dfl_change: dmt$dfl_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      ok: boolean,
      dfl_entry: dmt$ms_device_file_list_entry;

    dfl_entry := p_dfl^.entries [dfl_change.dfl_index];

    { Validate DFL change.

    ok := valid_file_dfl (dfl_change.first_dau_block.global_file_name, dfl_entry);

    IF NOT ok THEN
      process_dfl_change_error (avt_index, dfl_change, dfl_entry, recovery_logging);
      RETURN; {----->
    IFEND;

    { Process DFL change.

    p_dfl^.entries [dfl_change.dfl_index].dau_chain_status := dmc$dau_chain_linked;
    p_dfl^.entries [dfl_change.dfl_index].first_dau_address := dfl_change.first_dau_block.dau_address;
  PROCEND do_dfl_first_dau;
?? TITLE := '  do_dfl_release_dfl', EJECT ??

  PROCEDURE do_dfl_release_dfl
    (    p_dfl: ^dmt$ms_device_file_list_table;
         dfl_change: dmt$dfl_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      ok: boolean,
      mainframe: dmt$mainframe_assigned,
      dfl_entry: dmt$ms_device_file_list_entry;

    dfl_entry := p_dfl^.entries [dfl_change.dfl_index];
    mainframe := dfl_change.release_dfl_block.mainframe_assigned;

    { Validate DFL change.

    ok := valid_file_dfl (dfl_change.release_dfl_block.global_file_name,
          dfl_entry) OR recovery_logging AND valid_mainframe_dfl (mainframe, dfl_entry);

    IF NOT ok THEN
      process_dfl_change_error (avt_index, dfl_change, dfl_entry, recovery_logging);
      RETURN; {----->
    IFEND;

    { Process DFL change.

    p_dfl^.entries [dfl_change.dfl_index].flags := dmc$dfle_assigned_to_mainframe;
    p_dfl^.entries [dfl_change.dfl_index].mainframe_assigned := mainframe;
  PROCEND do_dfl_release_dfl;
?? TITLE := '  do_dfl_return_dfl', EJECT ??

  PROCEDURE do_dfl_return_dfl
    (    p_dfl: ^dmt$ms_device_file_list_table;
         dfl_change: dmt$dfl_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      dfl_entry: dmt$ms_device_file_list_entry;

    dfl_entry := p_dfl^.entries [dfl_change.dfl_index];

    IF valid_mainframe_dfl (dfl_change.return_dfl_block.mainframe_assigned, dfl_entry) THEN
      p_dfl^.entries [dfl_change.dfl_index].flags := dmc$dfle_available;
    ELSEIF NOT recovery_logging THEN
      process_dfl_change_error (avt_index, dfl_change, dfl_entry, recovery_logging);
    IFEND;
  PROCEND do_dfl_return_dfl;
?? TITLE := '  do_dfl_update_file_length', EJECT ??

  PROCEDURE do_dfl_update_file_length
    (    p_dfl: ^dmt$ms_device_file_list_table;
         dfl_change: dmt$dfl_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      ok: boolean,
      dfl_entry: dmt$ms_device_file_list_entry;

    dfl_entry := p_dfl^.entries [dfl_change.dfl_index];

    { Validate DFL change.

    ok := valid_file_dfl (dfl_change.file_length_block.global_file_name, dfl_entry);

    IF NOT ok THEN
      process_dfl_change_error (avt_index, dfl_change, dfl_entry, recovery_logging);
      RETURN; {----->
    IFEND;

    { Process DFL change.

    IF dfl_change.file_length_block.eof_specified THEN
      p_dfl^.entries [dfl_change.dfl_index].end_of_file := dfl_change.file_length_block.eof;
    IFEND;

    IF dfl_change.file_length_block.eoi_specified THEN
      p_dfl^.entries [dfl_change.dfl_index].end_of_information := dfl_change.file_length_block.eoi;
    IFEND;
  PROCEND do_dfl_update_file_length;
?? TITLE := '  do_dfl_update_fmd_length', EJECT ??

  PROCEDURE do_dfl_update_fmd_length
    (    p_dfl: ^dmt$ms_device_file_list_table;
         dfl_change: dmt$dfl_change;
         avt_index: dmt$active_volume_table_index;
         recovery_logging: boolean);

    VAR
      ok: boolean,
      dfl_entry: dmt$ms_device_file_list_entry;

    dfl_entry := p_dfl^.entries [dfl_change.dfl_index];

    { Validate DFL change.

    ok := valid_file_dfl (dfl_change.fmd_length_block.global_file_name, dfl_entry);

    IF NOT ok THEN
      process_dfl_change_error (avt_index, dfl_change, dfl_entry, recovery_logging);
      RETURN; {----->
    IFEND;

    { Process DFL change.

    IF dfl_change.fmd_length_block.fmd_length_specified THEN
      p_dfl^.entries [dfl_change.dfl_index].fmd_length := dfl_change.fmd_length_block.fmd_length;
    IFEND;

    IF dfl_change.fmd_length_block.logical_length_specified THEN
      p_dfl^.entries [dfl_change.dfl_index].logical_length := dfl_change.fmd_length_block.logical_length;
    IFEND;
  PROCEND do_dfl_update_fmd_length;
?? TITLE := '  down_volume', EJECT ??

  PROCEDURE down_volume
    (    avt_index: dmt$active_volume_table_index;
         tell_cm: boolean;
     VAR status: ost$status);

    VAR
      element: ^cmt$element_definition,
      first_unit: iot$logical_unit,
      found: boolean,
      ignore: ost$status,
      iou0: cmt$element_name,
      l: integer,
      lun: iot$logical_unit,
      msg: string (56),
      pp: integer,
      p_ppit: ^iot$pp_interface_table,
      request_block: cmt$request_block,
      unit_count: iot$logical_unit;

    status.normal := TRUE;

    lun := dmv$active_volume_table.table_p^ [avt_index].logical_unit_number;
    PUSH element;
    cmp$pc_get_logical_unit (lun, element, status);
    IF status.normal THEN
      found := FALSE;

    /search_pp_table/
      FOR pp := LOWERBOUND (cmv$logical_pp_table_p^) TO UPPERBOUND (cmv$logical_pp_table_p^) DO
        IF NOT cmv$logical_pp_table_p^ [pp].flags.configured THEN
          CYCLE /search_pp_table/; {----->
        IFEND;
        p_ppit := cmv$logical_pp_table_p^ [pp].pp_info.pp_interface_table_p;
        first_unit := p_ppit^.first_logical_unit;
        unit_count := p_ppit^.number_of_units;

        IF (lun >= first_unit) AND (lun <= (first_unit + unit_count - 1)) THEN
          IF p_ppit^.unit_descriptors [lun].unit_interface_table <> NIL THEN
            found := TRUE;
            EXIT /search_pp_table/; {----->
          IFEND;
        IFEND;
      FOREND /search_pp_table/;

      IF NOT found THEN
        RETURN; {----->
      IFEND;

      request_block.request_code := syc$rc_config_mgmt_request;
      request_block.status.normal := TRUE;
      request_block.kind := cmc$rbk_change_state;
      request_block.iou := 0;
      request_block.element_name := element^.element_name;
      request_block.new_state := cmc$down;
      request_block.redundant_path_available := FALSE;
      request_block.update_controller_address := FALSE;
      request_block.redundant_path_pp_list_p := NIL;
      request_block.logical_unit_list_p := NIL;
      request_block.element_type := cmc$storage_device_element;
      request_block.unit_pp := pp;
      request_block.unit_channel := p_ppit^.unit_descriptors [lun].physical_path.channel_number;
      request_block.unit_controller := p_ppit^.unit_descriptors [lun].physical_path.controller_number;
      request_block.logical_unit := lun;



      i#call_monitor (#LOC (request_block), #SIZE (request_block));

      IF NOT request_block.status.normal THEN { downing a volume twice is a no-op, so that
        status.normal := FALSE; { isn't the problem ...
        status.condition := request_block.status.condition;

      ELSE { issue critical message

        IF tell_cm THEN { alter memory tables to allow change_element_state on the volume
          iou0 := 'JUNK'; { cm doesn't use iou_name for mass storage devices
          cmp$change_state_info_table (element^.element_name, iou0, cmc$down, ignore);
        IFEND;
        STRINGREP (msg, l, 'VOLUME ', dmv$active_volume_table.table_p^ [avt_index].mass_storage.recorded_vsn,
              ' DOWNED (', element^.element_name, ')');
        dpp$put_critical_message (msg (1, l), ignore);
        { will not retain across DS as we cannot change the PCU in ring 1
        dpp$put_critical_message ('STATE CHANGE WILL NOT SURVIVE A DEADSTART', ignore);
        IF NOT tell_cm THEN
          dpp$put_critical_message ('YOU WILL BE UNABLE TO CHANGE_ELEMENT_STATE', ignore);
        IFEND;
      IFEND;
    IFEND;

  PROCEND down_volume;

?? TITLE := '  empty_device_log', EJECT ??

  PROCEDURE empty_device_log
    (    login_table_sfid: gft$system_file_identifier;
         p_device_log: dmt$device_log;
         mainframe_assigned: dmt$mainframe_assigned;
         p_dat: ^dmt$ms_device_allocation_table;
         p_dflt: ^dmt$ms_device_file_list_table;
         avt_index: dmt$active_volume_table_index;
         split_al: boolean;
         production_logging: boolean;
     VAR log_position: integer;
     VAR status: ost$status);

    VAR
      recovery_logging: boolean,
      device_log: dmt$device_log,
      p_login_table: ^dmt$ms_mainframe_login_table,
      p_dat_changes: ^dmt$dat_changes,
      p_dfl_changes: ^dmt$dfl_changes,
      number_dfl_changes: integer,
      number_dat_changes: integer,
      login_index: dmt$login_table_entry_index,
      no_more_stuff_in_log: boolean,
      log_entry: dmt$dl_entry,
      recovery_testing_aborts: dmt$dl_recovery_testing_aborts;

    status.normal := TRUE;
    recovery_logging := NOT production_logging;
    recovery_testing_aborts := dmc$dl_no_abort;

    login_index := mainframe_assigned.log_in_index;
    device_log := p_device_log;

    dmp$open_login_table (login_table_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend,
          mmc$as_sequential, p_login_table, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    REPEAT
      IF split_al THEN
        dmp$split_allocation_log (FALSE, status);
        IF NOT status.normal THEN
          RETURN; {----->
        IFEND;
      IFEND;
      p_dat_changes := NIL;
      p_dfl_changes := NIL;
      number_dat_changes := 0;
      number_dfl_changes := 0;

      log_entry.kind := dmc$dl_last_update_entry;
      IF production_logging THEN
        lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
      ELSE
        insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, log_position, status);
      IFEND;

      process_device_log (avt_index, mainframe_assigned, p_dat, p_dflt, login_table_sfid, device_log,
            production_logging, p_dat_changes, number_dat_changes, p_dfl_changes, number_dfl_changes,
            recovery_testing_aborts, log_position, status);

      log_entry.kind := dmc$dl_update_disk_tables;
      IF production_logging THEN
        lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
      ELSE
        insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, log_position, status);
      IFEND;

      process_dat_changes (p_dat, avt_index, number_dat_changes, recovery_logging, p_dat_changes, status);

      process_dfl_changes (p_dflt, avt_index, number_dfl_changes, recovery_logging, p_dfl_changes, status);

      IF recovery_testing_aborts = dmc$dl_halt_before_logging_dtu THEN
        osp$fatal_system_error ('HALT FOR RECOVERY TEST', NIL);
      IFEND;

      log_entry.kind := dmc$dl_disk_tables_updated;
      IF production_logging THEN
        lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
      ELSE
        insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, log_position, status);
      IFEND;

      check_device_log (p_login_table, login_index, device_log, no_more_stuff_in_log);

    UNTIL no_more_stuff_in_log;

    dmp$close_file (p_login_table, status);

  PROCEND empty_device_log;
?? TITLE := '  extract_log_entries_from_al', EJECT ??

  PROCEDURE extract_log_entries_from_al
    (    p_aloc_log_info: ^dmt$allocation_log_info;
     VAR device_log: dmt$device_log;
         login_table_sfid: gft$system_file_identifier;
         p_login_table: ^dmt$ms_mainframe_login_table;
         login_index: dmt$login_table_entry_index;
         avt_index: dmt$active_volume_table_index;
     VAR log_position: integer;
     VAR status: ost$status);

    VAR
      j,
      i: dmt$allocation_log_index,
      log_entry: dmt$dl_entry,
      al_entry: dmt$al_entry;

    status.normal := TRUE;

    j := p_aloc_log_info^.first;

    FOR i := 1 TO p_aloc_log_info^.number DO
      IF p_aloc_log_info^.entries [j].avt_index = p_login_table^.body [login_index].avt_index THEN
        al_entry := p_aloc_log_info^.entries [j];

        CASE al_entry.kind OF

        = dmc$al_allocate =
          log_entry.kind := dmc$dl_allocate;
          log_entry.allocate_block := p_aloc_log_info^.entries [j].allocate_block;

        = dmc$al_initialize =
          log_entry.kind := dmc$dl_initialize;
          log_entry.initialize_block := p_aloc_log_info^.entries [j].initialize_block;

        = dmc$al_return_dau =
          log_entry.kind := dmc$dl_return_dau;
          log_entry.return_dau_block := p_aloc_log_info^.entries [j].return_dau_block;

        = dmc$al_software_flawed =
          log_entry.kind := dmc$dl_software_flawed;
          log_entry.software_flaw_block := p_aloc_log_info^.entries [j].software_flaw_block;

        = dmc$al_reallocate =
          log_entry.kind := dmc$dl_reallocate;
          log_entry.reallocate_block := p_aloc_log_info^.entries [j].reallocate_block;

        = dmc$al_trim_file =
          log_entry.kind := dmc$dl_trim_file;
          log_entry.trim_file_block := p_aloc_log_info^.entries [j].trim_file_block;

        ELSE
          osp$set_status_abnormal (dmc$device_manager_ident, dme$invalid_device_log_entry,
                'bad entry in allocation log - DMMLOG', status);
          osp$fatal_system_error ('bad stuff in allocation log - DMMLOG', ^status);
        CASEND;

        insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, log_position, status);
      IFEND;

      j := (j + 1) MOD dmc$max_allocation_log_entries;

    FOREND;
  PROCEND extract_log_entries_from_al;
?? TITLE := '  find_place_in_log', EJECT ??

  PROCEDURE find_place_in_log
    (    old_mainframe_assigned: dmt$mainframe_assigned;
         p_device_log: dmt$device_log;
     VAR current_log_position: integer;
     VAR p_login_table: ^dmt$ms_mainframe_login_table;
     VAR recovery_dat_update_required: boolean;
     VAR status: ost$status);

    VAR
      device_log: dmt$device_log,
      last: integer,
      last_last: integer,
      p_entry_kind: ^dmt$dl_entry_kind,
      p_bytes: ^array [1 .. * ] of cell,
      p_check_byte: ^0 .. 0ff(16);

    status.normal := TRUE;

    last := p_login_table^.body [old_mainframe_assigned.log_in_index].last_update_offset;
    last_last := p_login_table^.body [old_mainframe_assigned.log_in_index].last_last_update_offset;
    device_log := p_device_log;
    p_entry_kind := #ADDRESS (#RING (device_log), #SEGMENT (device_log), last);


    RESET device_log TO p_entry_kind;

    REPEAT
      NEXT p_entry_kind IN device_log;
      IF (log_entry_data_size [p_entry_kind^] > 0) THEN
        NEXT p_bytes: [1 .. log_entry_data_size [p_entry_kind^]] IN device_log;
      IFEND;
      NEXT p_check_byte IN device_log;
    UNTIL (p_entry_kind^ = dmc$invalid_dl_entry) OR (p_check_byte^ <> device_log_check_byte);

    current_log_position := #OFFSET (p_entry_kind);

    p_entry_kind^ := dmc$invalid_dl_entry;
    p_entry_kind := #ADDRESS (#RING (device_log), #SEGMENT (device_log), last);

    RESET device_log TO p_entry_kind;

    REPEAT
      NEXT p_entry_kind IN device_log;
      IF (log_entry_data_size [p_entry_kind^] > 0) THEN
        NEXT p_bytes: [1 .. log_entry_data_size [p_entry_kind^]] IN device_log;
      IFEND;
      NEXT p_check_byte IN device_log;
    UNTIL (p_entry_kind^ = dmc$dl_disk_tables_updated) OR (p_entry_kind^ = dmc$invalid_dl_entry) OR
          (p_check_byte^ <> device_log_check_byte);

    recovery_dat_update_required := (p_entry_kind^ <> dmc$dl_disk_tables_updated) AND (last <> last_last);

  PROCEND find_place_in_log;
?? TITLE := '  insert_dat_change', EJECT ??

  PROCEDURE insert_dat_change
    (    dat_change: dmt$dat_change;
     VAR dat_change_abort: dmt$dat_change_abort;
     VAR p_dat_changes: ^dmt$dat_changes;
     VAR number_dat_changes: integer);

    VAR
      status: ost$status,
      temp_p_dat_changes: ^dmt$dat_changes,
      aux_dat_change: dmt$dat_change;

    IF dat_change_abort = dmc$dat_halt_before_change THEN
      dat_change_abort := dmc$dat_no_action;
      aux_dat_change.kind := dmc$dat_halt;
      aux_dat_change.dau_address := dat_change.dau_address;
      insert_dat_change (aux_dat_change, dat_change_abort, p_dat_changes, number_dat_changes);
    IFEND;

    IF p_dat_changes = NIL THEN
      ALLOCATE p_dat_changes: [1 .. 1000] IN osv$mainframe_pageable_heap^;
    IFEND;

    IF number_dat_changes = UPPERBOUND (p_dat_changes^) THEN
      ALLOCATE temp_p_dat_changes: [1 .. 2 * UPPERBOUND (p_dat_changes^)] IN osv$mainframe_pageable_heap^;
      i#move (p_dat_changes, temp_p_dat_changes, #SIZE (p_dat_changes^));
      FREE p_dat_changes IN osv$mainframe_pageable_heap^;
      p_dat_changes := temp_p_dat_changes;
    IFEND;

    number_dat_changes := number_dat_changes + 1;
    p_dat_changes^ [number_dat_changes] := dat_change;
    p_dat_changes^ [number_dat_changes].index := number_dat_changes;

    IF dat_change_abort = dmc$dat_halt_after_change THEN
      dat_change_abort := dmc$dat_no_action;
      aux_dat_change.kind := dmc$dat_halt;
      aux_dat_change.dau_address := dat_change.dau_address;
      insert_dat_change (aux_dat_change, dat_change_abort, p_dat_changes, number_dat_changes);
    IFEND;
  PROCEND insert_dat_change;
?? TITLE := '  insert_dfl_change', EJECT ??

  PROCEDURE insert_dfl_change
    (    dfl_change: dmt$dfl_change;
     VAR dfl_change_abort: dmt$dfl_change_abort;
     VAR p_dfl_changes: ^dmt$dfl_changes;
     VAR number_dfl_changes: integer);

    VAR
      temp: integer,
      status: ost$status,
      lower: dmt$dfl_change_index,
      upper: dmt$dfl_change_index,
      guess: dmt$dfl_change_index,
      insertion_index: dmt$dfl_change_index,
      replacement_index: dmt$dfl_change_index,
      size: 0 .. 7fffffff(16),
      number_to_move: dmt$dfl_change_index,
      insertion_address: ^cell,
      replacement_address: ^cell,
      p_temp_buffer: ^dmt$dfl_changes,
      temp_p_dfl_changes: ^dmt$dfl_changes,
      aux_dfl_change: dmt$dfl_change;

    IF dfl_change_abort = dmc$dfl_halt_before_change THEN
      dfl_change_abort := dmc$dfl_no_action;
      aux_dfl_change.kind := dmc$dfl_halt;
      aux_dfl_change.dfl_index := dfl_change.dfl_index;
      insert_dfl_change (aux_dfl_change, dfl_change_abort, p_dfl_changes, number_dfl_changes);
    IFEND;

    IF p_dfl_changes = NIL THEN
      ALLOCATE p_dfl_changes: [1 .. 1000] IN osv$mainframe_pageable_heap^;
    IFEND;

    IF number_dfl_changes = UPPERBOUND (p_dfl_changes^) THEN
      ALLOCATE temp_p_dfl_changes: [1 .. 2 * UPPERBOUND (p_dfl_changes^)] IN osv$mainframe_pageable_heap^;
      i#move (p_dfl_changes, temp_p_dfl_changes, #SIZE (p_dfl_changes^));
      FREE p_dfl_changes IN osv$mainframe_pageable_heap^;
      p_dfl_changes := temp_p_dfl_changes;
    IFEND;

    p_dfl_changes := p_dfl_changes;
    lower := 0;
    upper := number_dfl_changes + 1;
    temp := lower + upper;
    guess := temp DIV 2;

    WHILE guess <> lower DO
      IF p_dfl_changes^ [guess].dfl_index <= dfl_change.dfl_index THEN
        lower := guess;
      ELSE
        upper := guess;
      IFEND;
      temp := lower + upper;
      guess := temp DIV 2;
    WHILEND;

    insertion_index := guess + 1;
    replacement_index := guess + 2;
    number_to_move := number_dfl_changes - insertion_index + 1;
    size := #SIZE (dmt$dfl_change) * number_to_move;

    IF size <> 0 THEN
      insertion_address := ^p_dfl_changes^ [insertion_index];
      replacement_address := ^p_dfl_changes^ [replacement_index];
      PUSH p_temp_buffer: [1 .. number_to_move];
      i#move (insertion_address, p_temp_buffer, size);
      i#move (p_temp_buffer, replacement_address, size);
    IFEND;

    p_dfl_changes^ [insertion_index] := dfl_change;
    number_dfl_changes := number_dfl_changes + 1;

    IF dfl_change_abort = dmc$dfl_halt_after_change THEN
      dfl_change_abort := dmc$dfl_no_action;
      aux_dfl_change.kind := dmc$dfl_halt;
      aux_dfl_change.dfl_index := dfl_change.dfl_index;
      insert_dfl_change (aux_dfl_change, dfl_change_abort, p_dfl_changes, number_dfl_changes);
    IFEND;
  PROCEND insert_dfl_change;
?? TITLE := '  insert_dl_entry', EJECT ??

  PROCEDURE insert_dl_entry
    (    login_table_sfid: gft$system_file_identifier;
         login_index: dmt$login_table_entry_index;
         device_log_entry: dmt$dl_entry;
         p_device_log: dmt$device_log;
     VAR current_log_position: integer; { this is an input output parameter }
     VAR status: ost$status);

    VAR
      device_log: dmt$device_log,
      dl_entry_kind: dmt$dl_entry_kind,
      p_login_table: ^dmt$ms_mainframe_login_table,
      p_create_block: ^dmt$dl_create_block,
      p_allocate_block: ^dmt$dl_allocate_block,
      p_deallocate_fragment_block: ^dmt$dl_deallocate_fragment_blk,
      p_trim_file_block: ^dmt$dl_trim_file_block,
      p_reallocate_block: ^dmt$dl_reallocate_block,
      p_sft_delete_block: ^dmt$dl_sft_delete_block,
      p_return_dau_block: ^dmt$dl_return_dau_block,
      p_attach_file_block: ^dmt$dl_attach_file_block,
      p_initialize_block: ^dmt$dl_initialize_block,
      p_purge_file_block: ^dmt$dl_purge_file_block,
      p_release_dau_block: ^dmt$dl_release_dau_block,
      p_release_dfl_block: ^dmt$dl_release_dfl_block,
      p_return_dfl_block: ^dmt$dl_return_dfl_block,
      p_software_flaw_block: ^dmt$dl_software_flaw_block,
      p_file_length_block: ^dmt$dl_file_length_block,
      p_fmd_length_block: ^dmt$dl_fmd_length_block,
      p_file_damaged_block: ^dmt$dl_file_damaged_block,
      p_entry_kind: ^dmt$dl_entry_kind,
      p_aux_entry_kind: ^dmt$dl_entry_kind,
      p_initial_entry_kind: ^dmt$dl_entry_kind,
      pva: ^cell,
      local_status: ost$status,
      p_check_byte: ^0 .. 0ff(16);

    status.normal := TRUE;

    dl_entry_kind := device_log_entry.kind;
    device_log := p_device_log;
    p_entry_kind := #ADDRESS (#RING (device_log), #SEGMENT (device_log), current_log_position);

    RESET device_log TO p_entry_kind;

    NEXT p_entry_kind IN device_log;
    p_initial_entry_kind := p_entry_kind;

    CASE device_log_entry.kind OF

    = dmc$dl_allocate =
      NEXT p_allocate_block IN device_log;
      p_allocate_block^ := device_log_entry.allocate_block;

    = dmc$dl_deallocate_file_fragment =
      NEXT p_deallocate_fragment_block IN device_log;
      p_deallocate_fragment_block^ := device_log_entry.deallocate_file_fragment_block;

    = dmc$dl_trim_file =
      NEXT p_trim_file_block IN device_log;
      p_trim_file_block^ := device_log_entry.trim_file_block;

    = dmc$dl_reallocate =
      NEXT p_reallocate_block IN device_log;
      p_reallocate_block^ := device_log_entry.reallocate_block;

    = dmc$dl_create =
      NEXT p_create_block IN device_log;
      p_create_block^ := device_log_entry.create_block;

    = dmc$dl_return_dau, dmc$dl_recycle_dau =
      NEXT p_return_dau_block IN device_log;
      p_return_dau_block^ := device_log_entry.return_dau_block;

    = dmc$dl_attach_file, dmc$dl_detach_file =
      NEXT p_attach_file_block IN device_log;
      p_attach_file_block^ := device_log_entry.attach_file_block;

    = dmc$dl_initialize =
      NEXT p_initialize_block IN device_log;
      p_initialize_block^ := device_log_entry.initialize_block;

    = dmc$dl_purge_file =
      NEXT p_purge_file_block IN device_log;
      p_purge_file_block^ := device_log_entry.purge_file_block;

    = dmc$dl_second_purge_file =
      NEXT p_purge_file_block IN device_log;
      p_purge_file_block^ := device_log_entry.purge_file_block;

    = dmc$dl_release_dau, dmc$dl_continue_purge =
      NEXT p_release_dau_block IN device_log;
      p_release_dau_block^ := device_log_entry.release_dau_block;

    = dmc$dl_release_dfl =
      NEXT p_release_dfl_block IN device_log;
      p_release_dfl_block^ := device_log_entry.release_dfl_block;

    = dmc$dl_return_dfl =
      NEXT p_return_dfl_block IN device_log;
      p_return_dfl_block^ := device_log_entry.return_dfl_block;

    = dmc$dl_software_flawed =
      NEXT p_software_flaw_block IN device_log;
      p_software_flaw_block^ := device_log_entry.software_flaw_block;

    = dmc$dl_update_file_length =
      NEXT p_file_length_block IN device_log;
      p_file_length_block^ := device_log_entry.file_length_block;

    = dmc$dl_update_fmd_length =
      NEXT p_fmd_length_block IN device_log;
      p_fmd_length_block^ := device_log_entry.fmd_length_block;

    = dmc$dl_first_sft_delete, dmc$dl_second_sft_delete, dmc$dl_third_sft_delete =
      NEXT p_sft_delete_block IN device_log;
      p_sft_delete_block^ := device_log_entry.sft_delete_block;

    = dmc$dl_file_damaged =
      NEXT p_file_damaged_block IN device_log;
      p_file_damaged_block^ := device_log_entry.file_damaged_block;

    = dmc$dl_last_update_entry =
      dmp$open_login_table (login_table_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend,
            mmc$as_sequential, p_login_table, status);
      IF NOT status.normal THEN
        RETURN; {----->
      IFEND;

      NEXT p_check_byte IN device_log;
      p_check_byte^ := device_log_check_byte;
      NEXT p_aux_entry_kind IN device_log;
      p_aux_entry_kind^ := dmc$invalid_dl_entry;
      p_entry_kind^ := dmc$dl_last_update_entry;

      IF p_login_table^.body [login_index].recovery_status <> dmc$lt_recovering THEN
        mmp$write_modified_pages (device_log, #OFFSET (p_aux_entry_kind) + 1, osc$wait, status);
        IF NOT status.normal THEN
          IF (p_login_table^.body [login_index].recovery_status = dmc$lt_normal_status) THEN
            IF osp$file_access_condition (status) THEN
              status.normal := TRUE;
            ELSE
              osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_flush_file,
                    'unable to flush device log - DMMLOG', status);
              RETURN; {----->
            IFEND;
          IFEND;
        IFEND;
      IFEND;

      p_login_table^.body [login_index].last_last_update_offset :=
            p_login_table^.body [login_index].last_update_offset;
      p_login_table^.body [login_index].last_update_offset := #OFFSET (p_entry_kind);
      p_login_table^.body [login_index].current_position_offset := #OFFSET (p_aux_entry_kind);

      mmp$write_modified_pages (p_login_table, #SIZE (p_login_table^), osc$wait, status);
      IF NOT status.normal THEN
        IF osp$file_access_condition (status) THEN
          status.normal := TRUE;
        ELSE
          osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_flush_file,
                'unable to flush login table - DMMLOG', status);
          RETURN; {----->
        IFEND;
      IFEND;

      dmp$close_file (p_login_table, status);

      current_log_position := #OFFSET (p_aux_entry_kind);

      RETURN; {----->

    = dmc$dl_sa_on_dl_entry, dmc$dl_sa_after_process_dl, dmc$dl_sa_bef_next_dfl_change,
          dmc$dl_sa_aft_next_dfl_change, dmc$dl_sa_bef_next_dat_change, dmc$dl_sa_aft_next_dat_change,
          dmc$dl_sa_bef_logging_dtu, dmc$dl_sa_bef_mf_table_update, dmc$dl_sa_aft_mf_table_update,
          dmc$dl_ra_on_dl_entry, dmc$dl_ra_after_process_dl, dmc$dl_ra_bef_next_dfl_change,
          dmc$dl_ra_aft_next_dfl_change, dmc$dl_ra_bef_next_dat_change, dmc$dl_ra_aft_next_dat_change,
          dmc$dl_start_update, dmc$dl_disk_tables_updated, dmc$dl_ra_bef_logging_dtu,
          dmc$dl_update_disk_tables =

    ELSE
      osp$set_status_abnormal (dmc$device_manager_ident, dme$invalid_device_log_kind,
            'bad device log entry kind - DMMLOG', status);
      RETURN; {----->
    CASEND;

    NEXT p_check_byte IN device_log;
    p_check_byte^ := device_log_check_byte;

    NEXT p_entry_kind IN device_log;
    p_entry_kind^ := dmc$invalid_dl_entry;

{   We can not over-write the previous invalid entry located at p_initial_entry_kind }
{    until this entire entry has been completed.  Crashes have occured during this   }
{    time in which a page boundry has been crossed and the invalid entry was lost.   }

    p_initial_entry_kind^ := dl_entry_kind;

    current_log_position := #OFFSET (p_entry_kind);

  PROCEND insert_dl_entry;
?? TITLE := '  lock_log_and_insert_entry', EJECT ??

  PROCEDURE lock_log_and_insert_entry
    (    device_log_entry: dmt$dl_entry;
         avt_index: dmt$active_volume_table_index;
         p_device_log: dmt$device_log;
     VAR status: ost$status);

    VAR
      info: dmt$avt_logging_info,
      login_table_sfid: gft$system_file_identifier,
      login_index: dmt$login_table_entry_index,
      current_log_position: integer,
      number_of_log_entries: integer,
      avt_entry_found: boolean;

    status.normal := TRUE;
    osp$set_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_lock);

    dmp$get_avt_logging_info (avt_index, info, avt_entry_found);
    IF avt_entry_found THEN

      current_log_position := info.current_log_offset;
      login_index := info.mainframe_assigned.log_in_index;
      login_table_sfid := info.login_table_sfid;
      number_of_log_entries := info.log_entry_count;

      IF dmv$administer_log_initiated AND (number_of_log_entries >= dmv$log_entries_max_thresehold) THEN
        tmp$ready_system_task (tmc$stid_administer_log, status);
      IFEND;

      insert_dl_entry (login_table_sfid, login_index, device_log_entry, p_device_log, current_log_position,
            status);
      IF status.normal THEN
        dmv$active_volume_table.table_p^ [avt_index].mass_storage.current_position_offset_in_log :=
              current_log_position;
        dmv$active_volume_table.table_p^ [avt_index].mass_storage.device_log_entry_count :=
              (number_of_log_entries + 1) MOD UPPERVALUE (dmv$active_volume_table.table_p^ [avt_index].
              mass_storage.device_log_entry_count);
      IFEND;
    ELSE
      osp$set_status_abnormal (dmc$device_manager_ident, dme$avt_entry_not_found,
            'unable to locate avt entry - lock_log_and_insert_entry', status);
    IFEND;

    osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_lock);

  PROCEND lock_log_and_insert_entry;
?? TITLE := '  open_device_log', EJECT ??

  PROCEDURE open_device_log
    (    sfid: gft$system_file_identifier;
         force_open: boolean;
     VAR device_log: dmt$device_log;
     VAR status: ost$status);

    VAR
      p_segment_pva: ^cell,
      seq_pointer: ^cyt$sequence_pointer,
      segment_number: ost$segment,
      p_fde: ^gft$file_descriptor_entry,
      able_to_locate_fde: boolean,
      segment_pointer: mmt$segment_pointer;

    status.normal := TRUE;

    segment_pointer.kind := mmc$sequence_pointer;

    dmp$open_file (sfid, osc$os_ring_1, osc$os_ring_1, mmc$sar_write_extend, mmc$as_sequential,
          segment_pointer, status);
    IF NOT status.normal THEN
      IF status.condition = dme$volume_unavailable THEN
        IF force_open THEN
          gfp$get_fde_p (sfid, p_fde);
          IF p_fde <> NIL THEN
            mmp$open_file_by_sfid (sfid, osc$os_ring_1, osc$os_ring_1, mmc$as_sequential,
                  mmc$sar_write_extend, segment_number, status);
            IF status.normal THEN
              p_segment_pva := #ADDRESS (1, segment_number, 0);
              seq_pointer := #LOC (segment_pointer.seq_pointer);
              seq_pointer^.pva := p_segment_pva;
              IF p_fde^.file_limit <= osc$maximum_offset THEN
                seq_pointer^.length := p_fde^.file_limit;
              ELSE
                seq_pointer^.length := osc$maximum_offset;
              IFEND;
              seq_pointer^.nextt := 0;
            IFEND;
          IFEND;
        IFEND;
      IFEND;
    IFEND;
    IF status.normal THEN
      device_log := segment_pointer.seq_pointer;
    IFEND;

  PROCEND open_device_log;
?? TITLE := '  preallocate_device_log', EJECT ??

{    The purpose of this procedure is to keep the device log preallocated and preinitialized.  }
{  This is particularly  important in the event of a recovery  without image or a  retry of a  }
{  recovery  with image.   By allocating  the  device  log considerably  ahead of the current  }
{  position, and touching  each  uninitialized  allocation unit and then forcing a write, the  }
{  probability of being able to attach the  device log at recovery time,   solely from tables  }
{  that reside on the disk, is rendered  near certainty.   This is necessary when  recovering  }
{  without  an image and when reentering recovery.                                             }

  PROCEDURE preallocate_device_log
    (    device_log: dmt$device_log;
         device_log_sfid: gft$system_file_identifier;
         avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

    VAR
      avt_entry_found: boolean,
      byte_address: amt$file_byte_address,
      bytes_per_allocation: dmt$bytes_per_allocation,
      current_log_position_address: amt$file_byte_address,
      device_log_pva: ^integer,
      highest_allocated_log_address: amt$file_byte_address,
      info: dmt$avt_logging_info,
      length: integer,
      number_bytes_to_allocate: amt$file_byte_address,
      p_attributes: ^array [ * ] of dmt$assigned_ms_vol_attribute,
      p_dfd: ^dmt$disk_file_descriptor,
      p_fau: ^dmt$file_allocation_unit,
      p_fde: ^gft$file_descriptor_entry,
      p_fmd: ^dmt$file_medium_descriptor,
      rounded_up_current_log_position: amt$file_byte_address;


    status.normal := TRUE;

    dmp$get_avt_logging_info (avt_index, info, avt_entry_found);
    IF NOT avt_entry_found THEN
      osp$set_status_abnormal (dmc$device_manager_ident, dme$avt_entry_not_found,
            'unable to locate avt entry - preallocate_device_log', status);
      RETURN; {----->
    IFEND;
    highest_allocated_log_address := info.allocated_log_size;
    current_log_position_address := info.current_log_offset;

    number_bytes_to_allocate := 32768;
    rounded_up_current_log_position := ((current_log_position_address DIV number_bytes_to_allocate) + 1) *
          number_bytes_to_allocate;
    IF (number_bytes_to_allocate + rounded_up_current_log_position) > highest_allocated_log_address THEN
      gfp$get_fde_p (device_log_sfid, p_fde);
      IF p_fde = NIL THEN
        osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_locate_fde,
              'unable to locate device log fde', status);
        RETURN; {----->
      IFEND;

      IF (p_fde^.file_kind <> gfc$fk_device_file) THEN
        RETURN; {----->
      IFEND;

      dmp$allocate_file_space_r1 (device_log_sfid, highest_allocated_log_address, number_bytes_to_allocate, 0,
            osc$wait, sfc$no_limit, status);

      dmp$get_disk_file_descriptor_p (p_fde, p_dfd);
      osp$set_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_lock);

    /logging_lock_set/
      BEGIN

        dmp$get_avt_logging_info (avt_index, info, avt_entry_found);
        IF NOT avt_entry_found THEN
          osp$set_status_abnormal (dmc$device_manager_ident, dme$avt_entry_not_found,
                'unable to locate avt entry - preallocate_device_log', status);
          EXIT /logging_lock_set/; {----->
        IFEND;
        current_log_position_address := info.current_log_offset;
        bytes_per_allocation := p_dfd^.bytes_per_allocation;

        byte_address := highest_allocated_log_address + bytes_per_allocation;
        WHILE byte_address < (highest_allocated_log_address + number_bytes_to_allocate) DO
          dmp$get_fau_entry (p_dfd, byte_address, p_fau);
          IF p_fau^.state = dmc$fau_invalid_data THEN
            device_log_pva := #ADDRESS (#RING (device_log), #SEGMENT (device_log), byte_address);
            device_log_pva^ := 0;
          IFEND;
          byte_address := byte_address + bytes_per_allocation;
        WHILEND;

        {***  WHAT DOES IT MEAN IF P_FAU^.STATE = DMC$FAU_FREE? *** }

        dmp$get_fmd_by_index (p_dfd, p_fau^.fmd_index, p_fmd);
        dmv$active_volume_table.table_p^ [avt_index].mass_storage.allocated_log_size :=
              p_fmd^.fmd_allocated_length;

      END /logging_lock_set/;

      osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_lock);

      mmp$write_modified_pages (device_log, p_fmd^.fmd_allocated_length + number_bytes_to_allocate,
            osc$nowait, status);
      IF osp$file_access_condition (status) THEN
        status.normal := TRUE;
      IFEND;

    IFEND;

  PROCEND preallocate_device_log;
?? TITLE := '  process_dat_change_error', EJECT ??

  PROCEDURE process_dat_change_error
    (    avt_index: dmt$active_volume_table_index;
         dat_change: dmt$dat_change;
         dau_address: dmt$dau_address;
         dau_entry: dmt$ms_device_allocation_unit;
         recovery_logging: boolean);

    VAR
      error_count: integer,
      error_index: integer,
      list_lower: integer,
      list_length: integer,
      dat_change_error: dmt$dat_change_error;

    list_lower := LOWERBOUND (dmv$dat_change_errors.error_list);
    list_length := UPPERBOUND (dmv$dat_change_errors.error_list) - list_lower + 1;

    dat_change_error.avt_index := avt_index;
    dat_change_error.recovery_logging := recovery_logging;
    dat_change_error.dat_change := dat_change;
    dat_change_error.dau_address := dau_address;
    dat_change_error.dau_entry := dau_entry;
    dat_change_error.time := #FREE_RUNNING_CLOCK (0);

    osp$increment_locked_variable (dmv$dat_change_errors.error_count, 0, error_count);
    error_index := ((error_count - 1) MOD list_length) + list_lower;
    dmv$dat_change_errors.error_list [error_index] := dat_change_error;

    IF (dmc$debug_dat_changes IN dmv$debug_options) THEN
      IF NOT (recovery_logging AND osv$recover_at_all_costs) THEN
        osp$fatal_system_error ('Invalid DAT change.', NIL);
      IFEND;
    IFEND;
  PROCEND process_dat_change_error;
?? TITLE := '  process_dat_changes', EJECT ??

  PROCEDURE process_dat_changes
    (    p_dat: ^dmt$ms_device_allocation_table;
         avt_index: dmt$active_volume_table_index;
         number_dat_changes: integer;
         recovery_logging: boolean;
     VAR p_dat_changes: ^dmt$dat_changes;
     VAR status: ost$status);

?? SKIP := 1 ??

    PROCEDURE handler
      (    mf: ost$monitor_fault;
           p_msa: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      VAR
        p_scc: ^syt$system_core_condition,
        p_sac: ^mmt$segment_access_condition;

      IF mf.identifier = mmc$segment_fault_processor_id THEN
        p_sac := #LOC (mf.contents);
        CASE p_sac^.identifier OF
        = mmc$sac_io_read_error =
          osp$set_status_abnormal ('MM', mme$io_read_error, 'io error - process_dat_changes', status);
          EXIT process_dat_changes; {----->
        ELSE
        CASEND;

      ELSEIF mf.identifier = syc$system_core_condition THEN
        p_scc := #LOC (mf.system_core_condition);
        CASE p_scc^.condition OF
        = syc$user_defined_condition =
          IF p_scc^.user_defined_condition = syc$udc_volume_unavailable THEN
            osp$set_status_abnormal (dmc$device_manager_ident, dme$volume_unavailable,
                  'volume unavailable in process_dat_changes', status);
            EXIT process_dat_changes; {----->
          IFEND;
        ELSE
        CASEND;
      IFEND;

      syp$continue_to_cause (mf, p_msa, syc$condition_ignored, continue);

    PROCEND handler;
?? SKIP := 1 ??

    VAR
      mat_change_count: dmt$mat_change_count,
      p_mat_changes: ^dmt$mat_changes,
      i: dmt$dat_change_index,
      dat_change: dmt$dat_change;

    status.normal := TRUE;

    IF (p_dat_changes = NIL) OR (number_dat_changes = 0) THEN
      RETURN; {----->
    IFEND;

    sort_dat_changes (p_dat_changes, number_dat_changes);

    osp$set_mainframe_sig_lock (dmv$mat_change_list.lock);

    p_mat_changes := ^dmv$mat_change_list.values;
    mat_change_count := 0;

    syp$establish_condition_handler (^handler);

  /process_the_changes/
    FOR i := 1 TO number_dat_changes DO

      dat_change := p_dat_changes^ [i];

      IF (dat_change.dau_address >= p_dat^.header.number_of_entries) THEN
        process_dat_change_error (avt_index, dat_change, 0, p_dat^.body [0], recovery_logging);
        CYCLE /process_the_changes/; {----->
      IFEND;

      CASE dat_change.kind OF

      = dmc$dat_software_flawed =
        do_dat_software_flawed (p_dat, dat_change);

      = dmc$dat_initialize =
        do_dat_initialize (p_dat, dat_change, avt_index, recovery_logging);

      = dmc$dat_release_dau =
        do_dat_release_dau (p_dat, dat_change, avt_index, recovery_logging);

      = dmc$dat_return_dau =
        do_dat_return_dau (p_dat, dat_change, avt_index, recovery_logging);

      = dmc$dat_recycle_dau =
        do_dat_recycle_dau (p_dat, dat_change, avt_index, recovery_logging, p_mat_changes, mat_change_count);

      = dmc$dat_assign_dau =
        do_dat_assign_dau (p_dat, dat_change, avt_index, recovery_logging);

      = dmc$dat_update_dau =
        do_dat_update_dau (p_dat, dat_change, avt_index, recovery_logging);

      = dmc$dat_halt =
        osp$fatal_system_error ('HALT FOR RECOVERY TEST', NIL);

      = dmc$dat_reallocate_dau =
        do_dat_reallocate_dau (p_dat, dat_change, avt_index, recovery_logging);

      = dmc$dat_delink_dau =
        do_dat_delink_dau (p_dat, dat_change, avt_index, recovery_logging);

      ELSE
        osp$fatal_system_error ('Invalid DAT change.', NIL);
      CASEND;
    FOREND /process_the_changes/;

    syp$disestablish_cond_handler;

    change_mat (avt_index, mat_change_count, p_mat_changes, p_dat^.header.available);
    osp$clear_mainframe_sig_lock (dmv$mat_change_list.lock);

    mmp$write_modified_pages (p_dat, #SIZE (p_dat^), osc$wait, status);
    IF NOT status.normal THEN
      IF osp$file_access_condition (status) THEN
        status.normal := TRUE;
      IFEND;
    IFEND;

    IF p_dat_changes <> NIL THEN
      FREE p_dat_changes IN osv$mainframe_pageable_heap^;
    IFEND;

  PROCEND process_dat_changes;
?? TITLE := '  process_device_log', EJECT ??

  PROCEDURE process_device_log
    (    avt_index: dmt$active_volume_table_index;
         mainframe_assigned: dmt$mainframe_assigned;
         p_dat: ^dmt$ms_device_allocation_table;
         p_dflt: ^dmt$ms_device_file_list_table;
         login_table_sfid: gft$system_file_identifier;
         p_device_log: dmt$device_log;
         production_logging: boolean;
     VAR p_dat_changes: ^dmt$dat_changes;
     VAR number_dat_changes: integer;
     VAR p_dfl_changes: ^dmt$dfl_changes;
     VAR number_dfl_changes: integer;
     VAR recovery_testing_aborts: dmt$dl_recovery_testing_aborts;
     VAR current_position_in_log: integer;
     VAR status: ost$status);

    VAR
      dfl_index: dmt$device_file_list_index,
      gfn: dmt$global_file_name,
      p_login_table: ^dmt$ms_mainframe_login_table,
      device_log: dmt$device_log,
      p_create_block: ^dmt$dl_create_block,
      p_allocate_block: ^dmt$dl_allocate_block,
      p_deallocate_fragment_block: ^dmt$dl_deallocate_fragment_blk,
      p_trim_file_block: ^dmt$dl_trim_file_block,
      p_reallocate_block: ^dmt$dl_reallocate_block,
      p_sft_delete_block: ^dmt$dl_sft_delete_block,
      p_return_dau_block: ^dmt$dl_return_dau_block,
      p_attach_file_block: ^dmt$dl_attach_file_block,
      p_initialize_block: ^dmt$dl_initialize_block,
      p_purge_file_block: ^dmt$dl_purge_file_block,
      p_release_dau_block: ^dmt$dl_release_dau_block,
      p_release_dfl_block: ^dmt$dl_release_dfl_block,
      p_return_dfl_block: ^dmt$dl_return_dfl_block,
      p_software_flaw_block: ^dmt$dl_software_flaw_block,
      p_file_length_block: ^dmt$dl_file_length_block,
      p_fmd_length_block: ^dmt$dl_fmd_length_block,
      p_file_damaged_block: ^dmt$dl_file_damaged_block,
      p_entry_kind: ^dmt$dl_entry_kind,
      p_check_byte: ^0 .. 0ff(16),
      log_entry: dmt$dl_entry,
      release_dau_block: dmt$dl_release_dau_block,
      dat_change: dmt$dat_change,
      dfl_change: dmt$dfl_change,
      dau_address: dmt$dau_address,
      normal_exit: boolean,
      more_aus: boolean,
      offset: integer,
      login_index: dmt$login_table_entry_index,
      p_dfd: ^dmt$disk_file_descriptor,
      p_fde: ^gft$file_descriptor_entry,
      fde_found: boolean,
      dat_change_abort: dmt$dat_change_abort,
      dfl_change_abort: dmt$dfl_change_abort,
      msg: string (80),
      msg_length: integer,
      recorded_vsn: rmt$recorded_vsn,
      recovery: boolean,
      local_status: ost$status,
      halt_after_processing_dl: boolean;

    dat_change_abort := dmc$dat_no_action;
    dfl_change_abort := dmc$dfl_no_action;
    recovery_testing_aborts := dmc$dl_no_abort;
    halt_after_processing_dl := FALSE;
    normal_exit := TRUE;
    device_log := p_device_log;
    login_index := mainframe_assigned.log_in_index;

    dmp$open_login_table (login_table_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_read, mmc$as_sequential,
          p_login_table, status);
    IF status.normal THEN
      offset := p_login_table^.body [login_index].last_last_update_offset;
      recovery := (p_login_table^.body [login_index].recovery_status <> dmc$lt_normal_status);
      dmp$close_file (p_login_table, status);
    IFEND;
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    p_entry_kind := #ADDRESS (#RING (device_log), #SEGMENT (device_log), offset);

    RESET device_log TO p_entry_kind;

    NEXT p_entry_kind IN device_log;
    IF p_entry_kind^ = dmc$dl_last_update_entry THEN {start at the first non-last_update_entry}
      NEXT p_check_byte IN device_log;
      IF p_check_byte^ <> device_log_check_byte THEN
        IF NOT production_logging AND osv$recover_at_all_costs THEN
          RETURN; {----->
        IFEND;
        STRINGREP (msg, msg_length, dmv$active_volume_table.table_p^ [avt_index].mass_storage.recorded_vsn,
              ' log check byte missing');
        osp$fatal_system_error (msg, NIL);
      ELSE
        NEXT p_entry_kind IN device_log;
      IFEND;
    ELSE
      IF NOT production_logging AND osv$recover_at_all_costs THEN
        RETURN; {----->
      IFEND;
      STRINGREP (msg, msg_length, dmv$active_volume_table.table_p^ [avt_index].mass_storage.recorded_vsn,
            ' log starts incorrectly');
      osp$fatal_system_error (msg, NIL);
    IFEND;

  /process_log/
    WHILE p_entry_kind^ <> dmc$dl_last_update_entry DO
      CASE p_entry_kind^ OF

      = dmc$dl_initialize =
        NEXT p_initialize_block IN device_log;
        dat_change.kind := dmc$dat_initialize;
        dat_change.initialize_block := p_initialize_block^;
        dat_change.dau_address := p_initialize_block^.dau_address;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ = device_log_check_byte THEN
          insert_dat_change (dat_change, dat_change_abort, p_dat_changes, number_dat_changes);
        ELSE
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_software_flawed =
        NEXT p_software_flaw_block IN device_log;
        dat_change.kind := dmc$dat_software_flawed;
        dat_change.software_flaw_block := p_software_flaw_block^;
        dat_change.dau_address := p_software_flaw_block^.dau_address;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ = device_log_check_byte THEN
          insert_dat_change (dat_change, dat_change_abort, p_dat_changes, number_dat_changes);
        ELSE
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_release_dau =
        NEXT p_release_dau_block IN device_log;
        dat_change.kind := dmc$dat_release_dau;
        dat_change.release_dau_block := p_release_dau_block^;
        dat_change.dau_address := p_release_dau_block^.dau_address;
        dat_change.release_dau_block.mainframe_assigned := mainframe_assigned;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ = device_log_check_byte THEN
          insert_dat_change (dat_change, dat_change_abort, p_dat_changes, number_dat_changes);
          log_entry.kind := dmc$dl_recycle_dau;
          log_entry.return_dau_block.mainframe_assigned := mainframe_assigned;
          log_entry.return_dau_block.dau_address := p_release_dau_block^.dau_address;
          log_entry.return_dau_block.daus_per_allocation := p_release_dau_block^.daus_per_allocation;
          IF production_logging THEN
            lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
          ELSE
            insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, current_position_in_log,
                  status);
          IFEND;
          IF NOT status.normal THEN
            osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_process_dl_entry,
                  'unable to process release dau log entry - DMMLOG', status);
            EXIT /process_log/; {----->
          IFEND;
        ELSE
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_return_dau, dmc$dl_recycle_dau =
        NEXT p_return_dau_block IN device_log;
        IF (p_entry_kind^ = dmc$dl_recycle_dau) THEN
          dat_change.kind := dmc$dat_recycle_dau;
        ELSE
          dat_change.kind := dmc$dat_return_dau;
        IFEND;
        dat_change.return_dau_block := p_return_dau_block^;
        dat_change.dau_address := p_return_dau_block^.dau_address;
        dat_change.return_dau_block.mainframe_assigned := mainframe_assigned;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ = device_log_check_byte THEN
          insert_dat_change (dat_change, dat_change_abort, p_dat_changes, number_dat_changes);
        ELSE
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_allocate =
        NEXT p_allocate_block IN device_log;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;
        dat_change.kind := dmc$dat_assign_dau;
        dat_change.dau_address := p_allocate_block^.dau_address;
        dat_change.assign_dau_block.global_file_name := p_allocate_block^.global_file_name;
        dat_change.assign_dau_block.dfl_index := p_allocate_block^.dfl_index;
        dat_change.assign_dau_block.mainframe_assigned := mainframe_assigned;
        dat_change.assign_dau_block.daus_per_allocation := p_allocate_block^.daus_per_allocation;
        IF p_allocate_block^.allocate_flags = dmc$dl_first_allocation THEN
          dat_change.assign_dau_block.first_flag := TRUE;
          insert_dat_change (dat_change, dat_change_abort, p_dat_changes, number_dat_changes);

          dfl_change.kind := dmc$dfl_first_dau;
          dfl_change.dfl_index := p_allocate_block^.dfl_index;
          dfl_change.first_dau_block.global_file_name := p_allocate_block^.global_file_name;
          dfl_change.first_dau_block.dfl_index := p_allocate_block^.dfl_index;
          dfl_change.first_dau_block.dau_address := p_allocate_block^.dau_address;
          insert_dfl_change (dfl_change, dfl_change_abort, p_dfl_changes, number_dfl_changes);
        ELSE
          dat_change.assign_dau_block.first_flag := FALSE;
          insert_dat_change (dat_change, dat_change_abort, p_dat_changes, number_dat_changes);

          dat_change.kind := dmc$dat_update_dau;
          dat_change.dau_address := p_allocate_block^.previous_dau_address;
          dat_change.update_dau_block.global_file_name := p_allocate_block^.global_file_name;
          dat_change.update_dau_block.dfl_index := p_allocate_block^.dfl_index;
          dat_change.update_dau_block.next_dau_address := p_allocate_block^.dau_address;
          insert_dat_change (dat_change, dat_change_abort, p_dat_changes, number_dat_changes);
        IFEND;

      = dmc$dl_deallocate_file_fragment =
        NEXT p_deallocate_fragment_block IN device_log;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;
        release_dau_block.global_file_name := p_deallocate_fragment_block^.global_file_name;
        release_dau_block.dfl_index := p_deallocate_fragment_block^.dfl_index;
        release_dau_block.daus_per_allocation := p_dflt^.entries [p_deallocate_fragment_block^.dfl_index].
              daus_per_allocation_unit;
        release_dau_block.mainframe_assigned := mainframe_assigned;
        release_dau_block.dau_address := p_deallocate_fragment_block^.dau_address;

        release_file_daus (release_dau_block, production_logging, avt_index, device_log, login_table_sfid,
              p_dat, current_position_in_log, status);
        IF NOT status.normal THEN
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_trim_file =
        NEXT p_trim_file_block IN device_log;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;
        dat_change.kind := dmc$dat_delink_dau;
        dat_change.dau_address := p_trim_file_block^.dau_address;
        dat_change.delink_dau_block.global_file_name := p_trim_file_block^.global_file_name;
        dat_change.delink_dau_block.dfl_index := p_trim_file_block^.dfl_index;
        insert_dat_change (dat_change, dat_change_abort, p_dat_changes, number_dat_changes);

        log_entry.kind := dmc$dl_deallocate_file_fragment;
        log_entry.deallocate_file_fragment_block.global_file_name := p_trim_file_block^.global_file_name;
        log_entry.deallocate_file_fragment_block.dfl_index := p_trim_file_block^.dfl_index;
        log_entry.deallocate_file_fragment_block.dau_address := p_trim_file_block^.dau_of_fragment;
        IF production_logging THEN
          lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
        ELSE
          insert_dl_entry (login_table_sfid, mainframe_assigned.log_in_index, log_entry, device_log,
                current_position_in_log, status);
        IFEND;
        IF NOT status.normal THEN
          osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_process_dl_entry,
                'unable to process trim log entry - DMMLOG', status);
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_reallocate =
        NEXT p_reallocate_block IN device_log;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;
        dat_change.kind := dmc$dat_reallocate_dau;
        dat_change.dau_address := p_reallocate_block^.dau_address;
        dat_change.reallocate_dau_block := p_reallocate_block^;
        dat_change.reallocate_dau_block.mainframe_assigned := mainframe_assigned;
        insert_dat_change (dat_change, dat_change_abort, p_dat_changes, number_dat_changes);
        IF (p_reallocate_block^.allocation_chain_position = dmc$first_allocation) OR
              (p_reallocate_block^.allocation_chain_position = dmc$first_and_last_allocation) THEN
          dfl_change.kind := dmc$dfl_first_dau;
          dfl_change.dfl_index := p_reallocate_block^.dfl_index;
          dfl_change.first_dau_block.global_file_name := p_reallocate_block^.global_file_name;
          dfl_change.first_dau_block.dfl_index := p_reallocate_block^.dfl_index;
          dfl_change.first_dau_block.dau_address := p_reallocate_block^.dau_address;
          insert_dfl_change (dfl_change, dfl_change_abort, p_dfl_changes, number_dfl_changes);
        ELSE
          dat_change.kind := dmc$dat_update_dau;
          dat_change.dau_address := p_reallocate_block^.previous_dau_address;
          dat_change.update_dau_block.global_file_name := p_reallocate_block^.global_file_name;
          dat_change.update_dau_block.dfl_index := p_reallocate_block^.dfl_index;
          dat_change.update_dau_block.next_dau_address := p_reallocate_block^.dau_address;
          insert_dat_change (dat_change, dat_change_abort, p_dat_changes, number_dat_changes);
        IFEND;
        log_entry.kind := dmc$dl_release_dau;
        log_entry.release_dau_block.global_file_name := p_reallocate_block^.global_file_name;
        log_entry.release_dau_block.dfl_index := p_reallocate_block^.dfl_index;
        log_entry.release_dau_block.daus_per_allocation := p_reallocate_block^.daus_per_allocation;
        log_entry.release_dau_block.mainframe_assigned := mainframe_assigned;
        log_entry.release_dau_block.dau_address := p_reallocate_block^.old_dau_address;
        IF production_logging THEN
          lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
        ELSE
          insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, current_position_in_log,
                status);
        IFEND;
        IF NOT status.normal THEN
          osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_process_dl_entry,
                'unable to process reallocate log entry - DMMLOG', status);
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_first_sft_delete =
        NEXT p_sft_delete_block IN device_log;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;
        IF production_logging THEN
          gfp$get_fde_p (p_sft_delete_block^.sfid, p_fde);
          IF p_fde <> NIL THEN
            dmp$get_disk_file_descriptor_p (p_fde, p_dfd);
            IF (p_dfd^.read_write_count <> 0) THEN
              log_entry.kind := dmc$dl_first_sft_delete;
            ELSE
              log_entry.kind := dmc$dl_second_sft_delete;
            IFEND;
            log_entry.sft_delete_block := p_sft_delete_block^;
            lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
          ELSE
            osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_locate_fde,
                  'Bad SFID - process_device_log.', status);
          IFEND;

          IF NOT status.normal THEN
            osp$fatal_system_error ('process_device_log failure.', ^status);
          IFEND;
        IFEND;

      = dmc$dl_second_sft_delete =
        NEXT p_sft_delete_block IN device_log;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;
        IF production_logging THEN
          log_entry.kind := dmc$dl_third_sft_delete;
          log_entry.sft_delete_block := p_sft_delete_block^;
          lock_log_and_insert_entry (log_entry, avt_index, device_log, status);

          IF NOT status.normal THEN
            osp$fatal_system_error ('process_device_log failure.', ^status);
          IFEND;
        IFEND;

      = dmc$dl_third_sft_delete =
        NEXT p_sft_delete_block IN device_log;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;
        IF production_logging THEN
          dmp$complete_sft_delete (p_sft_delete_block^.sfid, p_sft_delete_block^.fmd_index, status);

          IF NOT status.normal THEN
            osp$fatal_system_error ('process_device_log failure.', ^status);
          IFEND;
        IFEND;

      = dmc$dl_purge_file =
        NEXT p_purge_file_block IN device_log;
        log_entry.kind := dmc$dl_second_purge_file;
        log_entry.purge_file_block := p_purge_file_block^;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;
        IF production_logging THEN
          lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
        ELSE
          insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, current_position_in_log,
                status);
        IFEND;
        IF NOT status.normal THEN
          osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_process_dl_entry,
                'unable to process purge log entry - DMMLOG', status);
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_second_purge_file =
        NEXT p_purge_file_block IN device_log;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

        gfn := p_purge_file_block^.global_file_name;
        dfl_index := p_purge_file_block^.dfl_index;

        {The DFL entry must be validated to tolerate software or hardware corruption of
        {the log or the DFL.  In addition, the log entry may be invalid if bad parameters
        {are passed to dmp$destroy_permanent_file, since no validation is performed by it
        {before issuing a purge log entry.

        IF valid_dfl_index (dfl_index, p_dflt) AND valid_file_dfl (gfn, p_dflt^.entries [dfl_index]) THEN
          log_entry.kind := dmc$dl_release_dfl;
          log_entry.release_dfl_block.global_file_name := gfn;
          log_entry.release_dfl_block.dfl_index := dfl_index;
          log_entry.release_dfl_block.mainframe_assigned := mainframe_assigned;
          IF production_logging THEN
            lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
          ELSE
            insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, current_position_in_log,
                  status);
          IFEND;
          IF NOT status.normal THEN
            osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_process_dl_entry,
                  'unable to process 2nd purge log entry - DMMLOG', status);
            EXIT /process_log/; {----->
          IFEND;

          IF (p_dflt^.entries [dfl_index].dau_chain_status = dmc$dau_chain_linked) THEN
            release_dau_block.global_file_name := gfn;
            release_dau_block.dfl_index := dfl_index;
            release_dau_block.daus_per_allocation := p_dflt^.entries [dfl_index].daus_per_allocation_unit;
            release_dau_block.mainframe_assigned := mainframe_assigned;
            release_dau_block.dau_address := p_dflt^.entries [dfl_index].first_dau_address;
            release_file_daus (release_dau_block, production_logging, avt_index, device_log, login_table_sfid,
                  p_dat, current_position_in_log, status);
            IF NOT status.normal THEN
              EXIT /process_log/; {----->
            IFEND;
          IFEND;
        IFEND;

      = dmc$dl_continue_purge =
        NEXT p_release_dau_block IN device_log;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

        release_file_daus (p_release_dau_block^, production_logging, avt_index, device_log, login_table_sfid,
              p_dat, current_position_in_log, status);
        IF NOT status.normal THEN
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_create =
        dfl_change.kind := dmc$dfl_create;
        NEXT p_create_block IN device_log;
        dfl_change.create_block := p_create_block^;
        dfl_change.dfl_index := p_create_block^.dfl_index;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ = device_log_check_byte THEN
          insert_dfl_change (dfl_change, dfl_change_abort, p_dfl_changes, number_dfl_changes);
        ELSE
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_return_dfl =
        NEXT p_return_dfl_block IN device_log;
        dfl_change.kind := dmc$dfl_return_dfl;
        dfl_change.dfl_index := p_return_dfl_block^.dfl_index;
        dfl_change.return_dfl_block := p_return_dfl_block^;
        dfl_change.return_dfl_block.mainframe_assigned := mainframe_assigned;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ = device_log_check_byte THEN
          insert_dfl_change (dfl_change, dfl_change_abort, p_dfl_changes, number_dfl_changes);
        ELSE
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_release_dfl =
        NEXT p_release_dfl_block IN device_log;
        dfl_change.kind := dmc$dfl_release_dfl;
        dfl_change.dfl_index := p_release_dfl_block^.dfl_index;
        dfl_change.release_dfl_block := p_release_dfl_block^;
        dfl_change.release_dfl_block.mainframe_assigned := mainframe_assigned;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ = device_log_check_byte THEN
          insert_dfl_change (dfl_change, dfl_change_abort, p_dfl_changes, number_dfl_changes);
          log_entry.kind := dmc$dl_return_dfl;
          log_entry.return_dfl_block.dfl_index := dfl_change.dfl_index;
          log_entry.return_dfl_block.mainframe_assigned := mainframe_assigned;
          IF production_logging THEN
            lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
          ELSE
            insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, current_position_in_log,
                  status);
          IFEND;
          IF NOT status.normal THEN
            osp$set_status_abnormal (dmc$device_manager_ident, dme$unable_to_process_dl_entry,
                  'unable to process release dfl log entry - DMMLOG', status);
            EXIT /process_log/; {----->
          IFEND;
        ELSE
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_attach_file, dmc$dl_detach_file =
        NEXT p_attach_file_block IN device_log;
        dfl_change.attach_file_block := p_attach_file_block^;
        IF (p_entry_kind^ = dmc$dl_attach_file) THEN
          dfl_change.kind := dmc$dfl_attach_file;
          dfl_change.attach_file_block.mainframe_assigned := mainframe_assigned;
        ELSE
          dfl_change.kind := dmc$dfl_detach_file;
        IFEND;
        dfl_change.dfl_index := p_attach_file_block^.dfl_index;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ = device_log_check_byte THEN
          insert_dfl_change (dfl_change, dfl_change_abort, p_dfl_changes, number_dfl_changes);
        ELSE
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_update_file_length =
        NEXT p_file_length_block IN device_log;
        dfl_change.kind := dmc$dfl_update_file_length;
        dfl_change.dfl_index := p_file_length_block^.dfl_index;
        dfl_change.file_length_block := p_file_length_block^;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ = device_log_check_byte THEN
          insert_dfl_change (dfl_change, dfl_change_abort, p_dfl_changes, number_dfl_changes);
        ELSE
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_update_fmd_length =
        NEXT p_fmd_length_block IN device_log;
        dfl_change.kind := dmc$dfl_update_fmd_length;
        dfl_change.dfl_index := p_fmd_length_block^.dfl_index;
        dfl_change.fmd_length_block := p_fmd_length_block^;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ = device_log_check_byte THEN
          insert_dfl_change (dfl_change, dfl_change_abort, p_dfl_changes, number_dfl_changes);
        ELSE
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;

      = dmc$dl_disk_tables_updated, dmc$dl_start_update, dmc$dl_update_disk_tables =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
        IFEND;

      = dmc$dl_file_damaged =
        NEXT p_file_damaged_block IN device_log;
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/; {----->
        IFEND;
        dfl_change.kind := dmc$dfl_file_damaged;
        dfl_change.dfl_index := p_file_damaged_block^.dfl_index;
        dfl_change.file_damaged_block := p_file_damaged_block^;
        insert_dfl_change (dfl_change, dfl_change_abort, p_dfl_changes, number_dfl_changes);

      = dmc$dl_sa_on_dl_entry =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND NOT recovery THEN
          osp$fatal_system_error ('HALT FOR RECOVERY TEST', NIL);
        IFEND;

      = dmc$dl_sa_after_process_dl =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND NOT recovery THEN
          halt_after_processing_dl := TRUE;
        IFEND;

      = dmc$dl_sa_bef_next_dfl_change =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND NOT recovery THEN
          dfl_change_abort := dmc$dfl_halt_before_change;
        IFEND;

      = dmc$dl_sa_aft_next_dfl_change =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND NOT recovery THEN
          dfl_change_abort := dmc$dfl_halt_after_change;
        IFEND;

      = dmc$dl_sa_bef_next_dat_change =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND NOT recovery THEN
          dat_change_abort := dmc$dat_halt_before_change;
        IFEND;

      = dmc$dl_sa_aft_next_dat_change =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND NOT recovery THEN
          dat_change_abort := dmc$dat_halt_after_change;
        IFEND;

      = dmc$dl_sa_bef_logging_dtu =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND NOT recovery THEN
          recovery_testing_aborts := dmc$dl_halt_before_logging_dtu;
        IFEND;

      = dmc$dl_sa_bef_mf_table_update =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND NOT recovery THEN
          recovery_testing_aborts := dmc$dl_halt_before_mf_table_upd;
        IFEND;

      = dmc$dl_sa_aft_mf_table_update =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND NOT recovery THEN
          recovery_testing_aborts := dmc$dl_halt_after_mf_table_upd;
        IFEND;

      = dmc$dl_ra_on_dl_entry =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND recovery THEN
          osp$fatal_system_error ('HALT FOR RECOVERY TEST', NIL);
        IFEND;

      = dmc$dl_ra_after_process_dl =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND recovery THEN
          halt_after_processing_dl := TRUE;
        IFEND;

      = dmc$dl_ra_bef_next_dfl_change =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND recovery THEN
          dfl_change_abort := dmc$dfl_halt_before_change;
        IFEND;

      = dmc$dl_ra_aft_next_dfl_change =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND recovery THEN
          dfl_change_abort := dmc$dfl_halt_after_change;
        IFEND;

      = dmc$dl_ra_bef_next_dat_change =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND recovery THEN
          dat_change_abort := dmc$dat_halt_before_change;
        IFEND;

      = dmc$dl_ra_aft_next_dat_change =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;
        IF dmv$test_recovery AND recovery THEN
          dat_change_abort := dmc$dat_halt_after_change;
        IFEND;

      = dmc$dl_ra_bef_logging_dtu =
        NEXT p_check_byte IN device_log;
        IF p_check_byte^ <> device_log_check_byte THEN
          normal_exit := FALSE;
          EXIT /process_log/ {----->
        IFEND;

        IF dmv$test_recovery AND recovery THEN
          recovery_testing_aborts := dmc$dl_halt_before_logging_dtu;
        IFEND;

      = dmc$invalid_dl_entry =
        normal_exit := FALSE;
        EXIT /process_log/; {----->

      ELSE
        normal_exit := FALSE;
        EXIT /process_log/; {----->

      CASEND;
      NEXT p_entry_kind IN device_log;

    WHILEND /process_log/;

    IF NOT normal_exit THEN
      IF (NOT production_logging AND osv$recover_at_all_costs) OR cmv$post_deadstart THEN
        RETURN; {----->
      IFEND;
      STRINGREP (msg, msg_length, dmv$active_volume_table.table_p^ [avt_index].mass_storage.recorded_vsn,
            ' invalid log entry');
      osp$fatal_system_error (msg, NIL);
    IFEND;

    IF dmv$recycle_device_log AND normal_exit AND production_logging THEN
      recycle_device_log (avt_index, login_table_sfid, login_index, p_entry_kind, device_log, local_status);
      IF NOT local_status.normal THEN
        osp$fatal_system_error ('recycle device log failed - DMMLOG', ^local_status);
      IFEND;
    IFEND;

    IF halt_after_processing_dl THEN
      osp$fatal_system_error ('HALT FOR RECOVERY TEST', NIL);
    IFEND;

  PROCEND process_device_log;
?? TITLE := '  process_dfl_change_error', EJECT ??

  PROCEDURE process_dfl_change_error
    (    avt_index: dmt$active_volume_table_index;
         dfl_change: dmt$dfl_change;
         dfl_entry: dmt$ms_device_file_list_entry;
         recovery_logging: boolean);

    VAR
      error_count: integer,
      error_index: integer,
      list_lower: integer,
      list_length: integer,
      dfl_change_error: dmt$dfl_change_error;

    list_lower := LOWERBOUND (dmv$dfl_change_errors.error_list);
    list_length := UPPERBOUND (dmv$dfl_change_errors.error_list) - list_lower + 1;

    dfl_change_error.avt_index := avt_index;
    dfl_change_error.recovery_logging := recovery_logging;
    dfl_change_error.dfl_change := dfl_change;
    dfl_change_error.dfl_entry := dfl_entry;
    dfl_change_error.time := #FREE_RUNNING_CLOCK (0);

    osp$increment_locked_variable (dmv$dfl_change_errors.error_count, 0, error_count);
    error_index := ((error_count - 1) MOD list_length) + list_lower;
    dmv$dfl_change_errors.error_list [error_index] := dfl_change_error;

    IF (dmc$debug_dfl_changes IN dmv$debug_options) THEN
      IF NOT (recovery_logging AND osv$recover_at_all_costs) THEN
        osp$fatal_system_error ('Invalid DFL change.', NIL);
      IFEND;
    IFEND;
  PROCEND process_dfl_change_error;
?? TITLE := '  process_dfl_changes', EJECT ??

  PROCEDURE process_dfl_changes
    (    p_dfl: ^dmt$ms_device_file_list_table;
         avt_index: dmt$active_volume_table_index;
         number_dfl_changes: integer;
         recovery_logging: boolean;
     VAR p_dfl_changes: ^dmt$dfl_changes;
     VAR status: ost$status);

?? SKIP := 1 ??

    PROCEDURE handler
      (    mf: ost$monitor_fault;
           p_msa: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      VAR
        p_scc: ^syt$system_core_condition,
        p_sac: ^mmt$segment_access_condition;

      IF mf.identifier = mmc$segment_fault_processor_id THEN
        p_sac := #LOC (mf.contents);
        CASE p_sac^.identifier OF
        = mmc$sac_io_read_error =
          osp$set_status_abnormal ('MM', mme$io_read_error, 'io error - process_dfl_changes', status);
          EXIT process_dfl_changes; {----->
        ELSE
        CASEND;

      ELSEIF mf.identifier = syc$system_core_condition THEN
        p_scc := #LOC (mf.system_core_condition);
        CASE p_scc^.condition OF
        = syc$user_defined_condition =
          IF p_scc^.user_defined_condition = syc$udc_volume_unavailable THEN
            osp$set_status_abnormal (dmc$device_manager_ident, dme$volume_unavailable,
                  'volume unavailable in process_dfl_changes', status);
            EXIT process_dfl_changes; {----->
          IFEND;
        ELSE
        CASEND;
      IFEND;

      syp$continue_to_cause (mf, p_msa, syc$condition_ignored, continue);

    PROCEND handler;
?? SKIP := 1 ??

    VAR
      i: dmt$dfl_change_index,
      dfl_change: dmt$dfl_change;

    status.normal := TRUE;

    IF (p_dfl_changes = NIL) OR (number_dfl_changes = 0) THEN
      RETURN; {----->
    IFEND;

    syp$establish_condition_handler (^handler);

  /process_the_changes/
    FOR i := 1 TO number_dfl_changes DO

      dfl_change := p_dfl_changes^ [i];

      IF (dfl_change.dfl_index < 1) OR (dfl_change.dfl_index > p_dfl^.header.number_of_entries) THEN
        process_dfl_change_error (avt_index, dfl_change, p_dfl^.entries [1], recovery_logging);
        CYCLE /process_the_changes/; {----->
      IFEND;

      CASE dfl_change.kind OF

      = dmc$dfl_create =
        do_dfl_create (p_dfl, dfl_change, avt_index, recovery_logging);

      = dmc$dfl_return_dfl =
        do_dfl_return_dfl (p_dfl, dfl_change, avt_index, recovery_logging);

      = dmc$dfl_first_dau =
        do_dfl_first_dau (p_dfl, dfl_change, avt_index, recovery_logging);

      = dmc$dfl_release_dfl =
        do_dfl_release_dfl (p_dfl, dfl_change, avt_index, recovery_logging);

      = dmc$dfl_attach_file =
        do_dfl_attach_file (p_dfl, dfl_change, avt_index, recovery_logging);

      = dmc$dfl_detach_file =
        do_dfl_detach_file (p_dfl, dfl_change, avt_index, recovery_logging);

      = dmc$dfl_update_file_length =
        do_dfl_update_file_length (p_dfl, dfl_change, avt_index, recovery_logging);

      = dmc$dfl_update_fmd_length =
        do_dfl_update_fmd_length (p_dfl, dfl_change, avt_index, recovery_logging);

      = dmc$dfl_file_damaged =
        do_dfl_file_damaged (p_dfl, dfl_change, avt_index, recovery_logging);

      = dmc$dfl_halt =
        osp$fatal_system_error ('HALT FOR RECOVERY TEST', NIL);


      ELSE
        osp$fatal_system_error ('Invalid DFL change.', NIL);
      CASEND;

    FOREND /process_the_changes/;

    syp$disestablish_cond_handler;

    mmp$write_modified_pages (p_dfl, #SIZE (p_dfl^), osc$wait, status);
    IF NOT status.normal THEN
      IF osp$file_access_condition (status) THEN
        status.normal := TRUE;
      IFEND;
    IFEND;

    IF p_dfl_changes <> NIL THEN
      FREE p_dfl_changes IN osv$mainframe_pageable_heap^;
    IFEND;

  PROCEND process_dfl_changes;
?? TITLE := '   recycle_device_log', EJECT ??

  PROCEDURE recycle_device_log
    (    avt_index: dmt$active_volume_table_index;
         login_table_sfid: gft$system_file_identifier;
         log_in_index: dmt$login_table_entry_index;
         p_last_processed_entry: ^dmt$dl_entry_kind;
     VAR device_log: dmt$device_log;
     VAR status: ost$status);

    VAR
      production_log: boolean,
      login_table: ^dmt$ms_mainframe_login_table,
      current_position: integer,
      p_last_last: ^dmt$dl_entry_kind,
      move_length: integer,
      entry_kind: ^dmt$dl_entry_kind;

    status.normal := TRUE;
    dmp$open_login_table (login_table_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend,
          mmc$as_sequential, login_table, status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;

    osp$set_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_lock);
    current_position := dmv$active_volume_table.table_p^ [avt_index].mass_storage.
          current_position_offset_in_log;

    p_last_last := #ADDRESS (#RING (device_log), #SEGMENT (device_log),
          login_table^.body [log_in_index].last_last_update_offset);

    IF #OFFSET (p_last_last) > (current_position - #OFFSET (p_last_last) + 3) THEN
      dmv$recycled_log := dmv$recycled_log + 1;
    ELSE
      dmv$skipped_recycle_of_log := dmv$skipped_recycle_of_log + 1;
      osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_lock);
      dmp$close_file (login_table, status);
      RETURN; {----->
    IFEND;

    move_length := current_position - #OFFSET (p_last_last);
    i#move (p_last_last, device_log, move_length);

    entry_kind := #ADDRESS (#RING (device_log), #SEGMENT (device_log), move_length);
    RESET device_log TO entry_kind;
    NEXT entry_kind IN device_log;
    entry_kind^ := dmc$invalid_dl_entry;

    production_log := (login_table^.body [log_in_index].recovery_status <> dmc$lt_recovering);
    IF production_log THEN
      mmp$write_modified_pages (device_log, move_length, osc$wait, status);
    IFEND;

    login_table^.body [log_in_index].last_last_update_offset := 0;
    login_table^.body [log_in_index].last_update_offset := #OFFSET (p_last_processed_entry) -
          #OFFSET (p_last_last);
    mmp$write_modified_pages (login_table, #SIZE (login_table^), osc$wait, status);
    IF osp$file_access_condition (status) THEN
      status.normal := TRUE;
    IFEND;
    NEXT entry_kind IN device_log;
    dmp$set_eoi (dmv$active_volume_table.table_p^ [avt_index].mass_storage.p_device_log, #OFFSET (entry_kind),
          status);
    IF NOT status.normal THEN
      RETURN; {----->
    IFEND;
    mmp$free_pages (entry_kind, 7fffffff(16), osc$wait, status);

    dmv$active_volume_table.table_p^ [avt_index].mass_storage.current_position_offset_in_log := move_length;
    osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_lock);
    dmp$close_file (login_table, status);

  PROCEND recycle_device_log;

?? EJECT, TITLE := 'release_file_daus' ??
{  This procedure releases DAUs (logs a dmc$dl_release_dau) sequentially by DAU linkage until the
{ number of log entries generated is equal to a pre-defined constant.  It then logs (if need be)
{ a purge 'continuation' which will be processed in the next logger cycle.
{
{  This effectively causes large files (as defined by the constant) to have their file space returned
{ incrementally and giving the logger a breather occassionally when asked to purge a large subfile.
{ This code will 1) reduce the amount of space required by the device log, 2) lessen the 'console
{ freeze' problem when the logger is sorting a large number of DAT changes, and 3) cause more time
{ (logger cycles) to be required in order to reclaim disk space.
{
{  Validation is performed on each DAU of the allocation chain to protect against damage to the
{ file system.  If invalid information is found, the condition is logged as a DAT Change Error.
{ The index field of the DAT Change Error is set to its maximum value to distinguish the error
{ from a normal DAT Change Error.

  PROCEDURE release_file_daus
    (    release_dau_block: dmt$dl_release_dau_block; {MUST BE complete release_dau entry
         production_logging: boolean;
         avt_index: dmt$active_volume_table_index;
         device_log: dmt$device_log;
         login_table_sfid: gft$system_file_identifier;
         p_dat: ^dmt$ms_device_allocation_table;
     VAR current_position_in_log: integer;
     VAR status: ost$status);

?? SKIP := 1 ??

    PROCEDURE handler
      (    mf: ost$monitor_fault;
           p_msa: ^ost$minimum_save_area;
       VAR continue: syt$continue_option);

      VAR
        p_scc: ^syt$system_core_condition,
        p_sac: ^mmt$segment_access_condition;

      IF mf.identifier = mmc$segment_fault_processor_id THEN
        p_sac := #LOC (mf.contents);
        CASE p_sac^.identifier OF
        = mmc$sac_io_read_error =
          osp$set_status_abnormal ('MM', mme$io_read_error, 'io error - release_file_daus', status);
          EXIT release_file_daus; {----->
        ELSE
        CASEND;

      ELSEIF mf.identifier = syc$system_core_condition THEN
        p_scc := #LOC (mf.system_core_condition);
        CASE p_scc^.condition OF
        = syc$user_defined_condition =
          IF p_scc^.user_defined_condition = syc$udc_volume_unavailable THEN
            osp$set_status_abnormal (dmc$device_manager_ident, dme$volume_unavailable,
                  'volume unavailable in release_file_daus', status);
            EXIT release_file_daus; {----->
          IFEND;
        ELSE
        CASEND;
      IFEND;

      syp$continue_to_cause (mf, p_msa, syc$condition_ignored, continue);

    PROCEND handler;
?? SKIP := 1 ??

    VAR
      count: integer,
      dat_change: dmt$dat_change,
      dau: dmt$dau_address,
      dau_count: dmt$dau_address,
      dau_entry: dmt$ms_device_allocation_unit,
      daus_per_allocation: dmt$daus_per_allocation,
      dfl_index: dmt$device_file_list_index,
      file_hash: dmt$file_hash,
      first_dau: dmt$dau_address,
      last_dau: dmt$dau_address,
      log_entry: dmt$dl_entry,
      login_index: dmt$login_table_entry_index,
      more_aus: boolean,
      ok: boolean;

    status.normal := TRUE;

    count := 0;
    more_aus := TRUE;
    log_entry.kind := dmc$dl_release_dau;
    log_entry.release_dau_block := release_dau_block;
    daus_per_allocation := release_dau_block.daus_per_allocation;
    login_index := release_dau_block.mainframe_assigned.log_in_index;
    dfl_index := release_dau_block.dfl_index;

    dmp$generate_gfn_hash (release_dau_block.global_file_name, file_hash);

    syp$establish_condition_handler (^handler);

    dau_count := p_dat^.header.number_of_entries;

    { validate DAU address.

    IF ((release_dau_block.dau_address + daus_per_allocation) > dau_count) THEN
      dat_change.dau_address := release_dau_block.dau_address;
      dat_change.index := UPPERVALUE (dat_change.index);
      dat_change.kind := dmc$dat_release_dau;
      dat_change.release_dau_block := release_dau_block;
      process_dat_change_error (avt_index, dat_change, 0, p_dat^.body [0], NOT production_logging);
      more_aus := FALSE;
    IFEND;

    WHILE more_aus DO

      { Validate allocation unit.

      first_dau := log_entry.release_dau_block.dau_address;
      last_dau := first_dau + daus_per_allocation - 1;

    /validate_allocation_unit/
      FOR dau := first_dau TO last_dau DO
        dau_entry := p_dat^.body [dau];
        ok := valid_file_dau (dfl_index, file_hash, dau_entry);
        IF NOT ok THEN
          dat_change.dau_address := first_dau;
          dat_change.index := UPPERVALUE (dat_change.index);
          dat_change.kind := dmc$dat_release_dau;
          dat_change.release_dau_block := log_entry.release_dau_block;
          process_dat_change_error (avt_index, dat_change, dau, dau_entry, NOT production_logging);
          more_aus := FALSE;
          EXIT /validate_allocation_unit/; {----->
        IFEND;
      FOREND /validate_allocation_unit/;

      { Create log entry to release allocation unit.

      IF ok THEN
        IF production_logging THEN
          lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
        ELSE
          insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, current_position_in_log,
                status);
        IFEND;
        IF NOT status.normal THEN
          osp$append_status_parameter (osc$status_parameter_delimiter,
                'Unable to process release_dau log entry - release_file_daus.', status);
          ok := FALSE;
        IFEND;
      IFEND;

      { Determine next allocation unit.

      dau_entry := p_dat^.body [first_dau];
      more_aus := ok AND ((dau_entry.allocation_chain_position = dmc$first_allocation) OR
            (dau_entry.allocation_chain_position = dmc$middle_allocation));

      IF more_aus THEN
        IF ((dau_entry.next_allocation_unit_dau + daus_per_allocation) > dau_count) THEN
          more_aus := FALSE;
          dat_change.dau_address := first_dau;
          dat_change.index := UPPERVALUE (dat_change.index);
          dat_change.kind := dmc$dat_release_dau;
          dat_change.release_dau_block := log_entry.release_dau_block;
          process_dat_change_error (avt_index, dat_change, first_dau, dau_entry, NOT production_logging);
        ELSE
          log_entry.release_dau_block.dau_address := dau_entry.next_allocation_unit_dau;
          count := count + 1;
          IF (count >= dmv$continue_purge_limit) THEN
            more_aus := FALSE;

            { Create log entry to continue purge.

            log_entry.kind := dmc$dl_continue_purge;
            IF production_logging THEN
              lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
            ELSE
              insert_dl_entry (login_table_sfid, login_index, log_entry, device_log, current_position_in_log,
                    status);
            IFEND;
            IF NOT status.normal THEN
              osp$append_status_parameter (osc$status_parameter_delimiter,
                    'Continue purge failure - release_file_daus.', status);
            IFEND;
          IFEND;
        IFEND;
      IFEND;
    WHILEND;

    syp$disestablish_cond_handler;

  PROCEND release_file_daus;
?? TITLE := '  sort_dat_changes', EJECT ??

  PROCEDURE sort_dat_changes
    (    p_dat_changes: ^dmt$dat_changes;
         dat_change_count: integer);

    VAR
      gap: integer,
      start: integer,
      current: integer,
      dat_change: dmt$dat_change;

    dmv$running_total_sorts := dmv$running_total_sorts + 1;
    dmv$running_total_entries := dmv$running_total_entries + dat_change_count;

    IF (dat_change_count > dmv$max_sorted_entries) THEN
      dmv$max_sorted_entries := dat_change_count;
    IFEND;

    IF (dat_change_count < dmv$min_sorted_entries) THEN
      dmv$min_sorted_entries := dat_change_count;
    IFEND;

    { Use shell sort technique. }

    gap := dat_change_count;
    WHILE gap > 1 DO
      gap := 2 * (gap DIV 4) + 1;
      FOR start := 1 TO dat_change_count - gap DO
        current := start;

        { WHILE (current > 0) AND (key [current] > key [current + gap]) DO

        WHILE (current > 0) AND ((p_dat_changes^ [current].dau_address >
              p_dat_changes^ [current + gap].dau_address) OR ((p_dat_changes^ [current].dau_address =
              p_dat_changes^ [current + gap].dau_address) AND (p_dat_changes^ [current].index >
              p_dat_changes^ [current + gap].index))) DO
          dmv$running_total_iterations := dmv$running_total_iterations + 1;
          dat_change := p_dat_changes^ [current];
          p_dat_changes^ [current] := p_dat_changes^ [current + gap];
          p_dat_changes^ [current + gap] := dat_change;
          current := current - gap;
        WHILEND;
      FOREND;
    WHILEND;

  PROCEND sort_dat_changes;
?? TITLE := '  update_volume_tables', EJECT ??

  PROCEDURE update_volume_tables
    (    avt_index: dmt$active_volume_table_index;
     VAR status: ost$status);

    VAR
      info: dmt$avt_logging_info,
      recovery_logging: boolean,
      current_log_position: integer,
      p_dat: ^dmt$ms_device_allocation_table,
      p_dfl: ^dmt$ms_device_file_list_table,
      able: boolean,
      log_entry: dmt$dl_entry,
      device_log: dmt$device_log,
      p_dat_changes: ^dmt$dat_changes,
      p_dfl_changes: ^dmt$dfl_changes,
      number_dat_changes: integer,
      number_dfl_changes: integer,
      avt_entry_found: boolean,
      local_status: ost$status,
      recovery_testing_aborts: dmt$dl_recovery_testing_aborts;

    status.normal := TRUE;
    p_dat_changes := NIL;
    p_dfl_changes := NIL;
    number_dfl_changes := 0;
    number_dat_changes := 0;
    current_log_position := 0;

    IF dmv$test_recovery AND (dmc$table_update_inhibited IN
          dmv$active_volume_table.table_p^ [avt_index].mass_storage.disk_table_status) THEN
      RETURN; {----->
    IFEND;

{     split of the allocation log is ok even if the volume is unavailable (or logging_process_damaged)
{     as modified pages are not written out

    dmp$split_allocation_log (FALSE, status);
    IF NOT status.normal THEN
      osp$fatal_system_error ('split allocation log failure - update_volume_tables', ^status);
    IFEND;

    dmp$get_avt_logging_info (avt_index, info, avt_entry_found);
    IF NOT avt_entry_found THEN
      RETURN; {----->
    IFEND;

    IF info.log_entry_count <= dmv$minimum_log_count THEN
      RETURN; {----->
    IFEND;

    IF info.logging_process_damaged THEN {is never cleared except by deadstart
      down_volume (avt_index, FALSE, status);
      IF NOT status.normal THEN
        osp$fatal_system_error ('unable to down volume (1) - update_volume_tables', ^status);
      IFEND;
      RETURN; {----->
    IFEND;

    dmp$open_dat (info.dat_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_sequential, p_dat,
          status);
    IF NOT status.normal THEN
      IF osp$file_access_condition (status) THEN
        status.normal := TRUE;
        RETURN; {----->
      ELSEIF status.condition = mme$io_read_error THEN
        osp$append_status_parameter (osc$status_parameter_delimiter, 'open_dat failure', status);
        dmv$last_volume_downed_status := status;
        down_volume (avt_index, TRUE, status);
        IF NOT status.normal THEN
          osp$fatal_system_error ('unable to down volume (2) - update_volume_tables', ^status);
        IFEND;
        RETURN; {----->
      ELSE
        osp$fatal_system_error ('unable to open dat - update_volume_tables', ^status);
      IFEND;
    IFEND;

    dmp$open_dflt (info.dfl_sfid, osc$os_ring_1, osc$tsrv_ring, mmc$sar_write_extend, mmc$as_sequential,
          p_dfl, status);
    IF NOT status.normal THEN
      dmp$close_file (p_dat, local_status);
      IF osp$file_access_condition (status) THEN
        status.normal := TRUE;
        RETURN; {----->
      ELSEIF status.condition = mme$io_read_error THEN
        osp$append_status_parameter (osc$status_parameter_delimiter, 'open_dflt failure', status);
        dmv$last_volume_downed_status := status;
        down_volume (avt_index, TRUE, status);
        IF NOT status.normal THEN
          osp$fatal_system_error ('unable to down volume (3) - update_volume_tables', ^status);
        IFEND;
        RETURN; {----->
      ELSE
        osp$fatal_system_error ('unable to open dflt - update_volume_tables', ^status);
      IFEND;
    IFEND;

    osp$test_set_main_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock, able);

    IF able THEN
      open_device_log (info.device_log_sfid, FALSE, device_log, status);
      IF status.normal THEN
        log_entry.kind := dmc$dl_start_update;
        lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
        IF NOT status.normal THEN
          osp$fatal_system_error ('bad status inserting log entry (s) - update_volume_tables', ^status);
        IFEND;

        log_entry.kind := dmc$dl_last_update_entry;
        lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
        IF status.normal THEN

          osp$set_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_lock);
          dmv$active_volume_table.table_p^ [avt_index].mass_storage.device_log_entry_count := 0;
          osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.
                logging_lock);

          process_device_log (avt_index, info.mainframe_assigned, p_dat, p_dfl, info.login_table_sfid,
                device_log, TRUE, p_dat_changes, number_dat_changes, p_dfl_changes, number_dfl_changes,
                recovery_testing_aborts, current_log_position, status);
          IF status.normal THEN

            log_entry.kind := dmc$dl_update_disk_tables;
            lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
            IF NOT status.normal THEN
              osp$fatal_system_error ('table update failure (U) - update_volume_tables', ^status);
            IFEND;

            recovery_logging := FALSE;

            process_dat_changes (p_dat, avt_index, number_dat_changes, recovery_logging, p_dat_changes,
                  status);
            IF NOT status.normal THEN
              IF (status.condition = mme$io_read_error) OR (status.condition = mme$io_write_error) THEN
                osp$append_status_parameter (osc$status_parameter_delimiter, 'process_dat failure', status);
                dmv$last_volume_downed_status := status;
                down_volume (avt_index, FALSE, local_status);
                IF NOT local_status.normal THEN
                  osp$fatal_system_error ('unable to down volume (4) - update_volume_tables', ^local_status);
                IFEND;
              ELSEIF osp$file_access_condition (status) THEN
                {  fall through
              ELSE
                osp$fatal_system_error ('process_dat_changes failure - update_volume_tables', ^status);
              IFEND;
              dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_process_damaged := TRUE;
            IFEND;

            IF status.normal THEN
              process_dfl_changes (p_dfl, avt_index, number_dfl_changes, recovery_logging, p_dfl_changes,
                    status);
              IF NOT status.normal THEN
                IF (status.condition = mme$io_read_error) OR (status.condition = mme$io_write_error) THEN
                  osp$append_status_parameter (osc$status_parameter_delimiter, 'process_dflt failure',
                        status);
                  dmv$last_volume_downed_status := status;
                  down_volume (avt_index, FALSE, local_status);
                  IF NOT local_status.normal THEN
                    osp$fatal_system_error ('unable to down volume (5) update_volume_tables', ^local_status);
                  IFEND;
                ELSEIF osp$file_access_condition (status) THEN
                  {  fall through
                ELSE
                  osp$fatal_system_error ('process_dfl_changes failure - update_volume_tables', ^status);
                IFEND;
                dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_process_damaged := TRUE;
              IFEND;
            IFEND;

            IF recovery_testing_aborts = dmc$dl_halt_before_logging_dtu THEN
              osp$fatal_system_error ('HALT FOR RECOVERY TEST', NIL);
            IFEND;

            IF status.normal THEN
              log_entry.kind := dmc$dl_disk_tables_updated;
              lock_log_and_insert_entry (log_entry, avt_index, device_log, status);
              IF NOT status.normal THEN
                osp$fatal_system_error ('bad status inserting log entry (ud) - update_volume_tables',
                      ^status);
              IFEND;
            IFEND;

            status.normal := TRUE;

          ELSEIF (status.condition = mme$io_read_error) OR (status.condition = mme$io_write_error) THEN
            osp$append_status_parameter (osc$status_parameter_delimiter, 'process_device_log failure',
                  status);
            dmv$last_volume_downed_status := status;
            down_volume (avt_index, FALSE, local_status);
            IF NOT local_status.normal THEN
              osp$fatal_system_error ('unable to down volume (6) - update_volume_tables', ^local_status);
            IFEND;
            dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_process_damaged := TRUE;
            status.normal := TRUE;
          ELSEIF status.condition = dme$volume_unavailable THEN
            dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_process_damaged := TRUE;
            status.normal := TRUE;
          ELSE { process_device_log failure
            osp$fatal_system_error ('process log failure - update_volume_tables', ^status);
          IFEND;

        ELSE { couldn't insert last_update_entry - unsure if login table written, so damage=yes

          osp$append_status_parameter (osc$status_parameter_delimiter, 'last insertion failure', status);
          dmv$last_volume_downed_status := status;
          down_volume (avt_index, FALSE, local_status);
          IF NOT local_status.normal THEN
            osp$fatal_system_error ('unable to down volume (7) - update_volume_tables', ^local_status);
          IFEND;
          dmv$active_volume_table.table_p^ [avt_index].mass_storage.logging_process_damaged := TRUE;
          status.normal := TRUE;
        IFEND;

        dmp$close_file (device_log, local_status);

      ELSEIF status.condition = dme$volume_unavailable THEN { couldn't open device_log
        status.normal := TRUE;
      IFEND;

      osp$clear_mainframe_sig_lock (dmv$active_volume_table.table_p^ [avt_index].mass_storage.update_lock);
    IFEND;

    dmp$close_file (p_dfl, local_status);
    dmp$close_file (p_dat, local_status);

  PROCEND update_volume_tables;
?? TITLE := '  valid_dfl_index', EJECT ??

  FUNCTION [INLINE] valid_dfl_index
    (    dfl_index: dmt$device_file_list_index;
         p_dfl: ^dmt$ms_device_file_list_table): boolean;

    valid_dfl_index := (dfl_index >= LOWERBOUND (p_dfl^.entries)) AND
          (dfl_index <= UPPERBOUND (p_dfl^.entries));

  FUNCEND valid_dfl_index;
?? TITLE := '  valid_file_dau', EJECT ??

  FUNCTION [INLINE] valid_file_dau
    (    dfl_index: dmt$device_file_list_index;
         file_hash: dmt$file_hash;
         dau_entry: dmt$ms_device_allocation_unit): boolean;

    VAR
      ok: boolean,
      dfl_known: boolean;

    ok := ((dau_entry.dau_status = dmc$dau_assigned_to_file) OR
          (dau_entry.dau_status = dmc$dau_ass_to_file_swr_flawed)) AND
          ((dau_entry.file_hash = file_hash) OR (gff$old_file_hash (dau_entry.file_hash) =
          gff$old_file_hash (file_hash)));

    IF ok THEN
      dfl_known := (dau_entry.allocation_chain_position = dmc$last_allocation) OR
            (dau_entry.allocation_chain_position = dmc$first_and_last_allocation);
      ok := NOT dfl_known OR (dfl_index = (dau_entry.high_dfl_index *
            dmc$dfl_index_converter + dau_entry.low_dfl_index));
    IFEND;

    valid_file_dau := ok;

  FUNCEND valid_file_dau;
?? TITLE := '  valid_file_dfl', EJECT ??

  FUNCTION [INLINE] valid_file_dfl
    (    gfn: dmt$global_file_name;
         dfl_entry: dmt$ms_device_file_list_entry): boolean;

    valid_file_dfl := (dfl_entry.flags = dmc$dfle_assigned_to_file) AND (dfl_entry.global_file_name = gfn);

  FUNCEND valid_file_dfl;
?? TITLE := '  valid_mainframe_dau', EJECT ??

  FUNCTION [INLINE] valid_mainframe_dau
    (    mainframe: dmt$mainframe_assigned;
         dau_entry: dmt$ms_device_allocation_unit): boolean;

    valid_mainframe_dau := ((dau_entry.dau_status = dmc$dau_assigned_to_mainframe) OR
          (dau_entry.dau_status = dmc$dau_ass_to_mf_swr_flawed)) AND (dau_entry.mainframe_id = mainframe);

  FUNCEND valid_mainframe_dau;
?? TITLE := '  valid_mainframe_dfl', EJECT ??

  FUNCTION [INLINE] valid_mainframe_dfl
    (    mainframe: dmt$mainframe_assigned;
         dfl_entry: dmt$ms_device_file_list_entry): boolean;

    valid_mainframe_dfl := (dfl_entry.flags = dmc$dfle_assigned_to_mainframe) AND
          (dfl_entry.mainframe_assigned = mainframe);

  FUNCEND valid_mainframe_dfl;

MODEND dmm$logger;

