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 /* format: style4 */
 15 truncate_vtoce: proc (branchp, first_page, code);
 16 
 17 
 18 /* FUNCTION -
 19 
 20    This procedure truncates the segment whose branch is pointed  to  by  the  input
 21    argument  "branchp",  from  the  page  number  defined  by  the  input  argument
 22    "first_page". The current length of the segment becomes equal  to  "first_page".
 23    All core and disk records occupied by the truncated portion of the segment
 24    are  freed.  In  addition,  the quota used information of the parents, up to the
 25    appropriate terminal quota directory, are updated to reflect the fact that  they
 26    , are not responsible any longer for those pages that have been freed.
 27 
 28    If  code  = 0 upon return, the operation was successful. Otherwise the operation
 29    failed at some point because of a system error.
 30 
 31    The parent directory is supposed to be locked before this procedure  is  called.
 32 
 33 
 34    IMPLEMENTATION -
 35 
 36    If the segment is active, the truncation takes place in the ASTE. The VTOCE will
 37    automatically  be updated at deactivation or any time the procedure update_vtoce
 38    is called.
 39 
 40    If the segment is not active, the truncation takes place directly in the  VTOCE.
 41    Since  the  parent  is  locked  and  the  segment  is  not active, it is safe to
 42    manipulate the VTOCE. However, updating the used count of the  parents  will  be
 43    done  on the ASTE's of the parent, after having forced them to the active state.
 44 
 45 
 46 
 47    MODIFIED BY :
 48 
 49    04/29/75  A. Bensoussan - Written for the new storage system.
 50    05/76  By Greenberg for await_vtoce,  06/76 for hphcs_$delete_vtoce.
 51    06/76 D.Vinograd - added entry hold which does not release pvtx .
 52    07/76 D. Vinograd modified to set volume dumper bit map so that truncated/deleted vtoces are dumped
 53    06/08/81 by J. Bongiovanni to set vtoce.records to 0 if truncating to 0
 54    07/10/82 by J. Bongiovanni to read entire VTOCE
 55    08/18/82 by J. Bongiovanni for new pc$deposit_list calling sequence
 56    10/26/82 by J. Bongiovanni to reset fm_damaged if truncating to 0, fix grandparent locking
 57    830430 BIM to make check of pvtx and vtocx against branch.
 58    83-08-06 by E. N. Kittlitz to do pvtx/vtocx check using search_ast$check.
 59    84-12-20 by Keith Loepere to count dirs pages against own quota.
 60    85-01-10 by Keith Loepere for covert channel detection.
 61    85-01-21 by Keith Loepere to add dtm setting and detection.
 62 */
 63 
 64 %page;
 65 
 66 dcl  branchp ptr;
 67 dcl  code fixed bin (35);
 68 dcl  first_page fixed bin (17);
 69 
 70 dcl  csl fixed bin;
 71 dcl  deleting bit (1) init ("0"b);
 72 dcl  1 deposit aligned,
 73        2 list (256) bit (22) aligned;
 74 dcl  dir_must_be_unlocked bit (1);
 75 dcl  event_count fixed bin;
 76 dcl  first fixed bin;
 77 dcl  hold bit (1) init ("0"b);
 78 dcl  i fixed bin;
 79 dcl  1 local_vtoce like vtoce aligned;
 80 dcl  multi_class bit (1) aligned;
 81 dcl  n fixed bin;
 82 dcl  normal bit (1) aligned;
 83 dcl  page_count fixed bin;
 84 dcl  pageno_list (256) fixed bin aligned;
 85 dcl  par_astep ptr;
 86 dcl  par_dp ptr;
 87 dcl  par_ep ptr;
 88 dcl  par_pvid bit (36) aligned;
 89 dcl  par_uid bit (36) aligned;
 90 dcl  par_vtocx fixed bin;
 91 dcl  pvid bit (36) aligned;
 92 dcl  pvtx fixed bin;
 93 dcl  uid bit (36) aligned;
 94 dcl  vtocx fixed bin;
 95 
 96 dcl  error_table_$mylock fixed bin (35) external;
 97 dcl  error_table_$vtoce_connection_fail fixed bin (35) external;
 98 dcl  pds$throttle_segment_state_changes bit (1) aligned external;
 99 dcl  sst$checksum_filemap fixed bin (35) external;
100 
101 dcl  activate entry (ptr, fixed bin (35)) returns (ptr);
102 dcl  dbm_man$set_incr entry (fixed bin, fixed bin, fixed bin (35));
103 dcl  filemap_checksum_ entry (ptr, fixed bin, bit (36) aligned);
104 dcl  get_pvtx entry (bit (36) aligned, fixed bin (35)) returns (fixed bin);
105 dcl  get_pvtx$hold_pvtx entry (bit (36) aligned, fixed bin, fixed bin (35));
106 dcl  get_pvtx$release_pvtx entry (bit (36) aligned, fixed bin);
107 dcl  limit_covert_channel entry (fixed bin);
108 dcl  lock$dir_unlock entry (ptr);
109 dcl  lock$lock_ast entry;
110 dcl  lock$unlock_ast entry;
111 dcl  pc$deposit_list entry (fixed bin, fixed bin, ptr, fixed bin, ptr);
112 dcl  pc$truncate entry (ptr, fixed bin);
113 dcl  pc$updates entry (ptr);
114 dcl  quotaw$cu entry (ptr, fixed bin, bit (1), fixed bin, fixed bin (35));
115 dcl  search_ast$check entry (bit (36) aligned, bit (36) aligned, fixed bin, fixed bin (35)) returns (ptr);
116 dcl  sum$getbranch_root_my entry (ptr, bit (1), ptr, fixed bin (35));
117 dcl  syserr entry options (variable);
118 dcl  vtoc_man$await_vtoce entry (bit (36) aligned, fixed bin, fixed bin, fixed bin (35));
119 dcl  vtoc_man$get_vtoce entry (bit (36) aligned, fixed bin, fixed bin, bit (3), ptr, fixed bin (35));
120 dcl  vtoc_man$put_vtoce entry (bit (36) aligned, fixed bin, fixed bin, bit (3), ptr, fixed bin (35));
121 
122 dcl  (addr, bit, clock, fixed, min, null, ptr, substr) builtin;
123 
124 %page;
125           first = first_page;
126           go to join;
127 hold: entry (branchp, first_page, code);
128           first = first_page;
129           hold = "1"b;
130           goto join;
131 truncate_vtoce_delete: entry (branchp, code);
132           deleting = "1"b;
133           first = 0;
134 join:
135 
136 /* INITIALIZE POINTERS AND VARIABLES */
137 
138           normal = ^(deleting | hold);
139           ep = branchp;
140           code = 0;
141 
142           uid = entry.uid;
143           pvid = entry.pvid;
144           pvtx = get_pvtx (pvid, code); if code ^= 0 then return;
145           vtocx = entry.vtocx;
146           multi_class = entry.multiple_class;
147           event_count = 0;
148 
149 /* IF THE SEGMENT IS ACTIVE, CALL UPON PAGE CONTROL TO DO ALL THE WORK */
150 
151           call lock$lock_ast;
152 
153           astep = search_ast$check (uid, pvid, vtocx, (0)); /* ignore double-uid error for now */
154 
155           if astep ^= null then do;                         /* aste really matches */
156                if aste.hc_sdw then call syserr (CRASH, "truncate_vtoce: attempt to destroy hc_sdw seg astep ^p", astep);
157                csl = fixed (aste.csl);
158                call pc$truncate (astep, first);
159                if first = 0 then do;                        /* was truncate to zero length? */
160                     if aste.damaged then aste.fmchanged = "1"b; /* force update_vtoce if reset it */
161                     aste.damaged = "0"b;                    /* user wanted zeroes: he's got them */
162                     aste.fm_damaged = "0"b;                 /* any filemap damage got better */
163                end;
164                call lock$unlock_ast;
165                if ^deleting & hold then call get_pvtx$hold_pvtx (pvid, pvtx, code);
166                go to covert_test;
167           end;
168 
169           call lock$unlock_ast;
170 
171 
172 /* THE SEGMENT IS NOT ACTIVE - THEREFORE THE OPERATION HAS TO BE DONE ON THE VTOCE. */
173 /* NOTE THAT ANOTHER SEGMENT WITH THE SAME UID MIGHT BE ACTIVE, BUT WE DON'T CARE. */
174 
175           vtocep = addr (local_vtoce);
176 
177           call vtoc_man$get_vtoce (pvid, pvtx, vtocx, "111"b, vtocep, code);
178           if code ^= 0 then return;
179 
180           if uid ^= vtoce.uid then do;
181                code = error_table_$vtoce_connection_fail;
182                return;
183           end;
184 
185           csl = fixed (vtoce.csl);
186 
187           if ^deleting then call get_pvtx$hold_pvtx (pvid, pvtx, code);
188           if code ^= 0 then return;                         /* Got demounted if return */
189 
190 
191 /* PERFORM THE TRUNCATION ON THE VTOCE AND WRITE IT BACK IN THE DISK -
192    DO NOT DEPOSIT ANY DISK ADDRESSES YET, BUT REMEMBER THEM */
193 
194           n = 0;
195           do i = first to csl - 1;
196                if substr (vtoce.fm (i), 1, 1) = "0"b then do;
197                     n = n + 1;
198                     deposit.list (n) = vtoce.fm (i);
199                     pageno_list (n) = i;
200                     vtoce.fm (i) = truncate_vtoce_null_addr;
201                end;
202           end;
203 
204           if vtoce.fm_damaged & (sst$checksum_filemap ^= 0)
205           then n = 0;                                       /* don't deposit potentially bogus addresses */
206 
207           vtoce.csl = bit (fixed (min (first, csl), 9), 9);
208           if first = 0 then do;
209                vtoce.records = "0"b;
210                vtoce.damaged = "0"b;
211                vtoce.fm_damaged = "0"b;
212           end;
213           else vtoce.records = bit (fixed (fixed (vtoce.records, 9) - n, 9), 9); /* #@!*%! */
214 
215           if sst$checksum_filemap = 0 then do;
216                vtoce.fm_damaged = "0"b;
217                vtoce.fm_checksum_valid = "0"b;
218                vtoce.fm_checksum = ""b;
219           end;
220           else do;
221                vtoce.fm_checksum_valid = "1"b;
222                call filemap_checksum_ (addr (vtoce.fm), fixed (vtoce.csl, 9), vtoce.fm_checksum);
223           end;
224 
225           if vtoce.dirsw then
226                if ^vtoce.deciduous then
227                     vtoce.used (1) = vtoce.used (1) - n;    /* update dir quota */
228 
229 /* Set dtu, dtcm.
230    This setting can be a covert channel event (external to page control's
231    detection of dtu/dtm setting).  If the object is multi-class, then it sits
232    in a lower class dir and this dtu setting is lower class visible.  The dtm
233    is always lower class visible, since it propogates up the hierarchy. */
234 
235           if normal then do;
236                vtoce.dtm, vtoce.dtu = bit (fixed (clock (), 52), 52);
237                if multi_class then event_count = 2;
238                else event_count = 1;
239           end;
240 
241           call vtoc_man$put_vtoce ("0"b, pvtx, vtocx, "111"b, vtocep, code);
242           if code ^= 0 then go to release;
243 
244           if deleting | (^deleting & ^vtoce.per_process & ^vtoce.deciduous) then
245                call dbm_man$set_incr (pvtx, vtocx, code);
246 
247 
248 /* IF THERE ARE ANY DISK ADDRESSES TO BE DEPOSITED, DO IT NOW - AND ALSO UPDATE THE USED COUNT
249    IN ASTE's OF SUPERIOR DIRECTORIES AFTER HAVING FORCED THEM TO BE ACTIVE */
250 
251           if n = 0 then go to release;
252 
253           if ^vtoce.deciduous then do;                      /* Cannot free deciduous space (hc part) */
254                call vtoc_man$await_vtoce ("0"b, pvtx, vtocx, code);
255                if code ^= 0 then go to release;
256                call pc$deposit_list (pvtx, (n), addr (deposit.list), vtocx, addr (pageno_list));
257           end;
258 
259 release:
260           if normal then call get_pvtx$release_pvtx (pvid, pvtx); /* Free volume for demount */
261 
262 
263           if entry.owner = "111111111111111111111111111111111000"b then return;
264                                                             /* No quota handling if hphcs_$delv */
265 
266           dp = ptr (ep, 0);
267           par_uid = dir.uid;
268           par_pvid = dir.pvid;
269           par_vtocx = dir.vtocx;
270           dir_must_be_unlocked = "0"b;
271 
272           call lock$lock_ast;
273 
274           par_astep = search_ast$check (par_uid, par_pvid, par_vtocx, code);
275           if code ^= 0 then do;                             /* can't activate it, so punt */
276                call lock$unlock_ast;
277                return;
278           end;
279 
280           if par_astep = null then do;
281                call lock$unlock_ast;
282 
283                call sum$getbranch_root_my (dp, "0"b, par_ep, code);
284 
285                if code = 0 then dir_must_be_unlocked = "1"b;
286                else if code = error_table_$mylock then code = 0; else return;
287 
288                par_dp = ptr (par_ep, 0);
289                par_astep = activate (par_ep, code);
290 
291                if code ^= 0 then do;
292                     if dir_must_be_unlocked then call lock$dir_unlock (par_dp);
293                     return;
294                end;
295           end;
296 
297           if ^vtoce.deciduous then do;
298                if vtoce.dirsw then
299                     if vtoce.received (1) = 0 then          /* non-terminal dir - give back quota to terminal cell */
300                          call quotaw$cu (par_astep, (-n), "1"b, 0, code);
301                     else ;                                  /* deleting dir merely zeroes its own terminal quota */
302                else call quotaw$cu (par_astep, (-n), "0"b, 0, code);
303                if normal then call pc$updates (par_astep); /* let dumper know to come */
304           end;
305           call lock$unlock_ast;
306 
307           if dir_must_be_unlocked then call lock$dir_unlock (par_dp);
308 %page;
309 covert_test:
310           if ^normal then return;
311 
312 /* see if the truncation of these pages can transmit some data */
313 
314           if ^pds$throttle_segment_state_changes then return; /* uninteresting */
315           if multi_class then do;                           /* only multi-class segment attributes count towards covert channels */
316 
317 /* The changing of records used is a covert channel relevant event.  The number
318    of events depends on how many pages were truncated. */
319 
320                csl = csl - first;
321                if csl > 0 then do;
322                     page_count = 1;
323                     do event_count = event_count repeat event_count + 1 while (page_count <= csl);
324                          page_count = page_count * 2;       /* this finds log2(csl), sort of */
325                     end;
326                end;
327           end;
328 
329           if event_count > 0 then call limit_covert_channel (event_count);
330           return;
331 
332 /* format: off */
333 
334 %page; %include aste;
335 %page; %include dir_entry;
336 %page; %include dir_header;
337 %page; %include null_addresses;
338 %page; %include syserr_constants;
339 %page; %include vtoce;
340 %page;
341 /* format: on */
342 
343 /* BEGIN MESSAGE DOCUMENTATION
344 
345    Message:
346    truncate_vtoce: attempt to destroy hc_sdw seg astep PPP
347 
348    S: $crash
349 
350    T: $run
351 
352    M: An attempt has been made to truncate
353    a supervisor segment.
354    The AST entry is located at PPP.
355    $err
356 
357    A: $recover
358 
359    END MESSAGE DOCUMENTATION */
360 
361      end truncate_vtoce;