.ifi init_plm "FS-00" .srv draft "" .srv draft_date "" .srv section %Arg1% .pdl 66 .ifi l0h "File System Primitives" The file system primitives described in this section are those that are (for the most part) directly callable from the user ring via a gate entry. .ifi hit "K|properties~access" These primitives implement the various file system functions (ACL listing, object deletion, address space manipulation, etc). They make heavy use of the facilities of directory control and of address and name space management, as discussed in the previous sections. .ifi l1h "AIM Related Primitives" There are only two AIM related primitives. access_class_check, which .ifi hit "K|properties~AIM" validates a directory, and reclassify, which can change the access class of objects. .ifi l2h "Access Class Checks" The primitive access_class_check sets the soos (security out of service) .ifi hit "K|access_class_check" switch off for an object that meets the various AIM restrictions. These checks are: the access class of all objects must be equal to the containing directory, or the object must be multi-class and must be of greater class than the directory and in ring one (for segments) or have a terminal quota (directories). Also, this directory must itself be equal to its parent, or greater and have a terminal quota. If all succeeds, it will turn off soos. If it fails, it turns it on. .ifi l2h "Access Class Setting" reclassify is the privileged routine that changes the access classes for .ifi hit "K|reclassify" objects. The common routine setup finds the object in question and the access classes. It finds the object and the parent. The logical volume for the object is found, not only to check for mountedness but to ensure that its AIM limits allow the new classification. The branch entry reclassifies an object to the class of its parent. The access class of the parent (found in setup) is set for the son. Also, the son's multi-class attribute is forced off. Normal termination then proceeds. Changing the access class of the object involves changing the directory entry (requires the directory being write locked) and changing the VTOCE. For this, this program must lock the AST, fetch the VTOCE, patch the access .ifi hit "K|change_dtem" class and output the VTOCE. change_dtem is called to reflect this access change. If any of this fails, the soos switch is turned on for the son. sys_seg changes a segment to be multi-class. After a few checks, the access class is patched in, as well as the multi-class bit. In this case, normal termination involves unlocking the parent directory and performing a setfaults on the son (to pick up access class change). sum$dirmod is called. The node entry changes the access class of a directory and its contents. The process must have "sm" access to the directory for this to work, since this operation implies a directory name list function, as well as a reclassify function. The quota limit is obtained for this directory, so reclassify can later check for the presence of terminal quota. (In particular, if the directory is an upgraded directory, it must have a terminal quota account.) The parent directory is unlocked at this time, even though it will be needed later, to avoid holding it so long. The parent directory can be easily relocked later via sum. The directory is traversed, forcing the access class (and reseting the multi-class status) of all segments who are not multi-class segments of higher class than requested; for sub-directories, those equal to the access class have their multi-class status reset, those greater are set, and those less are set security out of service. A separate loop makes sure that all upgraded sub-directories have quota accounts; otherwise, they are set soos. This finishes the directory (after sum$dirmod). For the parent, though (who was locked earlier when the main directory's access class was set), reclassify makes the parent dir soos if it had an error setting the class for a sub-ordinate segment. .ifi l1h "ACL Primitives" There are two sets of ACL primitives. The module acl .ifi hit "K|properties~ACL" implements the old style primitives. The old style primitives had no concept of IACLs. They also merged the setting of ring brackets with the setting of ACL terms. asd_ and friends implement the new style calling sequence primitives. .ifi l2h "Old-style Primitives" acl implements the old-style ACL primitives. The actual work on ACL .ifi hit "K|acl" terms is performed by acl_. In the add side, there are two entrypoints, aadd to add a list of ACL terms and a1add to add a single ACL term. a1add creates a single element array of ACL terms from its arguments and joins the common code for ACL term addition. The code finds the appropriate directory entry, checks access modes, flags the directory as being modified, adds the ACL terms and then cleans up after itself. The areplace entrypoint replaces an entire ACL with another. It basically finds and locks the directory, deletes the old ACL, adds the new and then cleans up. The entrypoint adelete deletes terms from an ACL. In this entrypoint, a count of -1 means that all ACL terms are to be deleted. The internal routine delete_acl performs the deletion. Of course, these ACL changing primitives must call change_dtem and perform a setfaults on the segment. ACL listing is done by alist. Internal routines list_acl and list_acl_entries perform the listing, with the directory locked for reading only. Listing is performed into internal areas to avoid area problems. After the directory is unlocked, the ACL is copied to the user area, with an area handler set up if such an area needed to be allocated. .ifi l2h "New-style Primitives" asd_ contains the new style ACL primitives, the actual work on ACLs being performed by acl_. asd_ contains numerous entrypoints for .ifi hit "K|asd_" listing, deleting, replacing and adding ACL terms to ACLs. The list group consists of: list_idall (IACL for dirs), list_dall (ACL .ifi hit "K|properties~IACL" for a dir), list_isall (IACL for segs) and list_sall (ACL for a seg). Also present are entrypoint beginning with r_, which perform the same function as the non-r_ entrypoints but work with structures having refer extents. The actual work is performed by two internal routines, one for when a specified list of terms is desired (and the place for such ACL to be returned is therefore supplied) and one for when the entire ACL is desired, requiring the allocation of said list in the user supplied area, using the standard area .ifi hit "K|area return mechanism" return mechanism. But first, the directory is found, access checked and locked. For IACLs, the directory itself is found. For normal ACLs, the entry pointer is found. The ACL start pointer is found and the internal listing routines are called. The directory is unlocked. If the ACL count is zero, various kludges are applied to the returned lists to form valid pl1. In particular, a one element array specifying its extent (to the user) as zero is allocated. The delete, add and replace (ACL and IACL terms) entries all merge into one common code path. These entries consist of: del_identries (delete IACL for dirs), del_dentries (delete ACL for a dir), del_isentries (delete IACL for segs), del_sentries (delete ACL for a seg), replace_idall (replace IACL for dirs), replace_dall (replace ACL for a dir), replace_isall (replace IACL for segs), replace_sall (replace ACL for a seg), add_identries (add IACL for dirs), add_dentries (add ACL for a dir), add_isentries (add IACL for segs) and add_sentries (add ACL for a seg). The directory is found and locked for writing; it is flagged as being in the process of being modified. If the ACL being modified is the ACL of an .ifi hit "K|change_dtem" object, the dtem of the object is changed (change_dtem). For deletion of ACL terms, it is a simple matter to iterate over the supplied ACL terms, splitting them (acc_name_$elements) and use acl_$del_entry to delete the term. The ACL counts are maipulated also. The replace and add entries come next. It starts with the usual check for .ifi hit "K|check_gate_acl_" valid projects in ACL terms for non-ring 1 gates (check_gate_acl_). For the replace entries, the old ACL is first deleted. The SysDaemon ACL is put back if so indicated by arguments. For add or replace, the input ACL is iterated over, taking each term, copying it, taking it apart and adding it to the entry's ACL. The ACL term counts are updated. After this, the entry is setfaulted (unless IACLs are being manipulated) .ifi hit "K|setfaults" and the directory unlocked. Since the input list of ACL terms to add/delete/replace is variable .ifi hit "K|area input mechanism" extent, it is necessary to reference it with the directory locked. As a result, any random fault may occur during the changing of the ACL. Because of this, all such operations in asd_ run with an any_other handler enabled. (Note that the old style primitives do not need this, since they copied all (limited size) input structures into stack space before locking the directory.) This any_other handler provides a cushion, so that errors return to the user as an error code (error_table_$argerr) rather than a crawlout. The critical reason for the any_other handler, though, is that asd_ must ensure that a setfaults is done on the target segment, even if the ACL update does not finish, since an aborted operation may have partially changed the ACL. Aside from acl and asd_, a primitive between the old and new styles is .ifi hit "K|list_inacl_all" .ifi hit "K|properties~IACL" list_inacl_all. This primitive returns all IACLs (seg and dir) for all rings for a directory. The code is standard for directory control. It uses the same dc_find functions and return area management techniques as asd_. .ifi l1h "Ring Bracket Primitives" ringbr_ performs the user callable ring bracket getting and setting .ifi hit "K|ringbr_" .ifi hit "K|properties~ring brackets" functions. It involves a simple matter of validating input arguments, finding and locking the directory and then getting/changing the values. Of course, if the object is being made a gate, it must perform a check_gate_acl_. Also, the ring brackets of data management objects (as specified by performing a vtoc_attributes$get_info to get the synchronized flag) must follow those .ifi hit "K|change_dtem" rules. The dtem of the directory must be updated (change_dtem; also sum$dirmod must be called at the end). Also, setfaults must be called upon .ifi hit "K|setfaults" the object. (Refer to the section on directory control mechanisms.) .ifi l1h "Name Listing" The star name matching primitives for the file system are implemented .ifi hit "K|name list" .ifi hit "K|star_" within star_. The entrypoints are: star_ (normal) and star_priv (privileged entry) (perform a "normal" type list); list_dir ("dc_pack" type list); list_dir_fast ("fast" "dc_pack" type list); dir_list_ ("fast" "star_list" entry); list_ ("star_list" entry); list_priv ("star_list" privileged entry). A privileged entry is one in which "s" access is not needed on the directory to be listed. A "fast" list is one in which the VTOCE's of the individual objects are not needed to satisfy the request. If this is not a fast list, the sons_lvid (as specified in the dir header) must be mounted. A "star_list" entry returns a greater amount of information about each object (the difference between star_entry and star_list_branch or star_list_link in star_info.incl.pl1). A "dc_pack" operation returns even more information, in a format for backup. (See dc_pack.incl.pl1.) A "dc_pack" operation always matches **. Either way, the star name is examined and the types of objects to match determined. The usual mechanisms are used to find and lock the directory, .ifi hit "K|area return mechanism" checking access. Since the star list function returns a variable extent structure, the area return management policy is used. The internal entry MAKE_ENTRY_LIST counts the objects that match the desired star name. It special cases non-star names and makes a call to hash$search for efficiency. The internal routine RETURN_INFO drives the placement of the desired information into the allocated structures. It calls vtoc_attributes$get_info, if necessary, to get VTOC resident information. It then calls the routines that copies the desired data into the allocated structures, either RETURN_DCPACK_INFO or RETURN_STAR_INFO. .ifi l1h "File System Object Creation" append is the master routine for creating new file system objects. It is also used by the volume retriever/segment adopter. Entrypoints are: .ifi hit "K|append" .ifi hit "K|creation" master_dir, retv, create_branch_, branchx, branch and link. The first step is the getting of the various attributes of the new entry. These are set via arguments and defaults. When a branch is being appended, the access modes of the new branch must also be determined from the arguments. dc_find ensures that the object doesn't exist in the process of finding the target directory. The access checks for appending appear there. The directory is locked for writing. The tree depth of the directory is found; if a new directory is being appended, the maximum hierarchy tree depth cannot be exceeded. For retv calls, it is necessary to make a check against the UID of all branches in the directory. Either way, a hash search for the new name is performed; it is not allowed that it be found. If a segment is being appending, the target logical volume must be mounted. A UID is found for the segment (this is an supplied argument for the retv entry). With the directory locked and flagged as in progress of modification, the object can now be appended. Links are easy. Simply figure out how much space it will need, allocate it (fs_alloc$alloc) and fill it in. Branch appending is as follows. The IACL for the object is found (directory vs segment vs validation level). For segments, if the new object is a non-ring 1 gate, the IACL (combined with the user_acl term) must be valid .ifi hit "K|ACL" .ifi hit "K|IACL" (check_gate_acl_). A directory entry is allocated (fs_alloc$alloc) and its base filled in. (This is just copied from the supplied entry for the retv entry). The ACL is added. This consists of adding the service_acl term and then adding each term of the IACL and then the user_acl term. (For a cross retv operation, the user_acl is not added. If this is a retv operation but not a cross retv operation, no ACLs are added.) For any type of object, the supplied name is added to it and hashed in. The various other directory entry values are filled in. For branches, a VTOCE is now obtained (create_vtoce). Its VTOCE index is placed in the directory entry for the new branch. If this is a segment being created, finishing up consists of filling in the directory entry and updating the directory's segment count. If this is a directory being created, the internal routine setup_directory comes into play. This routine sets the same sort of information as for segments. It, however, wants to initialize the new directory. To setup a new directory, the directory into which the entry was just appended is set as not within modification. (This is to avoid possible .ifi hit "K|makeknown_" problems with lock claiming the parent needs salvaging). makeknown_ is called upon the new object. The quota is checked before the new directory is touched. The new directory header is filled in, a hash table created, etc. Quota supplied is moved to it, unless this is a master dir creation in which quota$append_mdir_set comes into play. If the priv_mqsw switch is on and the new access class is greater than the directory into which this was appended, the soos flag is set (which is what allowed us to create this directory for the retv). This new directory is flagged as modified (sum$dirmod) and made unknown. The directory into which this directory was appended is re-flagged as currently undergoing modification, and normal append finishing is run. Note that the setup described above is not performed for the cross retv operation, who will later supply the directory/segment contents. The final step is to thread this new object into the directory lists, flag the directory as modified (sum$dirmod) and unlock this directory. The file system call hcs_$make_seg calls make_seg, which simply calls .ifi hit "K|make_seg" .ifi hit "K|initiate_" append$branch and then initiate_. .ifi l1h "File System Object Renaming" chname is the module for adding and deleting (and changing) names on .ifi hit "K|renaming" .ifi hit "K|chname" directory entries. It comes in three flavors, one (cfile) which takes a directory and entry name, one (cseg) which takes a pointer to an initiated segment and a retv entrypoint is supplied with the directory entry pointer. The arguments are an old and new name; if the old name is blank, this implies an addname of the new; if the new name is blank, this implies a deletename of the old; if both are supplied, this implies a rename. A check is made to ensure that the only name on the entry is being deleted. The first step is to add the new name, if present. It is hashed into the directory (which checks for name duplication) and this new name block is allocated and threaded into the list of names. The old name is then deleted. A hash search for the name is done, it is unhashed and threaded out of the entry's name list. The name block is freed from the directory. If the name being deleted was the primary name, this adds a complication. The primary name is stored in the entry structure itself. So, the old primary name must be removed, the next name in the name list picked and threaded out, put into the entry structure, and then hashed in its new location. Also, if the primary name is deleted, the AST name table entry for this segment must be changed. If this object is a directory, the pathname associative memory entries .ifi hit "K|PAM" for the name are flushed. The directory is cleared of its being modified state and sum$dirmod notices the modification. .ifi l1h "File System Object Deletion" The logic involved in deleting a file system object is contained within .ifi hit "K|deletion" .ifi hit "K|delentry" delentry. It has multiple entrypoints for calling from the user ring through hcs_ and entries for ring zero operations. The normal entrypoints are dfile and dseg, which take a dirname/entryname pair and a initiated segment pointer, respectively. There is also a priv_dfile entry, to set the priv_entry flag, which bypasses access checking (among other things). The priv_duid entry deletes an object given its UID path. The retv entrypoint is used to bypass access checking. Finally, the salv_delete_branch entry is used by the salvager to delete a branch without thinking about its (bad) VTOCE. The salv_delete_branch and retv entries supplied the directory entry pointer for the object. All other entries must use dc_find to find the entry and check access. The type of the entry to delete is found. Links are easy and bypass the following operations. For branches, the user must be in the "w" or "m" brackets of the object and the safety and copy switches must be off, except for the retv and privileged entries. If this is a directory to be delete, it must be empty. makeknown_ is used to activate the directory to be deleted. At this time, the parent is unlocked. This is done since the son will be locked, and the locking .ifi hit "K|directory~locks~hierarchy" hierarchy requires the parent to be unlocked at this time. The sub-directory is locked. If this succeeds, the parent is relocked, rechecking access. Now the directory can be checked for emptiness. For segments, the volume containing them must be mounted. (Such a check was unnecessary for directories.) The VTOCE of the branch is deleted (delete_vtoce) freeing the pages. All entries join eventually. The entry is removed from the directory. The name is hashed out. Its ACL is deleted. The acc_name structure for the author and bit_count author are deleted. The entry is unthreaded. If this is directory, then if it is per-process, the pathname associative memory from .ifi hit "K|PAM" here down is flushed; otherwise, this entry is simply removed from the PAM. sum$dirmod reflects the modification of the parent. If this was the deletion of a directory, it is unlocked. (It was kept locked so no one could create in it while it was being deleted.) A side door to directory unlocking must be used to unlock this directory, since it is no longer here. Final cleanup proceeds as normal. .ifi l2h "Sub-tree Deletion" As a practical matter, most deletions of a set of objects, or of a sub-tree, are performed via outer ring logic calling the file system .ifi hit "K|deletion~sub-tree" primitives repeatedly. This is especially necessary so as to be able to delete mailboxes and the like. However, there is a sub-tree deleting .ifi hit "K|del_dir_tree" primitive used now and again. It is del_dir_tree. del_dir_tree deletes all entries in a directory. It is a recursive program, recursing down the directory subtree to delete objects in subordinate directories. The program is basically viewed as a ring 0 star_list program, that uses delentry to delete the objects it lists. Since one cannot delete an entry (delentry or del_dir_tree$recurse) unless the directory is unlocked, the directory is unlocked during the delentry call. After each call, the .ifi hit "K|directory~locks~relocking" directory must be relocked, validating access. This is repeated until the directory is empty. During the unlocked time a seg_fault_error handler is kept ready to catch deletions of the directory. Also, if the delete of the subordinate entry fails because of the safety or copy switches being set, they are reset and another try of the deletion made. Deletion of subordinate directories containing other objects is handled by recursing on del_dir_tree. If this fails because of access, access is forced. .ifi l1h "Property Getting Primitives" As mentioned in the section on access control, the properties of file system properties are divided into three groups: status, attribute and contents properties. The ACL status properties are described above. Various attribute properties of file system objects within the address .ifi hit "K|properties~attribute" space, most notably the process' access to them, may be obtained by .ifi hit "K|fs_get" .ifi hit "K|KST" .ifi hit "K|SDW" fs_get. This access is computed basically from the KSTE/SDW information (by dc_find). Also present within fs_get are various ref_name asssociated things. These include fs_get$seg_ptr, which simply calls ref_name_$get_segno; fs_get$search_rules which copies, expanding segment numbers into pathnames, .ifi hit "K|RNT" the search rules from the RNT of the given ring; fs_get$path_name which does a .ifi hit "K|get_pathname_" get_pathname_ (after enforcing the name lookup policy on the segment number via dc_find); fs_get$ref_name which returns the nth refname (from ref_name_$get_refnames); fs_get$trans_sw which returns (and sets) pds$transparent; fs_get$get_link_target which simply calls the link tracer in .ifi hit "K|link target" dc_find. The status_ primitive is the usual target of attribute property requests. .ifi hit "K|status_" It comes in various flavors, depending on the internal variable status_call. .ifi hit "K|properties~status" The meaningful values are 0, ENTRY_status_ (1), ENTRY_status_long (2) and ENTRY_status_min (3). The differences include, obviously, what function is performed. The variable has other side effects, though. The values of 1 and 2 are used for the traditional status calls that return hoardes of information. A value of 0 is used by entries like get_author. A value of 3 is used by entries like get_safety_sw. The value of 0 requires "s" permission on the directory containing the object. A value of 3 allows for "s" on the directory or non-null on the object itself. For values of 1 and 2, not having "s" permission but having non-null access on the object allows attribute properties to be returned, but not status properties. The general operation of the routine is straightforward. Note that the main status entries use the .ifi hit "K|area return mechanism" return area mechanism described under file system mechanisms for returning the entry's names. .ifi l1h "Segment Initiation" initiate_ is the workings for hcs_$initiate and other related calls. It .ifi hit "K|initiation" .ifi hit "K|initiate_" is also used by certain ring zero primitives to make a segment known in the process. Its entries are: initiate_ and initiate_count (normal entries), .ifi hit "K|privilege~dir" priv_init and priv_init_count (work with the equivalent of dir privilege and use raw versus effective access mode), initiate_seg_count and initiate_seg (take a directory pointer and entryname instead of the directory and entry name). dc_find finds the corresponding directory entry, checking for non-null effective access. The object is checked to be on a mounted logical volume. Given the directory entry, an attempt is made to make the segment known. The directory is unlocked since KST garbage collection might occur while the segment is being made known, but the directory is segno held. makeknown_ is .ifi hit "K|makeknown_" called. Refer to address and name space management for more details. The ref name supplied is added to the RNT (ref_name_$insert). Finally, a .ifi hit "K|RNT" .ifi hit "K|ref_name_" check is made to see if the LOT for the given ring must be grown to handle this new segment number. Also present within initiate_ is an entry that doesn't actually initiate the target, it just finds its directory entry and decides (via a kstsrch) whether the segment is known to the process. This is provided as an optimization for delete_, who uses this information (the returned segment pointer) to decide if the segment being deleted needs to be terminated (via term_) before the deletion. .ifi l1h "Segment Termination" User requests for segment termination are made to terminate_, the inverse .ifi hit "K|termination" .ifi hit "K|terminate_" of initiate_. It consists of basically just a call to makeunknown_, after the name lookup enforcement done by dc_find. It will also zero the LOT entry for .ifi hit "K|LOT" .ifi hit "K|RNT" the segment, and delete the refnames for the segment. Refer to address and name space management for more details. .ifi l1h "Dynamic Linker Support" Although the operation of the dynamic linker is beyond the scope of this .ifi hit "K|dynamic linker" manual, the file system support for dynamic linker searches is described here. fs_search performs the work of finding an object given the search rules. .ifi hit "K|fs_search" Since this module is the user of search rules, it is also the keeper of the .ifi hit "K|working directory" working directory, which is maintained with the get_wdir and set_wdir entrypoints. The operation is a simple matter of testing each search rule. Before trying any search rules, though, fs_search makes a test reference of the stack for the ring of validation. This is done so as to force the .ifi hit "K|RNT" .ifi hit "K|makestack" invocation of makestack, if this is a new ring, so that the RNT and search rules will be initialized. For real directory search rules, this module finds the directory given the segment number. (Two tests are performed for validity. Since search rules are saved by directory segment number, and the directories in question can be terminated by the user, this segment number must be checked to see if if still refers to the directory it should be (search rule directory UID = .ifi hit "K|initiate_" kste.uid).) initiate_$initiate_seg_count initiates the segment. (Refer to the section on access control for special processing of the name lookup rule by this entrypoint.) The initiated segments search rule performs a RNT look up, with .ifi hit "K|ref_name_" ref_name_$getr_segno. The working_dir search rule uses the value of the working dir internally recorded (pds$wdir (ring)). The referencing_dir search rule keys off the directory indicated by the input reference pointer. (The KSTE entry for this segment is found and its parent (kste.entryp) determines the directory to search.) initiate_search_rules maintains the search rules for a user (per ring, in .ifi hit "K|search rules" .ifi hit "K|initiate_search_rules" the RNT) and the system search rules (in active_hardcore_data). This later function is performed under the protection of active_hardcore_data$search_rules_lock. initiate_search_rules is called when the user changes the search rules, and also whenever a new stack is created (by makestack). Adding a rule to a user search rule list is a simple array operation. When adding a pathname, though, dc_find enforces the name lookup policy, obtaining/finding a segment number for it in the process. This number (and the directory's UID) are kept in the search rule data. The directories so found are held via their usage counts. When supplying a new set of search rules to replace an existing set, then, the usage counts of the old search .ifi hit "K|making unknown~directories" rule directories must be decremented to un-hold them. (Of course, this dereferencing (potentially causing a future making unknown) must audit, enforcing the name lookup policy via dc_find.) Setting the working directory is functionally the same as setting a search rule directory. .ifi l1h "Property Setting Primitives" set .ifi hit "K|set" .ifi hit "K|properties~attribute" allows the setting of myriads of object attributes. Common to all of these are the internal procedures find_entry and get_entry_ptr. find_entry finds the directory entry in question. get_entry_ptr works given a segment pointer to find the directory entry. Either way, they extract the dirsw and check ring brackets of the final object, if necessary. The finish up portion of set takes two flavors: finish and unlock. finish updates the dtem of the object (unless transparent modify is specified) and then proceeds to unlock. unlock performs the sum$dirmod and the unlocking of the directory. Within the usual file system limitations and rules, the setting of the properties is straight forward. A few special notices are listed below. The auth setting function must use acc_name_ to delete the old author and add the new author. The bit count functions must likewise use acc_name_ to delete the old and add the new bit_count author. When setting dates, only the dtem and dtd can be set in the branch. The dtu and dtm must be set in the VTOCE/ASTE by vtoc_attributes. All references to VTOCEs are nice enough to make sure that the logical volume is mounted first. The setting of the volume_dump_switches, dnzp (don't null zero pages), synchronized switch, max length and the damaged switch must also reference the VTOCE via vtoc_attributes. The setting of the entry bound (call limiter) is not allowed for directories. It is necessary to setfaults the segment being so set. set_for_reloader is used to set all sorts of values by the reloader. It can set: safety_sw; tpd (transparent paging device (obsolete)); author; bit count author; dtu, dtm and max length (vtoc_attributes); dtem and dtd; entry .ifi hit "K|setfaults" bound (note that it is not necessary to setfaults when setting the entry bound if the max length was set since this would have caused a setfaults earlier and the segment can not be reconnected to anyone's process since the directory is write locked). .ifi l1h "Segment Truncation" Although a segment can be truncated by simply zeroing trailing pages, .ifi hit "K|truncation" .ifi hit "K|truncate" this is not efficient. So, truncate is provided to truncate (zeroes and frees the end) of segments by releasing pages directly. The segment must not be a directory. truncate_vtoce truncates the desired trailing pages followed by sum$dirmod reflected the length change. The truncation of the segment to a desired word is done by hand. .ifi l1h "Quota Primitives" quota .ifi hit "K|quota" is the file system interface to quota maintenance. It operates freely on the quota limits but needs quotaw to manipulate the quota used cells. To call quotaw, quota must find the appropriate ASTE and thereby lock the AST. Otherwise, only the directories in question need be locked. Many of the entries start by calling get_quota_cell to find the quota cell. This involves finding the directory whose cell is needed, locking it as required, and using vtoc_attributes$get_quota to fetch the quota cell. The entries dqlong_reset and qlong_reset are used by accounting to reset the trp (time record product) for the directory. They subtract the specified amount from the trp figure. The original quota cell is obtained by get_quota_cell, locking the directory for writing (which prevents activation/deactivation and other possible changes to the quota terminal-ness). sum$dirmod reflects that the directory was changed. dqset and qset set a quota limit. dqrestor and qrestor/qreload set the quota limit as well as the trp and the tup (time of trp update) for the reloaders. They are all privileged entries. They also fetch the quota cell, locking the directory for writing. The directory is forced to be active so that direct references can be made to ASTE values. If the terminal quota status of this cell isn't changing, the ASTE can be simply patched. Otherwise, quotaw must be used to walk up the quota hierarchy to the terminal account to change the quotas and terminal status. The AST is unlocked (locked in activating the directory), unlock the parent and record the directory as modified (sum$dirmod). mdir_set sets the quota on a master directory. append_mdir_set is used by append to set the initial quota for a master directory. dqread and qread/qget, along with priv_dqread and priv_qread (who do not check access) get the current quota and trp values for a directory. The quota cell is obtained, the directory locked, and the directory made active so that the used figures can be obtained, the trp updated while this is being done, and the information returned. check, check_file and check_seg check to see if the quota used on a cell may be increased by a given amount within the quota limit present. The actual work is done by quotaw (under the PTL). dqmove and qmove perform a move quota between a parent and its son. The arguments are the pathname of the parent and the entryname of the son. This starts by finding the son directory. An interesting manifestation of this particular system function is that a user is allowed to move quota from a directory to an upgraded directory from an authorization equal to that of the lower directory's access class. This special casing is understood by dc_find. All qmove entries obtain the qcells for the parent and son directories. The various validity checks for quota moving (not down from master_dir, parent has no quota limit, etc) are done. Both directories are made active (forcing son active forces parent). The trp of both are updated since a change in both directory's quota cells is being made which would screw up a subsequent trp update. quotaw$mq performs the actual move (since this operation may change the directory that holds the terminal account. quota will manually update the location of the terminal trp cell if this is necessary.) vtoc_attributes writes back the quota cells (limits; the usage values are extracted from ASTE information). .ifi l1h "Miscelaneous Functions" Various unique (mostly privileged support) functions are listed. .ifi l2h "Quota Correction" correct_qused examines the number of pages used by the objects .ifi hit "K|correct_qused" subordinate to a directory to correct the quota used figure for the directory. The operation of this function is described in the storage system PLM. The support provided to this primitive by directory control is that correct_qused uses a write lock on a directory to eliminate the possibility of segment creations and deletions. Also, the set of active segments subordinate to this .ifi hit "K|directory~locks~effect on connection" directory cannot change by virtue of this write lock (refer to the section on directory locks for details). .ifi l2h "Root Directory Creation" The root directory is created, during a cold boot initialization, by .ifi hit "K|create_root_dir" create_root_dir. This program simply fills in the directory header and hash table for the new (empty) root dir. .ifi l2h "Dump Copying" A dump found in the dump partition is copied into hierarchy segments by .ifi hit "K|copy_fdump" copy_fdump (name is historic). The creation of the hierarchy segments is via a normal call to append. The only thing interesting about this program is its creation of a rolling abs-seg on the dump partition; this mechanism is described in the Initialization SDN. .ifi l2h "Segment Moving" fs_move moves segments. It is a basically obsolete function that could .ifi hit "K|fs_move" just as well be performed in the user ring. It moves data from one segment to another by optionally truncating the target and moving data in (no deletion of target) and then truncating the source. On its way it checks for max length limits and quota, to help ensure success of the move. These checks are not done under any locks, though, so there is no guarantee. On the other hand, there is the real segment mover, invoked via .ifi hit "K|vacate_pv" vacate_pv. For a segment, the segment entry is found, the segment made known (makeknown_), the segment activated (activate) and the segment mover called. All of these locks are then undone. (vacate_pv also sets and resets the vacating flag for a physical volume; this mechanism is described in the Storage System PLM.) .ifi l2h "Volume Retriever/Dumper" The file system support for the volume dumper/retriever is imbedded within hc_dmpr_primitives, retv_copy and retv_util. .ifi l3h "Volume Dumper" hc_dmpr_primitives contains hardcore utilities for the volume dumper. It .ifi hit "K|hc_dmpr_primitives" .ifi hit "K|volume dumper" has a curious pseudo relationship to directory control. The volume dumper .ifi hit "K|directory~pseudo" internally builds abs-segs describing a segment on a physical volume it wishes to dump. For segments that are active, it wants to use the ASTE they have, keeping the AST locked to prevent segmoves, boundfaults, etc. For not active segments, it wants to activate them (using an abs-seg built given their VTOCE), but in such a way as to prevent some other process from activating them (using their branch info) without its having to hold the AST lock (which would make it hard to activate the segment). To do this requires a write lock on the objects' containing dir. Since is is not desirable to have to find this dir, this program builds a pseudo-dir, with the UID of the directory that would have been wanted to lock within it. lock$dir_lock_write is then called. lock is capable of dealing with this pseudo-dir. If some other process wanted to lock the real dir, lock could not tell the difference between this pseudo-dir and the real one, since such a match is done by UID. This mechanism, then, is part of the abs mechanisms for fetching the segment upon which to operate. .ifi l3h "Volume Retriever" retv_copy is the hardcore routine that copies data into a segment or .ifi hit "K|retv_copy" .ifi hit "K|volume retriever" directory for the volume retriever. This function exists as a hardcore primitive so as to provide a controlled way of replacing a directory with another. The basic operation is to find the object's directory entry which may or may not have a corresponding VTOCE at this time, locking the directory in the process, check access, find or create the VTOCE, make the segment known and then copy the new data in. Various VTOC attributes are then set from the supplied arguments. During the course of the copy, rw access is forced on in the segment in this process. The object is entry held and its parent locked so this access cannot be changed (or anyone else get to the segment). The operation for a directory is harder. Basically the directory that is being installed wants to match up with what is being replaced. That is, any objects in the old dir not in the new should be deleted. Also, any in the old that are in the new should be preserved as is. To get and keep the directory in sync, it is locked. Since it may not really exist (have no VTOCE or contents), a pseudo directory is built for the lock routine to have. The directory matchup routine walks down the old directory. For each entry it finds in the new also, it copies the old pvid and VTOCE index into the new entry. If the object is not in the new dir, it deletes it. To do this, it unlocks this directory (which it does using the real directory, now that it .ifi hit "K|del_dir_tree" .ifi hit "K|delentry" exists) and unlocks the parent so that del_dir_tree or delentry (both using the retv entrypoint) can eliminate the object. After this, the directory and its parent are relocked (following the directory relocking rules) and the scan restarted. This eventually succeeds when the dirs are in sync. Any object that can't be deleted is put on a list of objects to just ignore. When the directory is replaced, they will go away by not being findable. The other operation necessary for directories is maintaining the quota tree. When the parent's entry was locked, its quota info was fetched. The quota for this new dir is found as well as the sum of that received from its inferiors. If it was necessary to create a VTOCE for this new directory, its quota info is useless and that supplied by the input VTOCE is used. Otherwise, only the quota and received figures supplied apply. The check that is desired is that the quota received from this directory plus that received .ifi hit "K|quota" from its inferiors plus the parent quota is less than or equal to that distributed by the parent. If this is so, the quota for this new directory can be set with that computed safely, without destroying the quota tree. Otherwise, the quota must be forced to 1 (non-zero) to force this directory to have terminal quota. retv_util provides various utilities for the volume retriever. The delete .ifi hit "K|retv_util" entry deletes an object by calling delentry$salv_delete_branch. The set_bc entry patches the bit count in the entry, returning the old bit count. The get entry returns the contents of the directory entry. The check entry returns the object type and dtm. The status entry also returns the user effmode, user mode on parent, UID, pvid, volid and dtd. The name_list entry returns all of the names on the object. It uses the standard area return .ifi hit "K|area return mechanism" management mechanism when returning the names. The addname entry uses chname$retv to bypass access checks. The add_acl entry uses acl_$add_entry to add ACL terms. It adds the terms on an all or nothing basis. sum$dirmod is called. .ifi l2h "Privileged Versions of Operations" The file system provides certain privileged versions of some file system primitives. Some are mentioned above. Aside from these, there exists level_0_, which performs the work of the .ifi hit "K|level_0_" hphcs_$foo entries that do not have special privileged entrypoints. It simply sets the validation level to 0, calls the equivalent function, and resets the validation level. ring0_init .ifi hit "K|ring0_init" .ifi hit "K|privilege~initiation" performs the phcs_$foo functions with respect to initiating and terminating objects. It sets the validation level to 0, performs the operation, and resets the validation level. .ifi l2h "Set Sons LVID" set_sons_lvid sets the sons LVID for a directory. The program starts .ifi hit "K|set_sons_lvid" with a little bit of fancy lock footwork, in that the access check is made against the parent of the target directory, and so dc_find must be called upon .ifi hit "K|directory~locks~hierarchy" the parent. However, the target directory itself needs to be locked, and so it is necessary to unlock the parent and relock it after the son is locked. (Refer to the section on holding directory entries). The LVID is set (as well as the fact that this becomes a master dir) in the directory header. If the directory is active, its AST is found and the master dir bit sit on there also. sum$dirmod is called on the directory. The entrypoint set_rpv within this module does the same things as above, except that it sets the force_rpv bit in the directory header (to apply to this dir's sons). .ifi l2h "Disk Table Location" When a disk_table_ is created, the Initializer records its location in .ifi hit "K|set_disk_table_loc" the RPV label via set_disk_table_loc. This program simply extracts the UID and VTOCE index from the branch for disk_table_, and forces them into the label (fsout_vol). .ifi l2h "Temp Wiring" user_wire is the interface to pc_wired$wire_wait and pc_wired$unwire. It .ifi hit "K|user_wire" accepts either a pathname or a segptr. The entry pointer is fed to activate. If wiring is being done, the ASTE is entry held so that pc_wired will work (and the pages stay). The AST is unlocked and the directory unlocked before leaving. .ifi l2h "UID Path Utilities" uid_path_util performs mapping of UID pathnames into real pathnames and .ifi hit "K|uid_path_util" the mapping of segment pointers and pathnames into UID pathnames. The get entry is given a pointer to a directory and returns the UID pathname of its parent. This is a simple matter of iteratively calling get_kstep$dir and looking up the UIDs within the KST entries. Just as kst_info, this entry has no access requirements since it returns only KST information. This information could not have changed since the object in question was initiated; also, this information is not affected by whether the object still exists or not. get_uid_path is a gate entry which, given a pathname, returns a UID pathname. It uses dc_find to get an entry pointer, derives the directory pointer from that, and uses uid_path_util$get. decode_uidpath is a gate entry which, given a UID pathname, returns a directory and entry name. It also uses dc_find for the lookup. .brp ----------------------------------------------------------- Historical Background This edition of the Multics software materials and documentation is provided and donated to Massachusetts Institute of Technology by Group BULL including BULL HN Information Systems Inc. as a contribution to computer science knowledge. This donation is made also to give evidence of the common contributions of Massachusetts Institute of Technology, Bell Laboratories, General Electric, Honeywell Information Systems Inc., Honeywell BULL Inc., Groupe BULL and BULL HN Information Systems Inc. to the development of this operating system. Multics development was initiated by Massachusetts Institute of Technology Project MAC (1963-1970), renamed the MIT Laboratory for Computer Science and Artificial Intelligence in the mid 1970s, under the leadership of Professor Fernando Jose Corbato. Users consider that Multics provided the best software architecture for managing computer hardware properly and for executing programs. Many subsequent operating systems incorporated Multics principles. Multics was distributed in 1975 to 2000 by Group Bull in Europe , and in the U.S. by Bull HN Information Systems Inc., as successor in interest by change in name only to Honeywell Bull Inc. and Honeywell Information Systems Inc. . ----------------------------------------------------------- Permission to use, copy, modify, and distribute these programs and their documentation for any purpose and without fee is hereby granted,provided that the below copyright notice and historical background appear in all copies and that both the copyright notice and historical background and this permission notice appear in supporting documentation, and that the names of MIT, HIS, BULL or BULL HN not be used in advertising or publicity pertaining to distribution of the programs without specific prior written permission. Copyright 1972 by Massachusetts Institute of Technology and Honeywell Information Systems Inc. Copyright 2006 by BULL HN Information Systems Inc. Copyright 2006 by Bull SAS All Rights Reserved