?? RIGHT := 110 ??
?? TITLE := 'NOS/VE : Device Management - dmm$fetch_page_status' ??
MODULE dmm$fetch_page_status;
?? RIGHT := 110 ??

{ PURPOSE:
{   This module contain the following procedures:
{
{      dmp$fetch_page_status - used by memory manager to determine whether a
{           page is on disk or is a new page to be created.
{      dmp$fetch_multi_page_status - used by memory  manager to check
{           page status on a range of pages.
{

?? NEWTITLE := 'Global Declarations Referenced By This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc osd$virtual_address
*copyc dmt$file_allocation_status
*copyc dmt$file_descriptor_entry
*copyc gft$page_status
*copyc sft$file_space_limit_kind
?? POP ??
*copyc dmp$allocate_file_space
*copyc dmp$get_disk_file_descriptor_p
*copyc dmp$get_fau_entry
*copyc dmp$get_fmd_by_index
*copyc mtp$error_stop
*copyc dmv$active_volume_table
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared By This Module', EJECT ??

{ The following variable contains the number of unavailable volumes. If no volumes
{ are unavailable, then some checks can be skipped.

  VAR
    dmv$number_unavailable_volumes: [XDCL, #GATE] dmt$active_volume_table_index := 0;

?? OLDTITLE ??
?? NEWTITLE := '  [XDCL] dmp$fetch_page_status', EJECT ??
{
{ PURPOSE:
{    This procedure is used by memory manager to determine the residency of a page.
{    If the page is on disk, MM will issue IO requests to read the page; if the page
{    is not on disk, before creating a new page, MM must ensure that the page
{    can be written to disk. This requires space to be allocated.
{
{    If the space resides on a down-volume or if the space cannot be allocated, an
{    error is returned

  PROCEDURE [XDCL] dmp$fetch_page_status
    (    fde_p: gft$locked_file_desc_entry_p;
         offset: ost$segment_offset; {will be on page boundary}
         enforce_limits: sft$file_space_limit_kind;
         allow_allocation: boolean;
     VAR page_status: gft$page_status);

    VAR
      allocate_status: dmt$file_allocation_status,
      dfd_p: ^dmt$disk_file_descriptor,
      fau_entry_p: ^dmt$file_allocation_unit,
      fmd_p: ^dmt$file_medium_descriptor,
      overflow: boolean,
      units_obtained: amt$file_byte_address;


{ Get pointers to tables. If no FAT entry is assigned, reject and fix it in job mode.

    dmp$get_disk_file_descriptor_p (fde_p, dfd_p);
    dmp$get_fau_entry (dfd_p, offset, fau_entry_p);
    IF fau_entry_p = NIL THEN
      page_status := gfc$ps_job_mode_work_required;
      RETURN; {----->
    IFEND;

{ If no volumes are unavailable, the check of the FMD can be skipped. Otherwise, look at
{ the FMD/AVT and determine if the page resides on an unavailable volume.

    IF (dmv$number_unavailable_volumes > 0) AND (fau_entry_p^.state > dmc$fau_free) THEN
      dmp$get_fmd_by_index (dfd_p, fau_entry_p^.fmd_index, fmd_p);
      IF dmv$active_volume_table.table_p^ [fmd_p^.avt_index].mass_storage.volume_unavailable THEN
        page_status := gfc$ps_volume_unavailable;
        RETURN; {----->
      IFEND;
    IFEND;


{ Determine page status from the FAU status. If no space assigned and the caller wants allocation,
{ call the allocator to assign space.

    CASE fau_entry_p^.state OF
    = dmc$fau_invalid_data, dmc$fau_invalid_and_flawed, dmc$fau_initialization_in_prog =
      page_status := gfc$ps_page_doesnt_exist;

    = dmc$fau_initialized, dmc$fau_initialized_and_flawed =
      IF offset < fde_p^.eoi_byte_address THEN
        page_status := gfc$ps_page_on_disk;
      ELSE
        page_status := gfc$ps_page_doesnt_exist;
      IFEND;

    = dmc$fau_free =
      page_status := gfc$ps_page_doesnt_exist;
      IF allow_allocation THEN
        dmp$allocate_file_space (fde_p, offset, 1, enforce_limits, units_obtained, overflow, allocate_status);

        CASE allocate_status OF
        = dmc$fas_file_allocated =
        = dmc$fas_temp_reject =
          page_status := gfc$ps_temp_reject;
        = dmc$fas_account_limit_exceeded =
          page_status := gfc$ps_account_limit_exceeded;
        = dmc$fas_job_mode_work_required =
          page_status := gfc$ps_job_mode_work_required;
        ELSE
          mtp$error_stop ('bad allocate status');
        CASEND;
      IFEND;

    ELSE
      mtp$error_stop ('bad fau status - dmp$fetch_page_status');
    CASEND;

  PROCEND dmp$fetch_page_status;

?? OLDTITLE ??
?? NEWTITLE := '  [XDCL] dmp$fetch_multi_page_status', EJECT ??
{
{ PURPOSE:
{    This procedure verifies that a range of pages resides on accessible volumes.
{    Space is assigned if it is not already assigned.
{    If the space is on a down-volume or if space cannot be assigned, a reject is returned.
{
{    This request is similar to DMP$FETCH_PAGE_STATUS except that it does not return
{    information about whether pages are on disk.
{
{   !NOTE - performance of this request can be improved if necessary.
{

  PROCEDURE [XDCL] dmp$fetch_multi_page_status
    (    fde_p: gft$locked_file_desc_entry_p;
         offset: ost$segment_offset; {will be on page boundary}
         length: ost$segment_length; {will be multiple of page size
         enforce_limits: sft$file_space_limit_kind;
     VAR reject_offset: ost$segment_offset;
     VAR page_status: gft$page_status);

    VAR
      allocation_unit_size: integer,
      current_offset: integer,
      last_offset: integer;

    allocation_unit_size := fde_p^.allocation_unit_size;
    current_offset := (offset DIV allocation_unit_size) * allocation_unit_size;
    last_offset := ((offset + length - 1) DIV allocation_unit_size) * allocation_unit_size;

    REPEAT
      dmp$fetch_page_status (fde_p, current_offset, enforce_limits, TRUE, page_status);
      IF (page_status <> gfc$ps_page_doesnt_exist) AND (page_status <> gfc$ps_page_on_disk) THEN
        reject_offset := current_offset;
        RETURN; {----->
      IFEND;
      current_offset := current_offset + allocation_unit_size;
    UNTIL current_offset > last_offset;

  PROCEND dmp$fetch_multi_page_status;

?? OLDTITLE ??
MODEND dmm$fetch_page_status;
