1 /****^  ***********************************************************
  2         *                                                         *
  3         * Copyright, (C) Honeywell Bull Inc., 1987                *
  4         *                                                         *
  5         * Copyright, (C) Honeywell Information Systems Inc., 1982 *
  6         *                                                         *
  7         *********************************************************** */
  8 
  9 
 10 
 11 /* format: style3 */
 12 scavenger:
 13      proc (Pvtx, Pvid, Scavenger_Optionsp, Sc_metersp, Code);
 14 
 15 /*  This is the driver program for the scavenger. It validates the PVTE
 16     and sets up all data structures needed for scavenging. The scavenge
 17     itself is done elsewhere.
 18 
 19     scavenger$shutdown is called by normal shutdown to reset any
 20     scavenge in progress. It must be called after traffic control
 21     is shutdown to avoid races.
 22 
 23     Written July 1982 by J. Bongiovanni
 24     Modified October 1982 by J. Bongiovanni for fm_damaged and associated meters
 25     Modified 83-12-13 BIM to call verify_lock on faults.
 26     Modified 85-02-21, EJ Sharpe: use syserr_fault_msg.incl.pl1, correct logging of history registers.
 27 */
 28 
 29 /****^  HISTORY COMMENTS:
 30   1) change(86-05-13,GJohnson), approve(86-05-13,MCR7387),
 31      audit(86-05-13,Martinson), install(86-05-14,MR12.0-1056):
 32      Correct error message documentation.
 33   2) change(86-06-02,Fawcett), approve(86-04-11,MCR7383),
 34      audit(86-06-18,Beattie), install(86-07-17,MR12.0-1097):
 35      Add support for subvolumes.
 36                                                    END HISTORY COMMENTS */
 37 
 38 /*  Parameter  */
 39 
 40 dcl       Pvtx                fixed bin;                    /* PVTE index */
 41 dcl       Pvid                bit (36) aligned;             /* Physical Volume ID */
 42 dcl       Scavenger_Optionsp  ptr;                          /* -> scavenger_options */
 43 dcl       Sc_metersp          ptr;                          /* -> returned meters, or null */
 44 dcl       Code                fixed bin (35);               /* Error code */
 45 
 46 /*  Automatic  */
 47 
 48 dcl       begin_clock         fixed bin (71);
 49 dcl       begin_pf            fixed bin;
 50 dcl       begin_vcpu          fixed bin (71);
 51 dcl       code                fixed bin (35);
 52 dcl       end_pf              fixed bin;
 53 dcl       end_vcpu            fixed bin (71);
 54 dcl       i_am_wired          bit (1) aligned;
 55 dcl       1 local_sc_meters   aligned like sc_meters;
 56 dcl       1 local_scavenger_options
 57                               aligned like scavenger_options;
 58 dcl       p99                 pic "99";
 59 dcl       old_mask            fixed bin (71);
 60 dcl       process_tablex      fixed bin;
 61 dcl       ptwp                ptr;
 62 dcl       scavenger_data_astep
 63                               ptr;
 64 dcl       started             bit (1) aligned;
 65 
 66 /*  Static  */
 67 
 68 dcl       N_OVFL              fixed bin int static options (constant) init (1023);
 69                                                             /* Limited by field size */
 70 
 71 /*  Based  */
 72 
 73 dcl       1 Sc_meters         aligned like sc_meters based (Sc_metersp);
 74 dcl       1 Scavenger_Options aligned like scavenger_options based (Scavenger_Optionsp);
 75 
 76 /*  External  */
 77 
 78 dcl       error_table_$pvid_not_found
 79                               fixed bin (35) external;
 80 dcl       error_table_$unexpected_condition
 81                               fixed bin (35) external;
 82 dcl       error_table_$scavenge_process_limit
 83                               fixed bin (35) external;
 84 dcl       error_table_$pv_no_scavenge
 85                               fixed bin (35) external;
 86 dcl       pds$process_group_id
 87                               char (32) aligned external;
 88 dcl       pds$processid       bit (36) aligned external;
 89 dcl       sst$astl            bit (36) aligned external;
 90 
 91 /*  Entry  */
 92 
 93 dcl       condition_          entry (char (*), entry);
 94 dcl       get_ptrs_$given_segno
 95                               entry (fixed bin) returns (ptr);
 96 dcl       lock$lock_ast       entry;
 97 dcl       lock$lock_fast      entry (ptr);
 98 dcl       lock$unlock_ast     entry;
 99 dcl       lock$unlock_fast    entry (ptr);
100 dcl       pc_wired$wire_wait  entry (ptr, fixed bin, fixed bin);
101 dcl       pc_wired$unwire     entry (ptr, fixed bin, fixed bin);
102 dcl       pmut$lock_ptl       entry (fixed bin (71), ptr);
103 dcl       pmut$unlock_ptl     entry (fixed bin (71), ptr);
104 dcl       scavenge_volume     entry (ptr, ptr, ptr, ptr, fixed bin (35));
105 dcl       syserr              entry options (variable);
106 dcl       syserr$binary       entry options (variable);
107 dcl       syserr$error_code   entry options (variable);
108 dcl       usage_values        entry (fixed bin, fixed bin (71));
109 dcl       verify_lock$condition_nolog
110                               entry (character (*), pointer);
111 dcl       wire_proc$wire_me   entry;
112 dcl       wire_proc$unwire_me entry;
113 
114 /*  Builtin  */
115 
116 dcl       addr                builtin;
117 dcl       addrel              builtin;
118 dcl       baseno              builtin;
119 dcl       bin                 builtin;
120 dcl       clock               builtin;
121 dcl       convert             builtin;
122 dcl       divide              builtin;
123 dcl       float               builtin;
124 dcl       null                builtin;
125 dcl       rel                 builtin;
126 dcl       size                builtin;
127 dcl       unspec              builtin;
128 %page;
129           started = "0"b;
130           i_am_wired = "0"b;
131 
132           unspec (local_sc_meters) = ""b;
133           unspec (local_scavenger_options) = unspec (Scavenger_Options);
134 
135           call SETUP_LOCK (Code);
136           if Code ^= 0
137           then return;
138 
139           call SETUP_PROCESS_TABLE (process_tablex, code);
140           if code ^= 0
141           then goto CLEANUP_RETURN;
142 
143           call SETUP_BLOCK (process_tablex);
144 
145           pvte.scavenger_block_rel = rel (scavenger_blockp);
146           call lock$unlock_fast (addr (scavenger_data.lock));
147 
148           call usage_values (begin_pf, begin_vcpu);
149           begin_clock = clock ();
150 
151           call condition_ ("any_other", PRINT_ERROR);
152 
153           call syserr (ANNOUNCE, "scavenger: Begin scavenge of ^a_^a^[^a^;^1s^] by ^a", pvte.devname,
154                convert (p99, pvte.logical_area_number), pvte.is_sv, pvte.sv_name, pds$process_group_id);
155           started = "1"b;
156           call wire_proc$wire_me;
157           i_am_wired = "1"b;
158           call scavenge_volume (pvtep, scavenger_blockp, addr (local_scavenger_options), addr (local_sc_meters), code);
159 
160 LOCK_CLEANUP_RETURN:
161           call lock$lock_fast (addr (scavenger_data.lock));
162 
163 CLEANUP_RETURN:
164           if i_am_wired
165           then call wire_proc$unwire_me;
166 
167           if started & (code = 0)
168           then do;
169                     call usage_values (end_pf, end_vcpu);
170                     local_sc_meters.n_scavenge = 1;
171                     local_sc_meters.pf = end_pf - begin_pf;
172                     local_sc_meters.vcpu = end_vcpu - begin_vcpu;
173                     local_sc_meters.clock_time = clock () - begin_clock;
174                     if local_scavenger_options.print_meters
175                     then call PRINT_METERS;
176                     scavenger_data.meters = scavenger_data.meters + local_sc_meters;
177                end;
178 
179           call lock$lock_ast;                               /* Protect against asynchronous SC/PC */
180           call pmut$lock_ptl (old_mask, ptwp);
181           pvte.scavenger_block_rel = ""b;
182           pvte.scav_check_address = "0"b;
183           pvte.deposit_to_volmap = "0"b;
184           call pmut$unlock_ptl (old_mask, ptwp);
185           call lock$unlock_ast;
186 
187           if scavenger_blockp ^= null ()
188           then call RETURN_BLOCK (process_tablex);
189           if sc_process_tablep ^= null ()
190           then call RETURN_PROCESS_TABLE (process_tablex);
191 
192           call lock$unlock_fast (addr (scavenger_data.lock));
193 
194           if started
195           then do;
196                     if code = 0
197                     then call syserr (ANNOUNCE, "scavenger: Scavenge of ^a_^a^[^a^;^1s^] by ^a completed.", pvte.devname,
198                               convert (p99, pvte.logical_area_number), pvte.is_sv, pvte.sv_name, pds$process_group_id);
199                     else call syserr$error_code (ANNOUNCE, code,
200                               "scavenger: Scavenge of ^a_^a^[^a^;^1s^] by ^a completed with error.", pvte.devname,
201                               convert (p99, pvte.logical_area_number), pvte.is_sv, pvte.sv_name, pds$process_group_id);
202                end;
203 
204           if Sc_metersp ^= null ()
205           then unspec (Sc_meters) = unspec (local_sc_meters);
206 
207           Code = code;
208           return;
209 %page;
210 /*  Entry to shutdown scavenges in progress  */
211 
212 shutdown:
213      entry;
214 
215           scavenger_datap = addr (scavenger_data$);
216           sc_process_tablep = scavenger_data.process_table_ptr;
217 
218           do process_tablex = 1 to sc_process_table.max_n_processes;
219                if sc_process_table.process (process_tablex).processid ^= ""b
220                                                             /* Live entry */
221                then do;
222                          pvtep = sc_process_table.process (process_tablex).pvtep;
223                          pvte.deposit_to_volmap = "0"b;
224                          pvte.scav_check_address = "0"b;
225                          pvte.scavenger_block_rel = ""b;
226                          call syserr (ANNOUNCE, "scavenger: Scavenge of ^a_^a^[^a^] stopped.", pvte.devname,
227                               convert (p99, pvte.logical_area_number), pvte.is_sv, pvte.sv_name);
228                     end;
229           end;
230 
231           return;
232 
233 
234 %page;
235 /*  Internal Procedure to lock the scavenger data base and set up pointers */
236 
237 SETUP_LOCK:
238      proc (Code);
239 
240 dcl       Code                fixed bin (35);
241 
242           scavenger_datap = addr (scavenger_data$);
243           sc_process_tablep = null ();
244           scavenger_blockp = null ();
245           pvt_arrayp = addr (pvt$array);
246           pvtep = addr (pvt_array (Pvtx));
247           scavenger_data_astep = get_ptrs_$given_segno (bin (baseno (scavenger_datap)));
248           Code = 0;
249 
250           if pvte.pvid ^= Pvid
251           then do;
252                     Code = error_table_$pvid_not_found;
253                     return;
254                end;
255           if ^pvte.used | ^pvte.storage_system | (pvte.scavenger_block_rel ^= ""b)
256           then do;
257                     Code = error_table_$pv_no_scavenge;
258                     return;
259                end;
260 
261           call lock$lock_fast (addr (scavenger_data.lock));
262 
263      end SETUP_LOCK;
264 %page;
265 /*  Internal Procedure to get a process table entry and fill it in */
266 
267 SETUP_PROCESS_TABLE:
268      proc (Process_Index, Code);
269 
270 dcl       Process_Index       fixed bin;
271 dcl       Code                fixed bin (35);
272 
273 dcl       n_header_pages      fixed bin;
274 dcl       procx               fixed bin;
275 
276           Process_Index = -1;
277           Code = 0;
278 
279           sc_process_tablep = scavenger_data.process_table_ptr;
280           if sc_process_table.n_processes >= sc_process_table.max_n_processes
281           then do;
282 RETURN_ERROR:
283                     sc_process_tablep = null ();
284                     Code = error_table_$scavenge_process_limit;
285                     return;
286                end;
287 
288           do procx = 1 repeat procx + 1 while (procx <= sc_process_table.max_n_processes);
289                if sc_process_table.process (procx).processid = ""b
290                then goto FOUND_EMPTY;
291           end;
292           goto RETURN_ERROR;
293 
294 FOUND_EMPTY:
295           Process_Index = procx;
296           sc_process_table.process (procx).processid = pds$processid;
297           sc_process_table.process (procx).pvtep = pvtep;
298 
299           sc_process_table.n_processes = sc_process_table.n_processes + 1;
300           if sc_process_table.n_processes = 1
301           then do;
302                     n_header_pages = divide (size (scavenger_data) + 1023, 1024, 17);
303                     call pc_wired$wire_wait (scavenger_data_astep, 0, n_header_pages);
304                end;
305 
306 
307      end SETUP_PROCESS_TABLE;
308 %page;
309 /*  Internal Procedure to Allocate and Setup the Scavenge Block  */
310 
311 SETUP_BLOCK:
312      proc (Process_Index);
313 
314 dcl       Process_Index       fixed bin;
315 
316 dcl       first_page          fixed bin;
317 dcl       n_pages             fixed bin;
318 
319 
320           scavenger_n_records = pvte.totrec;
321           scavenger_n_ovfl = N_OVFL;
322 
323           first_page = sc_process_table.process (Process_Index).first_block_page;
324           n_pages = divide (size (scavenger_block) + 1023, 1024, 17);
325 
326           scavenger_blockp = sc_process_table.process (process_tablex).blockp;
327 
328           scavenger_block.n_records = scavenger_n_records;
329           scavenger_block.n_ovfl = scavenger_n_ovfl;
330           scavenger_block.ovfl_free_ix = 1;
331 
332           unspec (scavenger_block.records) = ""b;
333           unspec (scavenger_block.overflow) = ""b;
334 
335 
336           call pc_wired$wire_wait (scavenger_data_astep, first_page, n_pages);
337 
338           sc_process_table.process (Process_Index).n_block_pages = n_pages;
339 
340      end SETUP_BLOCK;
341 %page;
342 /*  Internal Procedure to Revert a Scavenge Block  */
343 
344 RETURN_BLOCK:
345      proc (Process_Index);
346 
347 dcl       Process_Index       fixed bin;
348 
349 dcl       first_page          fixed bin;
350 dcl       n_pages             fixed bin;
351 
352 
353           if sc_process_table.process (Process_Index).processid ^= pds$processid
354           then call syserr (CRASH, "scavenger: Invalid block reset");
355 
356           first_page = sc_process_table.process (Process_Index).first_block_page;
357           n_pages = sc_process_table.process (Process_Index).n_block_pages;
358           call pc_wired$unwire (scavenger_data_astep, first_page, n_pages);
359 
360 
361 
362      end RETURN_BLOCK;
363 %page;
364 /*  Internal Procedure to release a process table entry  */
365 
366 RETURN_PROCESS_TABLE:
367      proc (Process_Index);
368 
369 dcl       Process_Index       fixed bin;
370 dcl       n_header_pages      fixed bin;
371 
372           if sc_process_table.process (Process_Index).processid ^= pds$processid
373           then call syserr (CRASH, "scavenger: Process table entry not owned by this process.");
374 
375           sc_process_table.process (Process_Index).processid = ""b;
376           sc_process_table.process (Process_Index).pvtep = null ();
377           sc_process_table.process (Process_Index).n_block_pages = 0;
378 
379           sc_process_table.n_processes = sc_process_table.n_processes - 1;
380           if sc_process_table.n_processes = 0
381           then do;
382                     n_header_pages = divide (size (scavenger_data) + 1023, 1024, 17);
383                     call pc_wired$unwire (scavenger_data_astep, 0, n_header_pages);
384                end;
385 
386 
387      end RETURN_PROCESS_TABLE;
388 %page;
389 /*  Internal Procedure to print an error message and cleanup. Called
390     when any conditon is signalled through this frame */
391 
392 PRINT_ERROR:
393      proc (Mcptr, Condition, Coptr, Infoptr, Continue) options (non_quick);
394 
395 dcl       Mcptr               ptr;
396 dcl       Condition           char (*);
397 dcl       Coptr               ptr;
398 dcl       Infoptr             ptr;
399 dcl       Continue            bit (1) aligned;
400 
401 dcl       1 auto_fault_msg    aligned like fault_msg;       /* Machine conds and hist regs for logging */
402 dcl       ssptr               ptr;                          /* pointer to signaller stack frame */
403 
404 
405           if Mcptr ^= null ()
406           then do;
407                     ssptr = addrel (Mcptr, -8);             /* signaller_stack.pad is 8 words long! */
408 
409 /* Construct contiguous machine conditions and history registers */
410                     unspec (auto_fault_msg.mach_cond) = unspec (ssptr -> signaller_stack.mach_cond);
411                     auto_fault_msg.hist_reg = ssptr -> signaller_stack.history_registers;
412 
413                     call syserr$binary (scavenger_data.error_severity, Mcptr, SB_hw_fault, SBL_hw_fault,
414                          "scavenger: ^a condition signalled during scavenge of ^a_^a^[^a^;^1s^] by ^a", Condition,
415                          pvte.devname, convert (p99, pvte.logical_area_number), pvte.is_sv, pvte.sv_name,
416                          pds$process_group_id);
417                end;
418           else do;
419                     call syserr (scavenger_data.error_severity,
420                          "scavenger: ^a condition signalled during scavenge of ^a_^a^[^a^;^1s^] by ^a", Condition,
421                          pvte.devname, convert (p99, pvte.logical_area_number), pvte.is_sv, pvte.sv_name,
422                          pds$process_group_id);
423                end;
424 
425           if sst$astl = pds$processid
426           then call lock$unlock_ast;                        /* Read-only, safe */
427           call verify_lock$condition_nolog (Condition, Mcptr);
428                                                             /* Fix other locks */
429 
430           code = error_table_$unexpected_condition;
431 
432           goto LOCK_CLEANUP_RETURN;
433 
434      end PRINT_ERROR;
435 %page;
436 /*  Internal Procedure to print metering data into the syserr log  */
437 
438 PRINT_METERS:
439      proc;
440 
441 dcl       clock_sec           float;
442 dcl       vcpu_sec            float;
443 
444           vcpu_sec = float (local_sc_meters.vcpu) / 1.0e6;
445           clock_sec = float (local_sc_meters.clock_time) / 1.0e6;
446 
447           call syserr (LOG,
448                "scavenger: Meters from scavenge of ^a_^a^[^a^;^1s^]. Clock=^6.1f vcpu=^6.1f pf=^d^/VTOCES: Total=^d Damaged=^d Per-Proc=^d Per-Boot=^d FMDamaged=^d Freed=^d^/Records: Total=^d Pot conflict=^d FMD Conflict = ^d Conflict=^d Lost=^d",
449                pvte.devname, convert (p99, pvte.logical_area_number), pvte.is_sv, pvte.sv_name, clock_sec, vcpu_sec,
450                local_sc_meters.pf, local_sc_meters.n_vtoces, local_sc_meters.n_vtoces_damaged,
451                local_sc_meters.n_vtoces_per_proc, local_sc_meters.n_vtoces_per_boot, local_sc_meters.n_vtoces_fmd,
452                local_sc_meters.n_vtoces_freed, local_sc_meters.n_records, local_sc_meters.n_conflicts,
453                local_sc_meters.n_fmd_conflicts, local_sc_meters.n_real_conflicts, local_sc_meters.n_lost_records);
454 
455      end PRINT_METERS;
456 
457 %page;
458 %include pvte;
459 %page;
460 %include scavenger_data;
461 %page;
462 %include syserr_binary_def;
463 %page;
464 %include syserr_constants;
465 %page;
466 %include syserr_fault_msg;
467 %page;
468 %include mc;
469 %page;
470 %include signaller_stack;
471 %page;
472 /* BEGIN MESSAGE DOCUMENTATION
473 
474 
475 Message:
476 scavenger: Begin scavenge of dskX_NN{s} by PERSON.PROJECT.TAG
477 
478 S:        $info
479 
480 T:        When a physical volume is being scavenged
481 
482 M:        This is an informational message at the beginning of a volume
483 scavenge.
484 
485 A:        $ignore
486 
487 
488 Message:
489 scavenger: Scavenge of dskX_NN{s} by PERSON.PROJECT.TAG completed.
490 
491 S:        $info
492 
493 T:        When a physical volume is being scavenged.
494 
495 M:        This is an informational message to indicate successful completion
496 of a scavenge.
497 
498 A:        $ignore
499 
500 
501 Message:
502 scavenger: Scavenge of dskX_NN{s} by PERSON.PROJECT.TAG completed with error. ERRORMESSAGE.
503 
504 S:        $info
505 
506 T:        When a physical volume is being scavenged.
507 
508 M:        Scavenging could not be completed because of the error indicated.
509 
510 A:        $inform
511 
512 
513 Message:
514 scavenger: Invalid block reset.
515 
516 S:        $crash
517 
518 T:        When a physical volume is being scavenged.
519 
520 M:        A process attempted to clean up a scavenger block which was not
521 assigned to it. This indicates a software malfunction.
522 
523 A:        $recover
524 
525 
526 Message:
527 scavenger: Process table entry not owned by this process.
528 
529 S:        $crash
530 
531 T:        When a physical volume is being scavenged.
532 
533 M:        The scavenger attempted to release a process table entry which did not
534 belong to this process. This indicates a software malfunction.
535 
536 A:        $recover
537 
538 
539 Message:
540 scavenger: XXXXXX condition signalled during scavenge of dskX_NN{s} by PERSON.PROJECT.TAG
541 
542 S:        $info
543 
544 T:        When a physical volume is being scavenged.
545 
546 M:        An unexpected XXXXXX condition was signalled during a volume
547 scavenge, causing abnormal termination of the scavenge.
548 
549 A:        $inform
550 
551 
552 Message:
553 scavenger: Meters from scavenge of dskX_NN{s}. METERINGDATA.
554 
555 S:        $log
556 
557 T:        When a physical volume is being scavenged.
558 
559 M:        Various peformance measurements of the scavenge are recorded if
560 the appropriate scavenger control flag is set.
561 
562 A:        $ignore
563 
564 Message:
565 scavenger: Scavenge of dskX_NN{s} stopped.
566 
567 S:        $info
568 
569 T:        During system shutdown.
570 
571 M:        The system is being shutdown, and a scavenge of dskX_NN{s} is
572 in progress. The scavenge is terminated and likely had no effect.
573 
574 A:        Rerun the scavenge.
575 
576 
577 END MESSAGE DOCUMENTATION */
578 
579      end scavenger;