Multics > Library > Source
19 Nov 1982

activate.pl1

This Multics source file was rescued from the messed-up source archive at MIT.

This is the piece of segment control that makes an AST entry for a segment and brings its page table into core.

This hardcore module ends with a special comment that starts with "BEGIN MESSAGE DOCUMENTATION." A program was run over the hardcore source to extract and process these comments into a manual that explained each message the system could produce on the operator's console. This manual was regenerated for each release.

Back to Multics Source index.

                    activate.pl1                    11/19/82  1530.9r w 11/19/82  1528.6      13113



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1982 *
   *                                                         *
   * Copyright (c) 1972 by Massachusetts Institute of        *
   * Technology and Honeywell Information Systems, Inc.      *
   *                                                         *
   *********************************************************** */


/*
   astep = activate (branchp, code)




   FUNCTION -

   This procedure activates the segment whose branch is pointed  to  by  the  input
   argument  "branchp",  and it returns the aste pointer for that segment. In order
   to activate the segment this procedure activates  any  superior  directory  that
   happens  to  be inactive. If the operation is successful, the return occurs with
   the following state: astep ^= null, code = 0  and  AST  is  locked.  It  is  the
   responsability  of  the  caller to unlock the AST whenever it is appropriate. If
   the operation fails, the return occurs with the following state: astep  =  null,
   code ^= 0 and AST is unlocked.


   MODIFICATIONS -

   10/26/82 by J. Bongiovanni for synchronized segments, filemap checksum
   7/10/82 by J. Bongiovanni to read entire VTOCE
   3/7/82 by J. Bongiovanni for new PVTE
   12/25/81 by Benson I. Margulies to not depend on the directory read
          lock as protection against activations.
   5/31/81 by J. Bongiovanni to validate fields in VTOCE
   03/21/81, W. Olin Sibert, for ADP PTWs and SDWs, and get_ptrs_$given_sdw
   02/81 by E. N. Kittlitz for activate_long entry
   04/77 by THVV for damaged sw and messages
   8/76 by D. Vinograd to add entry for activating without parent being active.
   This entry, backup_activate, is used only by the volume dumper.
   09/13/76 by Greenberg to meter activations and fixe demount window error reporting
   03/25/76 by R. Bratt to fix gtpd bug and add explicit user deactive capability
   04/08/75 by Andre Bensoussan. This procedure has been completely rewritten for
   the new storage system.
*/


%page;
activate: proc (branchp, code) returns (ptr);


dcl  branchp ptr,                                       /* Input  - branch pointer */
     a_vtocep ptr,
     a_pvtx fixed bin,
     a_vtocx fixed bin,
     a_activated_sw bit (1) aligned,
     code fixed bin (35);                               /* Output - error code */


dcl (par_astep, par_sdwp) ptr;
dcl (i, pts, ptsi, pvtx, vtocx, esw) fixed bin (17);
dcl (uid, pvid, temp) bit (36) aligned;
dcl  old_par_ehs bit (1);
dcl  already_active_by_backup bit (1);
dcl  dirsw bit (1);
dcl  parts bit (3);
dcl  long_sw bit (1) aligned;
dcl 1 local_vtoce like vtoce aligned;
dcl 1 par_aste like aste aligned based (par_astep);
dcl  checksum bit (36) aligned;
dcl  p99 pic "99";

dcl  normal fixed bin internal static init (1);
dcl  backup fixed bin internal static init (2);

dcl  dseg$ (0 : 1023) fixed bin (71) external static;
dcl  error_table_$synch_seg_limit fixed bin (35) ext;
dcl  error_table_$vtoce_connection_fail fixed bin (35) ext;
dcl  error_table_$pvid_not_found ext fixed bin (35);
dcl  error_table_$illegal_activation fixed bin (35) ext;
dcl  error_table_$invalid_vtoce fixed bin (35) ext;
dcl  error_table_$dm_not_enabled fixed bin (35) ext;

dcl  pc$fill_page_table entry (ptr, ptr, fixed bin);
dcl  get_aste entry (fixed bin) returns (ptr);
dcl  get_aste$synchronized entry (fixed bin) returns (ptr);
dcl  lock$lock_ast entry;
dcl  lock$unlock_ast entry;
dcl  search_ast entry (bit (36) aligned) returns (ptr);
dcl  search_ast$hash_in entry (ptr);
dcl  get_pvtx entry (bit (36) aligned, fixed bin (35)) returns (fixed bin);
dcl  vtoc_man$get_vtoce entry (bit (36) aligned, fixed bin, fixed bin, bit (3), ptr, fixed bin (35));
dcl  get_ptrs_$given_sdw entry (pointer) returns (pointer);
dcl  filemap_checksum_ entry (ptr, fixed bin, bit (36) aligned);
dcl  sdw_util_$get_valid entry (pointer) returns (bit (1) aligned);
dcl  trace entry options (variable);
dcl  syserr entry options (variable);
dcl  syserr$binary entry options (variable);

dcl (addr, baseno, bin, convert, dim, divide, fixed, null, 
     ptr, rel, reverse, substr, verify) builtin;
                                                /*  */
        long_sw = "0"b;
        goto START;


/* activate_long is the same as activate, except that extra information
   is returned to the caller. */

activate_long: entry (branchp, a_activated_sw, code) returns (ptr);

        long_sw = "1"b;
        a_activated_sw = "0"b;

START:
        ep = branchp;
        dp = ptr (ep, 0);
        uid = entry.uid;
        pvid = entry.pvid;
        vtocx = entry.vtocx;
        dirsw = entry.dirsw;
        temp_entry_name = addr (ep -> entry.primary_name) -> names.name;
        pvtx = get_pvtx (pvid, code);
        if code ^= 0 then return (null);
        esw = normal;

COMMON:
        code = 0;
        already_active_by_backup = "0"b;
        sstp = addr (sst_seg$);
        pvt_arrayp = addr (pvt$array);
        pvtep = addr (pvt_array (pvtx));
        call lock$lock_ast;

/**** before multi-read directory locks, the directory lock was
      sufficient to protect against another processor making an activation.
      Thus the code below could unlock the AST, do VTOC I/O, and lock
      the AST, secure in the knowledge that nobody else was going
      to do the same thing while it was waiting for the I/O. This
      had the additional side effect of locking out any directory
      accesses for the duration.

      Now, the AST hash table is searched a second time after
      the AST is relocked after the VTOC I/O. If the uid is found,
      the code go-to's to ACTIVATED_BY_SOMEONE_ELSE to rejoin
      the same sequence that it would have taken had the segment
      been active to begin with.

      Under the new locking strategy, a program that wishes to protect
      against activations in a directory MUST HOLD A WRITE LOCK ON
      THAT DIRECTORY, or some higher lock.
****/

        astep = search_ast (uid);
        if astep ^= null then 
ACTIVATED_BY_SOMEONE_ELSE: 
        do;
             if (aste.pvtx ^= pvtx) | (aste.vtocx ^= vtocx) then do;
                call syserr (LOG, "activate: double uid ^w. vtocx ^o on ^a. vtocx ^o on ^a",
                     uid, vtocx, pvte.devname || "_" || convert (p99, pvte.logical_area_number),
                     aste.vtocx, pvt_array (aste.pvtx).devname || "_" || convert (p99, pvt_array (aste.pvtx).logical_area_number));
                code = error_table_$vtoce_connection_fail;
ret_ulast:      call lock$unlock_ast;
                return (null);
             end;
             if aste.par_astep ^= "0"b | aste.uid = (36)"1"b then return (astep); /* the normal case */
             already_active_by_backup = "1"b;           /* set switch */
        end;
        if esw = normal then do;
             if ^already_active_by_backup then do;
                call lock$unlock_ast;
                vtocep = addr (local_vtoce);
                call vtoc_man$get_vtoce (pvid, pvtx, vtocx, "111"b, vtocep, code);
                if code ^= 0 then return (null);
                if vtoce.uid ^= uid then code = error_table_$vtoce_connection_fail;
                else if vtoce.dirsw ^= dirsw | vtoce.deciduous then do;
                     code = error_table_$vtoce_connection_fail;
                     call syserr (LOG, "activate: error on ^[deciduous ^]^[dir ^]^a",
                        vtoce.deciduous, vtoce.dirsw, temp_entry_name);
                end;
                else code = 0;
                if code ^= 0 then return (null);
                call lock$lock_ast;
                /* now check to make sure it hasn't been activated
                   while we were VTOCE reading */
                astep = search_ast (uid);
                if astep ^= null
                then go to ACTIVATED_BY_SOMEONE_ELSE;
             end;

             par_sdwp = addr (dseg$ (fixed (baseno (dp), 18))); /* ptr to parent sdw */
             do while (sdw_util_$get_valid (par_sdwp) = "0"b); /* If parent active */
                call lock$unlock_ast;           /* Unlock the global lock */
                temp = dp -> dir.uid;           /* Cause a segfault on parent dir */
                call lock$lock_ast;                     /* relock */
             end;
             if (pvte.pvid ^= pvid) | pvte.being_demounted then do;
                code = error_table_$pvid_not_found;     /* Check demount with AST locked */
                go to ret_ulast;
             end;

             par_astep = get_ptrs_$given_sdw (par_sdwp);

             old_par_ehs = par_aste.ehs;                /* Save old ehs on parent */
             par_aste.ehs = "1"b;                       /* Do not let son deactivate his father */

             if already_active_by_backup then do;
                aste.par_astep = rel (par_astep);       /* set parent astep */
                aste.infl = par_aste.infp;
                par_aste.infp = rel (astep);
                aste.per_process = par_aste.per_process;
                par_aste.ehs = old_par_ehs;
                return (astep);                 /* not that hard */
             end;
        end;

/* validate some fields in the VTOCE which could really kill us
   if they're bogus                                                                             */

        if fixed (vtoce.records) > fixed (vtoce.csl)
             | fixed (vtoce.csl) > fixed (vtoce.msl)
             | fixed (vtoce.msl) > dim (vtoce.fm, 1)
             then do;
             code = error_table_$invalid_vtoce;
             goto ret_ulast;
        end;

/*  checksum the file map  */

        if vtoce.fm_checksum_valid & (sst.checksum_filemap ^= 0)
             & ^vtoce.fm_damaged then do;
             call filemap_checksum_ (addr (vtoce.fm), fixed (vtoce.csl, 9), checksum);
             if vtoce.fm_checksum ^= checksum then do;
                segdamage.pvid = pvte.pvid;
                segdamage.lvid = pvte.lvid;
                segdamage.uid = vtoce.uid;
                segdamage.vtocx = vtocx;
                segdamage.pno = -1;
                segdamage.uid_path = vtoce.uid_path;
                call syserr$binary (LOG, addr (segdamage), SB_vtoc_salv_dam, SBL_vtoc_salv_dam,
                     "activate: Setting damaged switch on ^a at ^o (^a). Filemap damaged.",
                     vtoce.primary_name, vtocx, pvte.devname || "_" || convert (p99, pvte.logical_area_number));
                vtoce.damaged = "1"b;
                vtoce.fm_damaged = "1"b;
                sst.damaged_ct = sst.damaged_ct + 1;
                pvte.vol_trouble_count = pvte.vol_trouble_count + 1;
             end;
        end;

        if ^vtoce.synchronized then do;         /* Normal case */
             astep = get_aste (fixed (vtoce.csl));
             if astep = null() then do;
                code = error_table_$illegal_activation;
                goto ret_ulast;
             end;
        end;
        else do;                                        /* Synchronized segment */
             if ^sst.dm_enabled then do;                /* No journal */
                code = error_table_$dm_not_enabled;
                goto ret_ulast;
             end;
             astep = get_aste$synchronized (fixed (vtoce.csl));
             if astep = null () then do;
                code = error_table_$synch_seg_limit;
                goto ret_ulast;
             end;
        end;
        

        if esw = normal then do;
             if astep = par_astep then call syserr (CRASH, "activate: activating into father ^p", astep);
             par_aste.ehs = old_par_ehs;

/*      aste.fp, aste.bp        = have been set by get_aste or deactivate  */
             aste.infl = par_aste.infp;
             par_aste.infp = rel (astep);
             aste.par_astep = rel (par_astep);
             aste.per_process = par_aste.per_process;   /* Inherit this one */
        end;
        /*      aste.uid = uid; */                      /* dont fill in now -protect against shutdown */
        aste.msl = vtoce.msl;
        aste.pvtx = pvtx;
        aste.vtocx = vtocx;
        aste.usedf = "1"b;
        aste.gtus = "1"b;
        aste.gtms = "1"b;
        aste.explicit_deact_ok = "1"b;
        aste.dnzp = vtoce.dnzp;
        aste.damaged = vtoce.damaged;
        aste.fm_damaged = vtoce.fm_damaged;
        aste.synchronized = vtoce.synchronized;
        aste.nqsw = vtoce.nqsw;
        aste.dirsw = vtoce.dirsw;
        aste.dtu = vtoce.dtu;
        aste.dtm = vtoce.dtm;
        aste.csl = vtoce.csl;
        aste.nid = vtoce.nid;
        aste.records = vtoce.records;

        sst.activations = sst.activations + 1;
        if esw = backup then
             sst.backup_activations = sst.backup_activations + 1;
        if long_sw then
             a_activated_sw = "1"b;                     /* indicate activation occured */
        if dirsw then do;
             aste.master_dir = vtoce.master_dir;
             aste.quota = vtoce.quota;
             aste.used = vtoce.used;
             aste.tqsw (0) = vtoce.received (0) ^= 0 | vtoce.master_dir;
             aste.tqsw (1) = vtoce.received (1) ^= 0;
             sst.dir_activations = sst.dir_activations + 1;
        end;
        else seg_aste.usage = seg_vtoce.usage;          /* Segments have no quota. keep pf count */

        call pc$fill_page_table (astep, addr (vtoce.fm), fixed (vtoce.csl)); /* fill in page table */

        aste.uid = uid;                         /* aste is stable now */

        call search_ast$hash_in (astep);

        nm_astep = astep;

        %include make_sstnt_entry;

        return (astep);                         /* return a pointer to the new AST entry */

/*  */

backup_activate: entry (a_vtocep, a_vtocx, a_pvtx, code) returns (ptr);

        esw = backup;
        long_sw = "0"b;
        vtocep = a_vtocep;
        pvtx = a_pvtx;
        vtocx = a_vtocx;
        uid = vtoce.uid;                                /* set local variables */
        dirsw = vtoce.dirsw;
        temp_entry_name = vtoce.primary_name;
        goto COMMON;                            /* with multiple entries you have to have one label */

%page; %include aste;
%page; %include dir_entry;
%page; %include dir_header;
%page; %include dir_name;
%page; %include pvte;
%page; %include segdamage_msg;
%page; %include sst;
%page; %include sstnt;
%page; %include syserr_binary_def;
%page; %include syserr_constants;
%page; %include vtoce;

%page;

/* BEGIN MESSAGE DOCUMENTATION

   Message:
   activate: double uid UUUU. vtocx N on dskX_MM. vtocx P on dskY_QQ.

   S:   $log

   T:   $run

   M:   A mismatch has been detected between
   the branch and the ASTE for a segment. The two segments indicated
   by VTOCE index and physical volume name claim to have the same
   file system unique identifier.
   A connection failure is returned to the user process.
   This message is logged for the use of system programmers.

   This error can occur if damage to
   a directory branch has caused
   its unique ID to become incorrect,
   and if the incorrect unique ID happens to be
   identical to the unique ID of a segment already active.

   A:   $inform


   Message:
   activate: error on (deciduous) (dir) NAME

   S:   $log

   T:   $run

   M:   An attempt has been made to activate a
   deciduous segment,
   or to activate a segment
   when the VTOCE's directory switch did not match the branch.
   A connection failure is returned to the user process.
   This information is logged for the use of system programmers.

   A:   $ignore


   Message:
   activate: activating into father PPPP

   S:   $crash

   T:   $run
   M:   The AST entry pointer returned by get_aste
   is identical to the AST entry pointer for the parent of the segment being activated.
   $err
   $crashes

   A:   $recover


   Message:
   activate: Setting damaged switch on NAME at VTOCX (dskX_NN). Filemap damaged.

   S:     $log

   T:   $run

   M:   The segment's File Map in the VTOCE had an invalid checksum, which
   indicates likely damage to the File Map. The segment is marked as damaged.
   It is possible that there is other damage on the physical volume due
   to invalid or reused disk addresses. The count of volume inconsistencies is
   incremented by 1.

   A:      Examine the VTOCE for damage using dump_vtoce. If other damage
   is evident, delete it using hp_delete_vtoce -clear and recover the
   segment. Run the physical volume scavenger as soon as possible to
   detect and correct other damage on the physical volume.

   
   END MESSAGE DOCUMENTATION */

     end activate;

"This material is presented to ensure dissemination of scholarly and technical work. Copyright and all rights therein are retained by authors or by other copyright holders. All persons copying this information are expected to adhere to the terms and constraints invoked by each author's copyright. In most cases, these works may not be reposted without the explicit permission of the copyright holder."