1 /****^  ***********************************************************
  2         *                                                         *
  3         * Copyright, (C) Honeywell Bull Inc., 1987                *
  4         *                                                         *
  5         * Copyright, (C) Honeywell Information Systems Inc., 1982 *
  6         *                                                         *
  7         * Copyright (c) 1972 by Massachusetts Institute of        *
  8         * Technology and Honeywell Information Systems, Inc.      *
  9         *                                                         *
 10         *********************************************************** */
 11 
 12 
 13 
 14 /****^  HISTORY COMMENTS:
 15   1) change(86-05-13,GJohnson), approve(86-05-13,MCR7387),
 16      audit(86-05-13,Martinson), install(86-05-14,MR12.0-1056):
 17      Correct error message documentation.
 18   2) change(86-05-28,Fawcett), approve(86-04-11,MCR7383),
 19      audit(86-05-28,Coppola), install(86-07-17,MR12.0-1097):
 20      Add support for subvolumes.
 21                                                    END HISTORY COMMENTS */
 22 
 23 /*
 24    astep = activate (branchp, code)
 25 
 26    FUNCTION -
 27 
 28    This procedure activates the segment whose branch is pointed  to  by  the  input
 29    argument  "branchp",  and it returns the aste pointer for that segment. In order
 30    to activate the segment this procedure activates  any  superior  directory  that
 31    happens  to  be inactive. If the operation is successful, the return occurs with
 32    the following state: astep ^= null, code = 0  and  AST  is  locked.  It  is  the
 33    responsability  of  the  caller to unlock the AST whenever it is appropriate. If
 34    the operation fails, the return occurs with the following state: astep  =  null,
 35    code ^= 0 and AST is unlocked.
 36 
 37 
 38    MODIFICATIONS -
 39 
 40    85-01-04 by Keith Loepere to set aste.multi_class.
 41    84-01-31 by BIM. SST reformat. Close window due to extra AST unlock for
 42    parent segfault that I missed the first time.
 43    05/30/83 by E. N. Kittlitz for search_ast$check
 44    10/26/82 by J. Bongiovanni for synchronized segments, filemap checksum
 45    7/10/82 by J. Bongiovanni to read entire VTOCE
 46    3/7/82 by J. Bongiovanni for new PVTE
 47    12/25/81 by Benson I. Margulies to not depend on the directory read
 48    lock as protection against activations.
 49    5/31/81 by J. Bongiovanni to validate fields in VTOCE
 50    03/21/81, W. Olin Sibert, for ADP PTWs and SDWs, and get_ptrs_$given_sdw
 51    02/81 by E. N. Kittlitz for activate_long entry
 52    04/77 by THVV for damaged sw and messages
 53    8/76 by D. Vinograd to add entry for activating without parent being active.
 54    This entry, backup_activate, is used only by the volume dumper.
 55    09/13/76 by Greenberg to meter activations and fixe demount window error reporting
 56    03/25/76 by R. Bratt to fix gtpd bug and add explicit user deactive capability
 57    04/08/75 by Andre Bensoussan. This procedure has been completely rewritten for
 58    the new storage system.
 59 */
 60 /* format: style4 */
 61 %page;
 62 
 63 activate: proc (branchp, code) returns (ptr);
 64 
 65 
 66 dcl  branchp ptr,                                           /* Input  - branch pointer */
 67      a_vtocep ptr,
 68      a_pvtx fixed bin,
 69      a_vtocx fixed bin,
 70      a_activated_sw bit (1) aligned,
 71      code fixed bin (35);                                   /* Output - error code */
 72 
 73 
 74 dcl  ast_unlocked bit (1) aligned;
 75 dcl  (par_astep, par_sdwp) ptr;
 76 dcl  (pvtx, vtocx, esw) fixed bin (17);
 77 dcl  (uid, pvid, temp) bit (36) aligned;
 78 dcl  old_par_ehs bit (1);
 79 dcl  already_active_by_backup bit (1);
 80 dcl  dirsw bit (1);
 81 dcl  multi_class bit (1);
 82 
 83 dcl  long_sw bit (1) aligned;
 84 dcl  1 local_vtoce like vtoce aligned;
 85 dcl  1 par_aste like aste aligned based (par_astep);
 86 dcl  checksum bit (36) aligned;
 87 dcl  p99 pic "99";
 88 
 89 dcl  normal fixed bin internal static init (1);
 90 dcl  backup fixed bin internal static init (2);
 91 
 92 dcl  sst$checksum_filemap fixed bin (35) external static;
 93 dcl  sst$damaged_ct fixed bin (35) external static;
 94 dcl  sst$dm_enabled bit (1) aligned external static;
 95 dcl  sst$activations fixed bin (35) external static;
 96 dcl  sst$backup_activations fixed bin (35) external static;
 97 dcl  sst$dir_activations fixed bin (35) external static;
 98 dcl  dseg$ (0:1023) fixed bin (71) external static;
 99 dcl  error_table_$synch_seg_limit fixed bin (35) ext;
100 dcl  error_table_$vtoce_connection_fail fixed bin (35) ext;
101 dcl  error_table_$pvid_not_found ext fixed bin (35);
102 dcl  error_table_$illegal_activation fixed bin (35) ext;
103 dcl  error_table_$invalid_vtoce fixed bin (35) ext;
104 dcl  error_table_$dm_not_enabled fixed bin (35) ext;
105 
106 dcl  pc$fill_page_table entry (ptr, ptr, fixed bin);
107 dcl  get_aste entry (fixed bin) returns (ptr);
108 dcl  get_aste$synchronized entry (fixed bin) returns (ptr);
109 dcl  lock$lock_ast entry;
110 dcl  lock$unlock_ast entry;
111 dcl  search_ast$check entry (bit (36) aligned, bit (36) aligned, fixed bin, fixed bin (35)) returns (ptr);
112 dcl  search_ast$hash_in entry (ptr);
113 dcl  get_pvtx entry (bit (36) aligned, fixed bin (35)) returns (fixed bin);
114 dcl  vtoc_man$get_vtoce entry (bit (36) aligned, fixed bin, fixed bin, bit (3), ptr, fixed bin (35));
115 dcl  get_ptrs_$given_sdw entry (pointer) returns (pointer);
116 dcl  filemap_checksum_ entry (ptr, fixed bin, bit (36) aligned);
117 dcl  sdw_util_$get_valid entry (pointer) returns (bit (1) aligned);
118 dcl  syserr entry options (variable);
119 dcl  syserr$binary entry options (variable);
120 
121 dcl  (addr, baseno, bin, convert, dim, divide, fixed, null,
122      ptr, rel, rtrim) builtin;
123 %page;
124           long_sw = "0"b;
125           goto START;
126 
127 
128 /* activate_long is the same as activate, except that extra information
129    is returned to the caller. */
130 
131 activate_long: entry (branchp, a_activated_sw, code) returns (ptr);
132 
133           long_sw = "1"b;
134           a_activated_sw = "0"b;
135 
136 START:
137           ep = branchp;
138           dp = ptr (ep, 0);
139           uid = entry.uid;
140           pvid = entry.pvid;
141           vtocx = entry.vtocx;
142           dirsw = entry.dirsw;
143           multi_class = entry.multiple_class;
144           temp_entry_name = addr (ep -> entry.primary_name) -> names.name;
145           pvtx = get_pvtx (pvid, code);
146           if code ^= 0 then return (null);
147           esw = normal;
148 
149 COMMON:
150           code = 0;
151           already_active_by_backup = "0"b;
152           pvt_arrayp = addr (pvt$array);
153           pvtep = addr (pvt_array (pvtx));
154           call lock$lock_ast;
155 
156 /**** before multi-read directory locks, the directory lock was
157       sufficient to protect against another processor making an activation.
158       Thus the code below could unlock the AST, do VTOC I/O, and lock
159       the AST, secure in the knowledge that nobody else was going
160       to do the same thing while it was waiting for the I/O. This
161       had the additional side effect of locking out any directory
162       accesses for the duration.
163 
164       Now, the AST hash table is searched a second time after
165       the AST is relocked after the VTOC I/O. If the uid is found,
166       the code go-to's to ACTIVATED_BY_SOMEONE_ELSE to rejoin
167       the same sequence that it would have taken had the segment
168       been active to begin with.
169 
170       Under the new locking strategy, a program that wishes to protect
171       against activations in a directory MUST HOLD A WRITE LOCK ON
172       THAT DIRECTORY, or some higher lock.
173 ****/
174 
175           astep = search_ast$check (uid, pvid, vtocx, code);
176 ACTIVATED_BY_SOMEONE_ELSE:
177           if code ^= 0 then                                 /* double uid */
178                do;
179 ret_ulast:     call lock$unlock_ast;
180                return (null);
181           end;
182           ast_unlocked = "0"b;
183           if astep ^= null then
184                do;
185                if aste.par_astep ^= "0"b | aste.uid = (36)"1"b then do;
186                     aste.multi_class = multi_class;         /* update after possible setfaults */
187                     return (astep);                         /* the normal case */
188                end;
189                already_active_by_backup = "1"b;             /* set switch */
190           end;
191           if esw = normal then do;
192                if ^already_active_by_backup then do;
193                     ast_unlocked = "1"b;
194                     call lock$unlock_ast;
195                     vtocep = addr (local_vtoce);
196                     call vtoc_man$get_vtoce (pvid, pvtx, vtocx, "111"b, vtocep, code);
197                     if code ^= 0 then return (null);
198                     if vtoce.uid ^= uid then code = error_table_$vtoce_connection_fail;
199                     else if vtoce.dirsw ^= dirsw | vtoce.deciduous then do;
200                          code = error_table_$vtoce_connection_fail;
201                          call syserr (LOG, "activate: error on ^[deciduous ^]^[dir ^]^a",
202                               vtoce.deciduous, vtoce.dirsw, temp_entry_name);
203                     end;
204                     else code = 0;
205                     if code ^= 0 then return (null);
206                     call lock$lock_ast;
207                end;
208 
209                par_sdwp = addr (dseg$ (fixed (baseno (dp), 18))); /* ptr to parent sdw */
210                do while (sdw_util_$get_valid (par_sdwp) = "0"b); /* If parent active */
211                     ast_unlocked = "1"b;
212                     call lock$unlock_ast;                   /* Unlock the global lock */
213                     temp = dp -> dir.uid;                   /* Cause a segfault on parent dir */
214                     call lock$lock_ast;                     /* relock */
215                end;
216                if (pvte.pvid ^= pvid) | pvte.being_demounted then do;
217                     code = error_table_$pvid_not_found;     /* Check demount with AST locked */
218                     go to ret_ulast;
219                end;
220 
221 /**** now check to make sure it hasn't been activated
222       while we were not under the AST lock */
223 
224                if ast_unlocked & ^already_active_by_backup
225                then do;
226                     astep = search_ast$check (uid, pvid, vtocx, code);
227                     if astep ^= null | code ^= 0
228                     then go to ACTIVATED_BY_SOMEONE_ELSE;
229                end;
230 
231                par_astep = get_ptrs_$given_sdw (par_sdwp);
232 
233                old_par_ehs = par_aste.ehs;                  /* Save old ehs on parent */
234                par_aste.ehs = "1"b;                         /* Do not let son deactivate his father */
235 
236                if already_active_by_backup then do;
237                     aste.par_astep = rel (par_astep);       /* set parent astep */
238                     aste.infl = par_aste.infp;
239                     par_aste.infp = rel (astep);
240                     aste.per_process = par_aste.per_process;
241                     aste.multi_class = multi_class;         /* fix this now that we know */
242                     par_aste.ehs = old_par_ehs;
243                     return (astep);                         /* not that hard */
244                end;
245           end;
246 
247 /* validate some fields in the VTOCE which could really kill us
248    if they're bogus                                                                                           */
249 
250           if fixed (vtoce.records) > fixed (vtoce.csl)
251                | fixed (vtoce.csl) > fixed (vtoce.msl)
252                | fixed (vtoce.msl) > dim (vtoce.fm, 1)
253           then do;
254                code = error_table_$invalid_vtoce;
255                goto ret_ulast;
256           end;
257 
258 /*  checksum the file map  */
259 
260           if vtoce.fm_checksum_valid & (sst$checksum_filemap ^= 0)
261                & ^vtoce.fm_damaged then do;
262                call filemap_checksum_ (addr (vtoce.fm), fixed (vtoce.csl, 9), checksum);
263                if vtoce.fm_checksum ^= checksum then do;
264                     segdamage.pvid = pvte.pvid;
265                     segdamage.lvid = pvte.lvid;
266                     segdamage.uid = vtoce.uid;
267                     segdamage.vtocx = vtocx;
268                     segdamage.pno = -1;
269                     segdamage.uid_path = vtoce.uid_path;
270                     call syserr$binary (LOG, addr (segdamage), SB_vtoc_salv_dam, SBL_vtoc_salv_dam,
271                          "activate: Setting damaged switch on ^a at ^o (^a^[^a^]). Filemap damaged.",
272                          vtoce.primary_name, vtocx, pvte.devname || "_" || convert (p99, pvte.logical_area_number),
273                          pvte.is_sv, pvte.sv_name);
274                     vtoce.damaged = "1"b;
275                     vtoce.fm_damaged = "1"b;
276                     sst$damaged_ct = sst$damaged_ct + 1;
277                     pvte.vol_trouble_count = pvte.vol_trouble_count + 1;
278                end;
279           end;
280 
281           if ^vtoce.synchronized then do;                   /* Normal case */
282                astep = get_aste (fixed (vtoce.csl));
283                if astep = null () then do;
284                     code = error_table_$illegal_activation;
285                     goto ret_ulast;
286                end;
287           end;
288           else do;                                          /* Synchronized segment */
289                if ^sst$dm_enabled then do;                  /* No journal */
290                     code = error_table_$dm_not_enabled;
291                     goto ret_ulast;
292                end;
293                astep = get_aste$synchronized (fixed (vtoce.csl));
294                if astep = null () then do;
295                     code = error_table_$synch_seg_limit;
296                     goto ret_ulast;
297                end;
298           end;
299 
300 
301           if esw = normal then do;
302                if astep = par_astep then call syserr (CRASH, "activate: activating into father ^p", astep);
303                par_aste.ehs = old_par_ehs;
304 
305 /*        aste.fp, aste.bp    = have been set by get_aste or deactivate  */
306                aste.infl = par_aste.infp;
307                par_aste.infp = rel (astep);
308                aste.par_astep = rel (par_astep);
309                aste.per_process = par_aste.per_process;     /* Inherit this one */
310           end;
311                                                             /*        aste.uid = uid;     */ /* dont fill in now -protect against shutdown */
312           aste.msl = vtoce.msl;
313           aste.pvtx = pvtx;
314           aste.vtocx = vtocx;
315           aste.usedf = "1"b;
316           aste.gtus = "1"b;
317           aste.gtms = "1"b;
318           aste.explicit_deact_ok = "1"b;
319           aste.dnzp = vtoce.dnzp;
320           aste.damaged = vtoce.damaged;
321           aste.fm_damaged = vtoce.fm_damaged;
322           aste.synchronized = vtoce.synchronized;
323           aste.nqsw = vtoce.nqsw;
324           aste.dirsw = vtoce.dirsw;
325           aste.dtu = vtoce.dtu;
326           aste.dtm = vtoce.dtm;
327           aste.csl = vtoce.csl;
328           aste.nid = vtoce.nid;
329           aste.records = vtoce.records;
330           aste.multi_class = multi_class;
331 
332           sst$activations = sst$activations + 1;
333           if esw = backup then
334                sst$backup_activations = sst$backup_activations + 1;
335           if long_sw then
336                a_activated_sw = "1"b;                       /* indicate activation occured */
337           if dirsw then do;
338                aste.master_dir = vtoce.master_dir;
339                aste.quota = vtoce.quota;
340                aste.used = vtoce.used;
341                aste.tqsw (0) = vtoce.received (0) ^= 0 | vtoce.master_dir;
342                aste.tqsw (1) = vtoce.received (1) ^= 0;
343                sst$dir_activations = sst$dir_activations + 1;
344           end;
345           else seg_aste.usage = seg_vtoce.usage;            /* Segments have no quota. keep pf count */
346 
347           call pc$fill_page_table (astep, addr (vtoce.fm), fixed (vtoce.csl)); /* fill in page table */
348 
349           aste.uid = uid;                                   /* aste is stable now */
350 
351           call search_ast$hash_in (astep);
352 
353           nm_astep = astep;
354 
355 %include make_sstnt_entry;
356 
357           return (astep);                                   /* return a pointer to the new AST entry */
358 
359 %page;
360 
361 backup_activate: entry (a_vtocep, a_vtocx, a_pvtx, code) returns (ptr);
362 
363           esw = backup;
364           long_sw = "0"b;
365           vtocep = a_vtocep;
366           pvtx = a_pvtx;
367           vtocx = a_vtocx;
368           uid = vtoce.uid;                                  /* set local variables */
369           dirsw = vtoce.dirsw;
370           multi_class = "0"b;                               /* will get fixed up if someone else should activate this */
371           temp_entry_name = vtoce.primary_name;
372           goto COMMON;                                      /* with multiple entries you have to have one label */
373 
374 /* format: off */
375 %page; %include aste;
376 %page; %include dir_entry;
377 %page; %include dir_header;
378 %page; %include dir_name;
379 %page; %include pvte;
380 %page; %include segdamage_msg;
381 %page; %include sstnt;
382 %page; %include syserr_binary_def;
383 %page; %include syserr_constants;
384 %page; %include vtoce;
385 
386 /* format: on */
387 %page;
388 
389 /* BEGIN MESSAGE DOCUMENTATION
390 
391    Message:
392    activate: error on (deciduous) (dir) NAME
393 
394    S:     $log
395 
396    T:     $run
397 
398    M:     An attempt has been made to activate a
399    deciduous segment,
400    or to activate a segment
401    when the VTOCE's directory switch did not match the branch.
402    A connection failure is returned to the user process.
403    This information is logged for the use of system programmers.
404 
405    A:     $ignore
406 
407 
408    Message:
409    activate: activating into father PPPP
410 
411    S:     $crash
412 
413    T:     $run
414 
415    M:     The AST entry pointer returned by get_aste
416    is identical to the AST entry pointer for the parent of the segment being activated.
417    $err
418    $crashes
419 
420    A:     $recover
421 
422 
423    Message:
424    activate: Setting damaged switch on NAME at VTOCX (dskX_NN{s}). Filemap damaged.
425 
426    S:     $log
427 
428    T:     $run
429 
430    M:     The segment's File Map in the VTOCE had an invalid checksum, which
431    indicates likely damage to the File Map. The segment is marked as damaged.
432    It is possible that there is other damage on the physical volume due
433    to invalid or reused disk addresses. The count of volume inconsistencies is
434    incremented by 1.
435 
436    A:      Examine the VTOCE for damage using dump_vtoce. If other damage
437    is evident, delete it using hp_delete_vtoce -clear and recover the
438    segment. Run the physical volume scavenger as soon as possible to
439    detect and correct other damage on the physical volume.
440 
441 
442    END MESSAGE DOCUMENTATION */
443 
444      end activate;