COMPUTER METHOD AND APPARATUS FOR ASYNCHRONOUS ORDERED OPERATIONS

Abstract: A computer system having data organized in files, having a secondary storage for storing files, having a primary storage, and having one or more types of subsystems (file system implementations) for controlling transfer of files between primary storage and secondary storage. A subset of writes to secondary storage are performed using a Delayed Ordered Write (DOW) subsystem, as shown in the figure, which makes it possible for any file system to control the order in which modifications are propagated to disk. The DOW subsystem (30) consists of two parts. The first part is a specification interface, which a file system implementation or any other kernel subsystem can use to indicate sequential ordering between a modification and some other modification of file system structural data. The second part of DOW subsystem is a mechanism that ensures that the disk write operations are indeed in accordance with an order store. DOW improves computer system performance by reducing disk traffic as well as the number of context switches that would be generated if synchronous writes were used for ordering.

Description: TITLE COMPUTER METHOD AND APPARATUS FOR ASYNCHRONOUS ORDERED OPERATIONS INVENTORS A portion of the disclosure of this patent document contains material which is subject to copyright protection. The copyright owner has no objection to the facsimile reproduction by anyone of the patent document or the patent disclosure, as it appears in the Patent and Trademark Office patent file or records, but otherwise reserves all copyright rights whatsoever. BACKGROUND OF THE INVENTION The present invention relates to computer systems and to file system implementations for computer operating systems and methods and apparatus used by file systems for controlling the order of operations, such as the order in which information is updated on secondary storage, to realize gains in performance. Computer systems are composed of hardware and software. The hardware includes one or more processors, typically a central processing unit (CPU), main storage or memory, secondary storage, and other input output I/O) devices. The software includes an operating system and user (application) programs. The computer system executes user programs in the hardware under the control of the operating system. The operating system controls the operation of secondary storage devices and other I/O devices such as terminals through a set of software modules called device drivers. In modern computer systems, secondary storage systems such as disks have become performance bottlenecks because processors have higher speeds than disks. Various methods have been used to minimize the impact of disk subsystems on overall system performance. For example, some disk controllers employ large random access memories as disk caches in order to reduce the number of slower disk accesses. Operating system device drivers use a variety of algorithms to schedule disk requests so that they can be serviced with minimum mechanical movement or delays within the disk hardware. Some file system implementations log their operations so that it is not critical to have all intermediate information updates applied immediately to secondary storage. See, for example, Mendel Rosenblum and John K. Ousterhout, "The Design and Implementation of a Log Structured File System," Proceedings of the 13th ACM Symposium on Operating System Principles (October 1991), and Robert Hagmann, "Reimplementing the Cedar File System using Logging and Group Commit, " Proceedings of the 11th ACM Symposium on Operating Systems Principles (November 1987). By way of background, three types of writes exist for writing information to disk storage, namely, Synchronous, Asynchronous, and Delayed writes. With a synchronous write, the computer system suspends execution of the program that caused the write to occur. When the write completes, the program is allowed to continue. With an asynchronous write, the computer system permits the program to continue, after enqueuing the request for writing with the device drivers that manage the operation of disks. In this case, the program can make further progress, even though the actual information to be written is not yet stored to disk. Delayed writing is a special type of asynchronous write, in which the execution of the program is allowed to continue without enqueuing the write request with the device drivers. In this case, the buffer in memory that is modified during the write is marked as needing to be written to disk, and the request is propagated to the device drivers by the operating system at a later time. Generally, the operating system ensures that the request propagates within a finite time interval. Asynchronous writes achieve a performance advantage over synchronous writes by decoupling the execution of processors from disk subsystems and allowing more overlap between them. Delayed writes improve the decoupling and serve to reduce the aggregate number of disk writes by allowing multiple modifications of the same buffer to be propagated to the disk with a single disk write. Despite the performance advantage of using asynchronous and delayed writes over synchronous writes as described above, many file system implementations employ synchronous write operations for recording changes to file system structural (administrative) data. Synchronous writing is used so that the file system implementation can regulate the order in which structural changes appear- on the disk. By controlling the order in which modifications of structural data are written to disk, a file system implementation achieves the capability to perform file system repairs in the event that a system crash occurs before a sequence of structural changes can complete and reach a self-consistent organization of file system structural information. The specific requirements for ordering updates of structural data vary according to file system implementation as described, for example, in M. Bach, "The Design of the UNIX Operating System," Prentice-Hall, Englewood Cliffs, 1986. An example of a utility for repairing file systems following a crash, the fsck program, is described in M. McKusick, W. Joy, S. Leffler, and S. Fabry, "Fsck - The UNIX File System Check Program," UNIX System Manager's Manual - 4.3 BSD Virtual Vax-11 Version, USENIX, April 1986. As described above, many file system implementations need to perform ordered disk writing for maintaining structural order and repairability and therefore they employ synchronous writes that maintain the order of disk writes. The use of synchronous writes, however, limits system performance since disks and other secondary storage devices are slower relative to processors and main memory. File system formats can be designed to minimize the number of distinct disk updates needed for accomplishing a consistent reorganization of structure. Alternative techniques for repairability, such as intent logging, provide the ability to recover from an incomplete sequence of disk modifications. Such alternatives, while being beneficial to performance, have proved overly burdensome due to loss of media or software compatibility. Accordingly, there is a need for an improved operating system that provides control of write ordering without the performance penalty of synchronous writing and without mandating special hardware, new media formats or other changes. SUMMARY OF THE INVENTION The present invention applies to a computer system having data organized in files, having a secondary storage for storing files, having a primary storage, and having one or more types of file subsystems (file system implementations) for controlling transfer of files between primary storage and secondary storage. A subset of writes to secondary storage are performed using a Delayed Ordered Write (DOW) subsystem, which makes it possible for any file system to control the order in which modifications are propagated to disk. The DOW subsystem consists of two parts. The first part is a specification interface, which a file system implementation or any other kernel subsystem can use to indicate sequential ordering between a modification and some other modification of file system structural data. The use of the specification interface by any file system implementation results implicitly in the construction of an order store in primary storage, that records the ordering interdependence among different buffers affected by the modifications. The second part of DOW subsystem is a mechanism that ensures that the disk write operations are indeed performed in accordance with the order store. The DOW subsystem accomplishes this task by both intercepting and initiating disk write operations, as needed, to control the actual sequence of writes presented to device drivers. DOW improves computer system performance by reducing disk traffic as well as the number of context switches that would be generated if synchronous writes were used for ordering. The use of DOW for controlling the order of structural updates does not require a structural redesign of a file system format, or changes to the system hardware or device drivers. Replacing synchronous writing by DOW-maintained ordered writing provides large gains in system performance. DOW is modular and is loosely coupled with other kernel subsystems, including the file system implementations that use it. It does not require any modifications to other kernel subsystems or to the standard file system interfaces. Any file system type (implementation) in the operating system can use DOW easily, without structural redesign and without loss of media compatibility. The file system implementation that uses DOW only needs to specify the necessary ordering, if any, among a sequence of structural changes in lieu of forcing synchronous writes. While DOW thus provides an alternate mechanism for regulating the disk writing, the file system implementation retains control of the policy — that is, control of which modifications should be ordered relative to each other. Thus, DOW allows a computer system to obtain the performance advantage associated with delayed writes while retaining the file system repairability characteristics that come with ordered writing. The foregoing and other objects, features and advantages of the invention will be apparent from the following detailed description in conjunction with the drawings. BRIEF DESCRIPTION OF THE DRAWINGS FIG. 1 depicts a block diagram of a computer system employing ordered operations including, for example, delayed ordered writes to secondary storage. FIG. 2 depicts a block diagram of the operating system software of the computer system of FIG. 1. FIG. 3 depicts a block .diagram of an example of the processing of a remove (rm) command that causes writes in the system of FIGs. 1 and 2 using synchronous writes. FIG. 4 depicts a block diagram of a directed acyclic graph for the FIG. 3 example of the processing of a remove (rm) command that causes writes in the system of FIGs. 1 and 2 using delayed ordered writes (DOW). -4- SUBS 1TUTE SHEET (RULE 26) FIG. 5 depicts a block diagram of an example of the processing of two touch commands and two remove commands that cause writes in the system of FIGs. 1 and 2 using synchronous writes. FIG. 6 depicts a block diagram of a directed acyclic graph for the FIG. 5 example of the processing of commands that cause writes in the system of FIGs. 1 and 2 using delayed ordered writes (DOW). FIG. 7 depicts an array of data structures that constitute the operation (node) entries in an ordering store. FIG. 8 depicts an array of data structures that constitute the order (link) entries in an ordering store. FIG. 9 depicts the manner in which predecessor and dependant entries are organized using pointers in the ordering store. FIG. 10 depicts the ordering of entries in the ordering store for the FIG. 4 example. FIG. 11 depicts a block diagram of the processing in which a write request is reserved for an inode buffer represented by a DOW node. FIG. 12 depicts a block diagram of the processing in which nodes C and E are marked pruned and the A node is moved to the dow flush chain. FIG. 13 depicts a block diagram of the processing in which the C node is moved to the dow flush chain after buffer write node completes. FIG. 14 depicts a block diagram of the processing in which the E and F nodes are moved to the dow flush chain after buffer write completes for the C node. FIG. 15 depicts normalized system throughput for users with and without delayed ordered writes. FIG. 16 depicts disk writes per user with and without delayed ordered writes. FIG. 17 depicts context switches per user for synchronous writes and delayed ordered writes. FIG. 18 depicts average disk service time for synchronous writes and delayed ordered writes. FIG. 19 depicts a block diagram of a computer system employing ordered operations in a network environment. FIG. 20 depicts a block diagram of the processing for the computer system of FIG. 20. DETAILED DESCRIPTION Computer System General - FIG. 1 The computer system 3 of FIG. 1 is composed of hardware 5 and software 6. The hardware 5 includes one or more processors 10, typically a central processing unit (CPU), main storage 11, input/output (I/O) in the form of secondary storage 12 and other input/output devices 13-1, ..., 13-N. The software 6 includes an operating system 14 and user (application) programs 15. The computer system 3 executes user programs 15 in the hardware 5 under control of the operating system 14. A common instance of the operating system 14 is the UNIX* operating system. UNIX Operating System - FIG. 2 Referring to FIG. 2, the UNIX operating system has files and processes that execute under the control of a kernel 20. A process is a computer program in a state of execution. The computer system of FIG. 1, when running the UNIX operating system, has three levels of operation: user 21, kernel 20, and hardware 5. Typically, application programs run at user level, and request the services of the operating system by means of system calls. A system call interface 31 and libraries 22 exist for this purpose; the libraries 22 are linked in with the user programs 15 and map system calls to primitives that the kernel 20 recognizes. The kernel 20 acts as a resource manager for all of the resources of hardware 5 of the computer system 3 of FIG. 1. Primarily the kernel has two functions. The first is to provide a large degree of device independence to the application programs by masking details of the various hardware resources needed during computation. The second is to perform various supervisory and control functions so that the needed resources are scheduled as necessary. The kernel is partitioned into a process control subsystem 35, a file management subsystem 32, a memory management subsystem 38, and other supporting subsystems. The process control subsystem 35 creates or terminates processes in response to explicit or implicit user requests, controls process behavior, obtains the resources that are necessary from the other subsystems for process execution, and provides means for inter-process communication. Chief among the resources that a process needs during execution are usage of the processors 10, usage of primary storage (main storage 11), access to data stored on secondary storage 12, and other facilities such as printers. The memory management subsystem 38 regulates the use of primary storage for efficient, protected, and convenient access to programs and data, and coordinates with file -6- SUBSTlTUTE SH E management subsystem 32 so that file data is transferred between primary and secondary storage as needed by processes. In most UNIX operating system versions, the memory management subsystem provides the convenient illusion of a linear space in which processes can expect to reference the data or code that they need during execution, although the main storage 11 employed for meeting this need is neither linearly nor continuously present for a specific process. This illusion is supported by managing the main storage in small units of allocation, called pages, and by dynamically adjusting the mapping between process generated references (also called addresses) and the pages into which the data accessed by these references reside. The pool of pages that are so used, as the variably allocatable storage resource, is termed a page cache that appears in FIG. 2 as page cache 41. Over the duration that the operating system executes a specific process on a processor, the processor is said to be functioning in the context of the process. The context of a process refers to the overall hardware and software state of a processor that makes it possible for the memory references generated during the process execution to map correctly to the physical addresses that contain the instructions or data needed for computation. Accordingly, the context of a process is defined by all the machine register contents that need to be saved at the time that the process control subsystem 35 disembarks the process from execution on a processor. This "saved context" information must be subsequently restored on a processor, in order to continue the execution of that process on the processor. The operation of a processor of stopping the execution of one process, saving its context, and restoring the context of a second process, so that the second process uses the processor instead of the first process, is called a context-switch. The file management subsystem 32 commonly comprises one or more file systems, each of which spans a single logical partition or subdivision of a secondary storage medium such as a disk, and which organize the data within that partition. Generally, multiple implementations of file systems are available, each providing a common set of services to the remainder of the operating system and differentiated from other implementations by virtue of specialized functions and structure that are appropriate for the specific uses intended by the implementation. The common set of services offered by various file system implementations to the other kernel subsystems is generally called the Virtual File System interface. A file system implementation is also commonly referred to as a file system type. Some of the commercial file system types that are in wide use are the UFS, S5FS, and VxFS file system implementations. These names are acronyms for (1) the [Berkeley] Unix File System, see M. McKusick et. al., "A Fast File System for UNIX," ACM Transactions on Computer Systems pp. 181-197, 1984, (2) the (AT&T) System V File System, see Maurice J. Bach, 'The Design of the UN X Operating System ", Prentice-Hall, Englewood Cliffs, 1986, and (3) the Veritas extent File System, (see the VeritasfTM) File System Administrator's Guide, VERITAS Software Corporation, 4800 Great America Parkway, Suite 420, Santa Clara, CA 95054). Also, a file system type that is used commonly for providing file system services between machines connected by a network is the NFS, or the Network File System, see R. Sandberg, et. al., "Design and Implementation of the Sun Network File System," Proceedings of the USENDC 1985 Summer Conference, pp. 119-130, June 1985. Since file system types can be different, the specific file system type to which any particular discussion in this specification applies will be identified where such identification is important. The transfer of data between primary storage and peripheral (I/O) devices such as disks, terminals, or printers, and the control of such devices, is accomplished by the services of kernel modules called Device Drivers 34. The device drivers support two models of access to the peripheral devices. One of the two models is the block device model 34-1, and is used for devices that can be addressed as sequences of blocks, in which the length of a block is typically 512 bytes. The other is called the character device model 34-2 and it is used for devices for which the block device model does not apply. The block device model is usually applied to disks and tapes. The purpose of the block model is to allow the use of buffering in order to reduce I/O traffic. The sizes of buffers used in performing transfers from or to block devices are some convenient multiples of 512, which is the size of a typical disk block. The buffering for block I/O data transfers is performed either by using some or all pages from the page cache 41, or by a dedicated pool of memory called buffer cache 40, and frequently by employing both the page cache and a buffer cache. In cases where both caches are used, pages that contain file data are used directly as the I/O buffers, while file system structural data (to be described) are held in the buffer cache. Both the file management subsystem 32 and the memory management subsystem 38 cooperatively manage the page cache 41, while only the file management subsystem manages the use of buffers from the buffer cache 40. Collectively, the buffer cache 40 and the page cache 41 are the cache 33. The functions implemented by block or character device drivers that kernel subsystems can call in order to perform data transfer or control operations are called device driver strategy routines. Of these, the functions called in order to write data from primary storage to secondary storage are called write strategy routines, while those that are called in order to read data from secondary storage into primary storage are called read strategy routines. Hardware control 39 is responsible for handling interrupts and for communicating with the machine hardware 5. I/O devices 12 and 13, such as disks or terminals, may interrupt the processors (CPU) 10 while a process in executing. If interrupted, the kernel 20 may resume execution of the interrupted process after servicing the interrupt. Interrupts are generally serviced by special functions in the kernel that are called in the context of a currently running process. While many of the processes that run under the control of the operating system kernel arise from computational work generated by users, some special processes are created and run on behalf of the operating system itself. These special processes are called daemons. Daemons perform many general system-wide services, such as administration and control of networks, line printer spooling, handling of many exceptional situations, and so on. UNIX File System Data Structures and Organization A File System is a span or subdivision of a secondary storage medium that is managed by a file system implementation. There exist multiple possible file system types or implementations that manage file systems. Within a file system are files, most of which contain ordinary data. Diskless work-stations are also used, frequently, where files are located on a remote system and are accessed via a network. For simplicity, all devices can be considered as "disks", since the principles apply to any storage device. The files are identified by names, each name is a string of characters. Certain files are distinguished as directories, and they contain names of other files along with pointers to their location in the file system. These names are called directory entries, and may refer either to plain files or to directories. Each file name is also called a "link". The system permits a single physical file within a file system to have more than one name or link. While conceptually a directory may be considered as containing the files for the file names the directory contains, the files named by a directory actually exist separately and are only referenced by the directory. By allowing directories to contain entries to other directories as well as plain files, the UNIX operating system provides to its users a perspective in which an entire file system is a tree structured hierarchical organization with a single starting directory called the root directory of the file system. The root directory refers to a number of files and directories; the directories in the root directory themselves refer to additional files and directories, and so on, thus covering all available files and directories in the file system. UNIX file system implementations do not impose any structural requirements on contents of plain files; these files are treated by the file system implementations as streams of bytes, to be arbitrarily accessed by application programs. Application programs may impose specific semantics on file contents in accordance with application needs. For example, some applications may interpret line feed or tab characters as distinguishing ends of data fields within a file; however, this information is of no significance to the file system implementations. The content of directories is however a different matter. Directories contain information about file system organization; so they have a specific structure that is defined by and meaningful to the file system implementation. In addition to directories, a file system implementation reads other structural data from secondary storage, manipulates and writes the structural data back to secondary storage as necessary in order to manage the physical layouts of files and directories and to reflect changes in characteristics of files and directories. Examples of structural data include owners, sizes, and access times for files and directories. The management of structural data occurs without the explicit knowledge or request of application programs and the rules for such management vary from one file system implementation to another. The kernel deals on a logical level with file systems, viewing them as sequences of logical blocks instead of viewing them as disks or other storage units. In this perspective, each disk or other storage device is viewed as one or more logical devices, identifiable by one or more logical device numbers. A logical device is equivalently a disk partition or a subdivision in which a file system resides. A file system is viewed by the file system implementation as a sequence of logical blocks of storage. The conversion between a logical device address (that is, a file system address) and a physical device address (e.g., a disk block address) is done by one of the block device drivers. Data Structures and Policies Of File System Implementations It is not generally possible to describe file system data structures and organization commonly across all file system implementations. The general requirements of all file system implementations are common, however; and these are that it should be possible to allocate and free space for file data and to allocate and free space for any auxiliary data describing the layout and characteristics of files and directories in the file system. Therefore, for simplicity, an overview of data structures and file system space management procedures is given here for the UFS file system implementation, but the principles and the invention to be detailed apply equally to UFS and to other file system implementations. However, to prevent ambiguity, the term UFS will be used to qualify the description that applies particularly to the UFS file system implementation. In the UFS file system the internal representation of a file is given by an inode which contains a description of the device layout of the file data and other information such as file owner, access permissions, and access times. Every file (or directory) has one inode, but may have several names (also called links), all of which map into the same inode. When a process creates or opens a file by name, UFS parses each component of the file name, checking that the process has the necessary privileges for searching the intermediate directories and then retrieves the inode for the file. In the case of opening or creating a new file, UFS assigns to the file an unused inode. Inodes are stored in the file system and UFS reads the needed inodes into an inode table that is maintained in primary storage for ease and efficiency of access. A file system in UFS is a sequence of logical blocks. The size of a logical block is a convenient multiple of the smallest size in which data transfer can be performed to secondary storage. Each UFS file system includes a number of special blocks, which contain file system administrative data, and whose contents are manipulated without explicit request from or knowledge of application programs. One of them is a superblock, which describes the state of the file system and information identifying available inodes and free space (unallocated blocks) in the file system. For achieving compact layouts, UFS divides a file system into smaller divisions called cylinder groups, and uses algorithms that promote allocations of inodes and data blocks from the same or neighboring cylinder groups among correlated uses. To protect against catastrophic loss of information, the superblock is replicated among the cylinder groups. Other blocks containing administrative information include blocks that contain bitmaps describing the available blocks within each of the cylinder groups, and blocks from which space can be used for allocating inodes. The blocks that contain file data are reachable from the inode for the file by one of three means. The inode itself contains the logical addresses for several initial data blocks. In addition, the inode contains a few block addresses for "indirect" and "double indirect" blocks for large files. The indirect blocks contain addresses of additional data blocks for a file and -11- SI ST- ' T ! x SH - " ' '•• ' c 26) double indirect blocks contain addresses of additional indirect blocks that could not be accommodated in the inode. The kernel allows processes to store new information in files or to recall previously stored information. When a process is to access data from a file, the data is brought into main storage 11 where the process can examine it, alter it, and request that the data be saved in the file system again. A process may also create new files and directories, remove existing files and directories, or replicate or rename existing files and directories. In all cases, as file sizes and file and directory populations in a file system change, the auxiliary data that describes the file system organization is brought into memory, examined and altered, and written to secondary storage. For example, the superblock of a file system must be examined when there is a need to allocate a new file or inode or to allocate new data blocks, and the superblock must be modified when data blocks or inodes are allocated or freed. Similarly, an inode describes the layout or data block organization within a file; the operating system reads an inode into memory to access its data, and writes the inode back to secondary storage when updating the file layout. The manipulation of this auxiliary data is done without the explicit knowledge or request of a running process. If the kernel were to read and write directly to and from disk for all file system accesses, then system response time and productivity would be poor because of the slow rate of data transfers between disk and memory. The file system implementation therefore attempts to minimize the frequency of disk accesses by keeping file data and file system structural information in the page cache 41 , or the buffer cache 40, or both the caches. Page cache 41 is generally used for keeping data or code that should be directly addressable from a process running in user mode. Buffer cache 40, on the other hand, is a pool of memory that is allocated to and managed by the file subsystem for storing information that is needed by a file system implementation. Commonly, file data are cached in the page cache 41, while structural data such as inodes, superblocks, and indirect blocks are kept in the buffer cache 40; however, a file system implementation may choose to maintain file data in buffer cache, or to maintain structural data in the page cache for reasons of policy or algorithmic convenience. Read/Write Procedures When reading data from disk of secondary storage 12, the kernel first attempts to find the data in buffer/page cache 33 and does not have to read from disk if found in cache 33. If the requested data block is not in the cache 33, then the kernel 20 calls the disk device driver 34 to "schedule" a read request, and suspends the current process ("puts it to sleep") awaiting the completion of the requested I/O. The disk driver notifies the disk controller hardware to read the data, which the disk controller later transfers to the indicated location in the buffer/page cache 33. Finally, the disk controller interrupts the processor when the I/O is complete, and the disk interrupt handler awakens the suspended process; the requested data is then in the cache 33. Similarly, data being written to disk is cached in cache 33 in case there is a subsequent read attempt for the data. When writing, the kernel also attempts to reduce frequency of disk writes by determining whether the data being written needs to be immediately sent to disk or whether it is transient data that will soon be overwritten and therefore is retained only in cache 33. The three styles of disk write operations described earlier: synchronous, asynchronous, and delayed writes have differing performance consequences. If the write is synchronous, the kernel informs the disk device driver 34, which schedules a write I/O. The calling process is suspended until the write is done, as in the case of a read request. If the write is asynchronous, a write I/O is scheduled, but the process is allowed to continue without waiting for the write to be done. If the write is delayed, then the page or the buffer of cache 33 to be written is merely marked as needing to be written at a later time and no attempt is made to schedule a write I/O operation. Some time later, the kernel writes the delayed write pages or buffers in cache 33 asynchronously to disk (secondary storage 12). In the interim, if the same buffer or page receives more delayed writes, then all of these writes are accumulated and result in only one physical disk write. Ordering for Structural Modifications Many file system implementations need to control the order in which modifications that are made to structural data are recorded to disk. This control is to allow file system repair by programs such as fsck following a system crash. The specific requirements for ordering vary accordingly from one file system implementation to another, but the following example for the UFS file system shows why ordering of modifications is necessary. Consider what happens when a file name is removed from a directory, and the name being removed is the last remaining link to the file. The operation of name removal in this case will also remove the file itself, and free up the storage associated with the file. This operation updates three kinds of structural information: (1) the directory entry, which is space in the directory data block, in which the file name and the file inode are identified, (2) the file inode, which is the structure describing the file layout and file properties such as owner and protections, and (3) the free block list for the file system, to which the file data blocks need to be returned upon the removal of the file. Copies of these structural data are updated in memory: the directory entry is maintained in the page cache while the file inode and the file system superblock which contains the free block list are maintained in the buffer cache. As a simplification, the term "buffer" will be used to refer to any in-memory copy of data, whether that copy is stored in the buffer cache 40 or the page cache 41. To remove a file, the UFS file system performs the steps in the following TABLE 1 : TABLE 1 1. Clear the directory entry referencing the file name. 2. Write the buffer containing the directory entry to disk. 3. Decrement the link count for the file inode. Since the link count reduces to 0, the file will need to be removed. Zero out all the data block pointers that are described by the file inode, in effect breaking the connection between the file inode and the file data blocks. 4. Write the buffer that contains the file inode, to disk. 5. Return the data blocks that belonged to the file, to the free block list. 6. Mark the inode as "free". 7. Since the file inode was changed again in step (6), mark the buffer that contains it as modified (to be written to disk at a later time). 8. Return the file inode itself to a list of free inodes in the file system. In the sequence of steps listed in TABLE 1 , the cleared directory entry must be written (step 2) to disk, before the freed inode (steps 6, 7) can be written to disk or reassigned to other use. Otherwise, if the system crashes before the modified directory entry is recorded on disk but after the inode has been reassigned to other use (for example, after step 7), then when the system is rebooted, the directory entry would still exist and identify the old file as valid, although the inode is reassigned. To the user, it would appear that the old file's name now refers to a different, newly created file. • -14- SiJ STITiJTE SHEET .RULE 26) Similarly, the inode, with its data block pointers zeroed out (step 4) must be written to disk before the freed data blocks can be allowed to appear on the free list (step 5). Once a data block is returned to the free list, it can get reassigned to another use, and if the ordering between step 4 and step 5 is not enforced and a system crash happens before the inode is written, a single data block can become part of more than one file. File system modules which require ordered disk writes for file system repairability have implemented this ordering using synchronous writes. In the example of TABLE 1, the writes at steps 2 and 4 are done synchronously; thus ensuring that step 4 has completed before step 5, and step 2 has completed before steps 6 or 7. In a synchronous write, the process issuing a disk write waits for the write to complete before continuing execution. Because typical delays in writing to disks are of a magnitude comparable to the time it would take for the processor to execute thousands of instructions, when a process needs to wait for a disk write to complete, the process control subsystem reassigns the processor to some other process that is ready to continue. Thus, synchronous disk writes give rise to context switches. Some consequences of using synchronous writes are described in connection with an example which consists of the execution of the UNIX system command: rm filel file2 file3 where the command (rm) removes three files (filel, file2, file3) in a single directory. For purposes of this example, the directory entries for all three files are in the same buffer of the directory, as would be typical for moderate sized directories. Also, in the example, the inode data for file2 and file3 are stored in the same buffer while the inode data for filel is in a separate buffer. Operation Of r Command - FIG. 3 FIG. 3 illustrates the operation of the above rm command in a UFS file system implementing ordering by using synchronous writes. It shows the ordering requirements for each file, based on the implementation of file removal procedure described in TABLE 1. FIG. 3 corresponds to a sequence of requests Rl, R2, ..., R9. Note that for each file, the order dependencies are that the buffer containing the directory entry must be written before the buffer containing the inode and the buffer containing the inode must be written before the data blocks are returned to the free list. In addition, FIG. 3 shows the additional order dependencies that each file is handled in sequence; all the actions for one file are performed before the actions for the next file and so on. In general, the order dependencies Dl, D2, ..., D8 for requests Rl , R2, ..., R9 of FIG. 3 are as follows: Dl: R1 - R2 D2: R2 → R3 D3: R3 → R4 D4: R4 - R5 D5: R5 - R6 D6: R6 → R7 D7: R7 → R8 D8: R8 → R9 The order dependency Dl, for example, means in the expression Rl → R2 that Rl is to be performed before R2. The eight order dependencies Dl, D2, ... , D8 result from a simple time-order presentation of the requests Rl, R2, ..., R9 so that a single time-order subset of order dependencies is formed D1→D2→D3→D4→D5-*D6→D7→D8 meaning that the requests are specifically ordered as R1→R2→R3→R4-*R5-*R6→R7→R8→R9. As shown in FIG. 3, there are two synchronous writes per file (requests Rl, R2; R4, R5; R7, R8), resulting in a total of six writes to disk and six context switches. Note that one buffer contains all three directory entries (requests Rl, R4, R7), and is thus written to disk three times, and, similarly, another buffer contains the inodes (requests R5, R8) for both file2 and file3 and is written to disk twice. Comparison of Synchronous. Asynchronous, and Delayed Disk Writes Asynchronous writes, and Delayed writes are two alternatives to Synchronous writes, and they are used commonly by various file system implementations for writes to disk because of their less adverse impact upon performance. TABLE 2 provides a comparison of the three write operations used in the kernel. IΔBLE.2 Synchronous Asynchronous Delayed 1. Writes to Disk When? Immediately Immediately Later 2. Data Integrity High High Medium 3. Ratio to Actual Disk Writes 1:1 Marginally > 1: 1 Many: 1 4. Waits for Disk Write to Complete? Yes No No 5. Can be used for Ordering? Yes No No 6. Causes Context Switches? Yes No No 7. Disk Throughput Limits Program? Yes Somewhat Minimal As shown in TABLE 2, each write operation provides a different tradeoff among various characteristics. Synchronous and asynchronous writes provide greater integrity on secondary storage in the event of machine failure (see line 2 of TABLE 2), while the use of delayed writes gains the benefit of improved performance but is more vulnerable to a system crash. Since delayed writes minimize the coupling between disk subsystem and the CPU (line 7), as well as reduce the actual number of disk writing by promoting write caching (line 3), they tend to be best suited for achieving high system throughput; and since they do not cause extra context switches (line 6), they improve individual response times as well. Delayed Ordered Writes ωOW The Delayed Ordered Write (DOW) subsystem 30 of FIG. 2 of the present invention provides a more efficient solution to the disk write ordering problem. DOW, implemented in one embodiment in a UNIX Operating System, doubles system performance by reducing the amount of disk traffic as well as the number of context switches generated by synchronous writes. DOW provides a mechanism for controlling the order in which modifications of file system structural data are recorded on disk, without using the one- disk-write-at-a-time style of synchronous disk writing. Large gains in system performance have resulted from using DOW in place of synchronous writes within the UFS file system implementation. These advantages are obtained without requiring a structural redesign or a change in the media format for UFS. DOW includes two parts. The first part is an interface by which file system implementations, or any kernel subsystem, specify the sequences in which modifications of file system data blocks can be recorded on disks. These sequences translate into ordering dependencies among disk blocks themselves, which are collectively represented by an ordering graph (entries in an ordering store), prepared by DOW in response to the specification. The second part of DOW consists of mechanisms responsible for ensuring that the operations of the ordering graph (indicated by the entries in the ordering store) are performed in the order specified. DOW is a modular service, loosely coupled with other kernel subsystems, including the file system implementations which use it. In the preferred embodiment, no modifications are made to other kernel subsystems (including device drivers) or to the -18- SU3STITUTE SHEET (RULE 26) standard file system interfaces. The changes to the file system implementations that choose to employ the DOW mechanism are simple in place code substitutions in which synchronous writing is replaced by calls into the DOW subsystem for recording the needed ordering entries. Any file system implementation in the operating system can therefore use DOW easily, without structural redesign and the loss of media compatibility that might otherwise result. Furthermore, while DOW provides the mechanism for ordering disk write operations, the file system retains control of the policy for ordering, that is, which disk write operations should be ordered and how. Terminology and Conventions For an exposition of how the DOW subsystem 30 works, it is useful to represent the actions that need to be performed in a time order as nodes (operation entries) of a graph and to represent the time ordering constraints as directed links (order entries) between the nodes. The nodes and links in the graph are stored as entries located in an ordering store for example in system memory such as main store 11 of FIG. 1. The graph in the ordering store is called a DOW ordering graph or simply an ordering graph. The actions that are represented by the nodes of the ordering graph for write operations are of two types: (1) writing of data to disk, and (2) execution of some function that needs to be time ordered relative to writing of some data to disk. For example, in FIG. 3, the functions which return the disk blocks of the removed files to the file system free list (requests R3, R6, R9), are represented in a DOW ordering store by nodes of the second type. A node of type (2) is called a function node, and the ordered function call that is represented by a function node is called a deferred procedure call. -19- SU3STITUTE SHEET (RULE 26) For convenience of description, the nodes in an ordering graph are identified symbolically as NI, N2, ..., Nn. An ordering constraint between two nodes NI and N2 of the ordering graph, such that the action corresponding to NI must happen before the action corresponding to N2 can happen, is represented by a link directed from NI to N2 — or, in text as N1→N2. The execution of a node in the ordering graph refers to the action of performing the task that is represented by that node. Thus, executions of DOW graph nodes result either in the writing of a particular data item to secondary storage, or, in the case of function nodes, the execution of the procedure call that the function node represents. For two nodes NI and N2 in the ordering graph, if a link N1-*N2 exists, then NI is called a predecessor of N2 since NI must be executed before N2 can be executed. Alternatively, since the execution of N2 depends upon the execution of NI, N2 is called a dependent of NI. As defined above, the ordering graph is directed, that is, any link between two nodes in the ordering graph is directed from one node to the other, to represent the ordering requirement between the actions that correspond to the two nodes. In addition, an important characteristic of the ordering graph is that at all times, it is free of cycles. If a cycle existed, for example, among 3 nodes NI, N2, and N3 of the ordering graph due to links N1→N2, N2→N3, and N3→N1, then the ordering constraints suggested by the three links would be self-contradictory, since at least one of the three constraints that the links represent would be violated in any order in which NI, N2, and N3 are executed. Therefore the ordering graph does not contain cycles, and is said to be a directed acyclic graph. Reducing Disk Writes with Delayed Ordered Writes Delayed Ordered Writes (DOW) combines delayed writes with an ordering store mechanism for controlling the order in which data is written to disk. Thus, the use of DOW allows the system to obtain the performance improvement associated with delayed writes while retaining the file system recovery capability that is provided by synchronous writes. FIG. 3 is analyzed to understand the transformation from synchronous writes to delayed ordered writes. Boxes A and C in FIG. 3 represent disk blocks having contents updated in more than one sequence of ordered modifications. The one-at-a-time handling of file removals which occurs as a result of synchronous writes, as described above in connection with FIG. 3 and TABLE 1 is not necessary for repairability, so the sequencing shown in FIG. 3 between boxes R3 and A(R4), and between boxes R6 and A(R7) can be removed. With these changes, the control flow of FIG. 3 is transformed into a directed acyclic graph. Directed Acyclic Graph - FIG. 4 The directed acyclic graph of FIG. 4 includes the nodes A, B, ..., F by merging disk write requests (Rl, R4, R7 and R5, R8 of FIG. 3) of the same buffer that are common to multiple sequences into a single disk write of the buffer. Merging common data into a single write in this example reduces the total number of disk writes from six (Rl, R2, R4, R5, R7, R8) to three (A, B, and C), while continuing the proper ordering among the disk writes. FIG. 4 also illustrates the use of deferred procedure calls (nodes D, E, and F), which represent other actions to be completed in the prescribed order relative to the delayed, ordered disk write operations. The nodes D, E, and F in FIG. 4 each represent a procedure to be executed for returning the data blocks of a removed file to the free list, but the procedure can be permitted to execute only after the inode for the removed file is written to disk with its data block pointers zeroed. This ordering is specified by creating a graph node which corresponds to the inode buffer, creating another graph node corresponding to a procedure that would free the data blocks for the inode, and then specifying that the procedure can be invoked only after the inode buffer is written to disk. Finally, note that unlike the synchronous write operations of FIG. 3, the ordering graph of FIG. 4 is only partially sequential and represents a partial ordering among multiple subsets of file system data structure modifications — some of which may, therefore, execute concurrently. Specifically, in FIG. 4, the common order dependencies CD1 and CD2 for a first subset are: CD1: A → B CD2: B → D The common order dependencies CD3, CD4, and CD5 for a second subset are as follows: CD3: A → C CD4: C → E CD5: C → F Note that the first and second subsets of common order dependencies for FIG. 4 are independent of each other. Four Process Example - FIG. 5 The operation of delayed ordered writes is further illustrated by a second example in FIG. 5. In this example, it is assumed that four processes operate separately on files in a directory. Two of the processes each create a file by using the unix touch command: touch filename which creates a zero-length file called filename if it does not already exist in a directory. The other two processes each remove a file from the directory using the unix rm command. The four processes execute these commands, in the same directory: Process 1 Process 2 Process 3 Process 4 touch filel touch file2 rm file3 rm file When creating a file name in a directory, a process increments the link count in the inode for the file and adds the file name to the directory. It is only after the increased link count is safely written to disk that the file name itself can be added to the directory buffer. Otherwise, an intervening system crash would cause the file inode to have a smaller link count than the number of actual directory entries referencing the file so that a file system repair utility could not correctly determine a proper recovery action, and so would be forced to leave the file in the directory from which it was being unlinked prior to the system crash. FIG. 5 illustrates the steps followed by each of the processes in accordance with the ordering dependencies that apply to creating and removing files. For purposes of this example, assume that the inodes for filel and Ωle2 are in one buffer and that the inodes for Ωle3 and Ωle4 are in another buffer. Also, assume that the directory entries for filel, file2, and file3 are in the same page buffer; and the directory entry for file4 is in another buffer. The four processes run independently. The time order of each update request per process is important and the overall time order of all the requests will be some interleaving of all the per-process requests. The overall time order is unimportant, so long as the order dependencies of update requests within each process are preserved. The order dependencies of FIG. 5 are as follows: Dl: Rl - R2 D2: R3 → R4 D3: R5 → R6 -23- SUBSTITUTE SHEET (RULE 261 D4: R6 → R7 D5: R8 → R9 D6: R9 → RIO Directed Acyclic Graph - FIG. 6 FIG. 6 shows how the ordering requirements of FIG. 5 can be met by using DOW so that it is possible to combine the common elements among the steps taken by the four processes. While the resulting overall order among all the steps is different, the sequencing of steps within each process is preserved. Specifically, the common order dependencies of FIG. 6 preserve the order dependencies of FIG. 5 while reducing the number of separate operations required. Specifically, in FIG. 6, the common order dependencies are: CD1: G → H CD2: H → J CD3: I → J CD4: J - K CD5: J → L The common order dependencies CD1 , CD2, ... , CDS OF FIG. 6 preserve the order dependencies Dl, D2, ..., D6 of FIG. 5. Constructing An Acyclic Ordering Graph The potential I/O reduction from delayed ordered writes relies on combining delayed writes with a control mechanism based on an order store storing entries, which constitute a directed acyclic graph, in which the graph represents ordering dependencies among data modifications. TABLE 3 presents a summary of the DOW procedures that are available to file system implementations for use in constructing the ordering graph in the ordering store. TABLE 3: Routines for Constructing an Ordering Graph dow create Create, if it does not exist, a node in the ordering graph which corresponds to either a delayed write buffer or a deferred function execution, and return an integer identifier which may be used to reference that node. dow_order Specify an ordering between two nodes in the ordering graph. dow_startmod Indicate that data in a buffer is about to be modified. dow_setmod Indicate either that modification of data in a buffer, or the setup for a deferred function execution, has completed. dow_rele Release a hold on a node identifier. dow_abort_range Destroy all nodes in the graph corresponding to a range of buffers in a particular file. In TABLE 4 below, a code sketch in C language illustrates the transformation from the example of FIG. 3 to the ordering graph of FIG. 4 using the routines of TABLE 3. TABLE 4: File Removal using Delayed Ordered Writes Iteration 1. 2. 3 Operation 1 dowid t pgdow, ibdow, fdow; 2 1* 3 * make a node in the ordering graph corresponding 4 * to directory buffer which contains the directory 5 * entry of the file being removed, and then clear 6 * the file's directory entry. 1 *1 A, (A), (A) 8 pgdow = dow_create(directory buffer containing entry); 9 dow_startmod(pgdow); 10 11 . clear the portion of the directory buffer containing 12 . the directory entry of the file being removed. 13 . 14 dow set od (pgdow); 15 16 /* 17 * make a graph node corresponding to the 18 * inode buffer, and set up ordering to write 19 * the inode buffer to disk after the directory 20 * buffer is written to disk. -25- SU3ST1TUTE SHEET (RULE 26) 21 */ B, C, (C) 22 ibdow = dow_create(inode buffer); A→B, A→C, (A→C) 23 dow_order (ibdow, pgdow, 0); 24 dow_startmod(ibdow); 25 . 26 . Decrement the inode link count and zero out 27 . the inode data block pointers 28 . 29 dow_setmod(ibdow); 30 /* 31 * set up ordering: call function to free 32 * the blocks after writing the inode. 33 */ D, E, F 34 fdow = dow_create(function to free data blocks, 35 block list specification); B→D, C→E, C-»F, 36 dow_order(fdow, ibdow, 0); 37 dow_setmod(fdow); 38 . 39 . mark the inode as free and return the inode 40 . to the free inode list 41 42/* 43 * release the node identifiers 44 */ 45 dow_rele(pgdow); 46 dow_rele(ibdow); 47 dow_rele(fdow); For the example of FIG. 3, the code in TABLE 4 is executed three times, once for each file that is removed, by the file system implementation that is a client of the DOW facility. The code segment appears in the right column, marked "Operation". The left column describes how, during each of the three iterations, the execution of the code in the right column results in the construction of the ordering graph of FIG. 4. In the left column, at lines 8, 22, 23, 34, and 36, are three comma separated entries; these entries identify the nodes or links in the ordering graph that result from the execution of the corresponding lines of code in the right column during the respective iterations. In the code sketch, line 1 is a declaration of three DOW identifiers, called pgdow, ibdow, and fdow; respectively, these variables are used to store identities of graph nodes -26- SUBSTiTUTE SHEET (RULE 261 corresponding to disk write of a page, disk write of a buffer, and a deferred procedure call. Lines 2-7, 16-21, 30-33, and 42-44 are comments. During the first iteration: At line 8, the file system implementation requests the DOW subsystem via dow create to map a directory page in which the entry for filel exists, to a DOW node. The result of this mapping, is to have in the variable pgdow, the value of the DOW node identifier for the directory page which will need to be modified in order to remove the files name entry. This is shown in the left hand column as the creation of node A of FIG. 4. Before proceeding to modify the directory page, the file system implementation signals its intent to the DOW subsystem by issuing the dow startmod. call (line 9) for pgdow. After that, in lines 10-13, the actual modification occurs, the code for which is not different in absence of DOW, and is not shown for brevity. Then at line 14, the file system implementation calls dow setmod for pgdow, to signal to the DOW subsystem that the modification is complete. At line 22, dow_create is called again for creating a second DOW node, corresponding to the buffer in which the inode for filel resides. The result is to have the variable ibdow contain the DOW node identifier for the buffer which contains the inode, and which will need to be modified and written to disk. This is shown in the left hand column as the creation of node B of FIG. 4. At line 23, the ordering constraint between pgdow and ibdow is specified via dow order. The effect of this is to insert a link directed from pgdow to ibdow, that is, from A to B in terms of FIG. 4. As in the case of pgdow, the intent to modify the inode (and hence the buffer which contains the inode) is signaled at line 24 by the call to dow_startmod for ibdow. Again, the actual modification is not shown for brevity because it is independent of DOW usage, and -27- SUSST1TUTE SHEET (RULE 26) happens in lines 25-28. Then, at line 29, the indication that the buffer is modified as desired, is given to the DOW subsystem via the call to do setmod. At line 34, the file system implementation calls dow create to request the creation of a function node. The deferred procedure call to which the function node is mapped, is one that would need to be executed in order to return the freed data blocks from filel to the disk block free list in the file system. This creates node D for the ordering graph shown in FIG. 4; the identifier for the node is kept in the variable fdow. At line 36, the ordering constraint between ibdow and fdow is specified via dow_order. The effect is to insert a link directed from ibdow to fdow, that is, from B to D in terms of FIG. 4. Enlisting the ordering constraint at line 36 effectively completes the setup of the function node; hence the dow setmod call is used at line 37 to signal the readiness of the function node for execution at any following time. All necessary ordering actions have been represented at this point, so the three DOW nodes can be released at any time. Actually, the node pgdow could be released at any time after line 24. The DOW nodes, pgdow, ibdow, and fdow, are released in lines 45-47. During the second iteration: As in the case of the first iteration, at line 8, the file system implementation requests the DOW subsystem (via dow_create) to map a directory page in which the entry for file2 exists, to a DOW node. Since the entry for file2 is in the same directory page as for filel the result of this mapping is to have in the variable pgdow, the same DOW identifier as in the first iteration; that is, the node A in FIG. 4. At line 22, when a DOW node for mapping the buffer containing the inode for file2 is requested, the result is that a new identifier is created and written into the variable ibdow. This new node is shown as the node C in FIG. 4, and in the left hand column in TABLE 4. -28- SUBSϊiTUTE SHEET (RULE 26) At line 23, the ordering constraint specified between pgdow and ibdow via dow order results in the directed link from A to C in terms of FIG. 4. At line 34, a new function node is requested for mapping to the deferred procedure call that would release the disk blocks from file2 to the file system free list. This creates the node E for the ordering graph shown in FIG. 4; the identifier for the node is kept in the variable fdow. At line 36, the ordering constraint between ibdow and fdow is specified. The effect is to insert a link directed from ibdow to fdow, that is, from C to E in terms of FIG. 4. During the third iteration: The third iteration, for the removal of file3, proceeds analogously to the first two iterations. In this iteration, the directory entries for file3 and file2 share the same page and the inodes for the two files reside in the same disk block. Hence, at lines 8 and 22, the same DOW identifiers are returned for the two iterations. At line 23, the ordering constraint that is specified between pgdow and ibdow, results in no new work since the ordering link from A to C was already created in iteration 2. At line 34, a new function node is requested for mapping to the deferred procedure call that would release the disk blocks from file3 to the file system free list. This creates the node F for the ordering graph shown in FIG. 4; the identifier for the node is kept in the variable fdow. At line 36, the ordering constraint between ibdow and fdow is specified, whose effect is to insert a link directed from ibdow to fdow, that is, from C to F in terms of FIG. 4. Thus when all three iterations are completed, the DOW subsystem has the necessary ordering requirements between the various disk writes and the deferred procedure calls in place, to resemble the ordering relationships of FIG. 4. File system implementations typically use these DOW functions in conjunction with modifying structural data. For the example in TABLE 4, the modifications of structural data occur in lines 10-13, 25-28, and 38-41, identically with the usual synchronous write based implementation. With the synchronous write based ordering, the modifications are followed by disk writes; with DOW, the modifications are followed by the primitives that construct the ordering graph. The general outline followed by a DOW client when modifying a datum which must be written to disk in an ordered fashion is described in TABLE 5 as follows: TABLE 5 1. Create a graph node corresponding to the datum and acquire a node identifier referencing the node by calling dow_create. 2. If there is a datum which must be written prior to this datum, use dow_order to specify an ordering between the two nodes representing these two data items. 3. Call dow startmod to indicate that this datum is about to be modified. 4. Modify the datum. 5. Signal that the modification is complete, by using dow_setmod to mark the graph node as "modified". 6. Finally, at any point after the last dow_order or dow_setmod call involving this graph node, release the graph node through a call to dow_rele. The functions dow startmod and dow setmod provide coordination points between a client of DOW and the DOW subsystem. They are used to notify the DOW subsystem that the client is modifying a page or a buffer that corresponds to a node in the ordering graph. One key aspect is the rule: When establishing an ordering between first and second operations (between first and second common writes or a first common write and a function), dow order is called only after dow_setmod for the first common operation has completed, but before dow startmod for the second common operation is called. -30- SUBST1TUTE SHEET (RULE 26) The reason for the rule can be understood as follows: 1. After dow order is called, the associated writes of data can occur at any time. If the call to dow_order takes place before modifying the first data, then the first data may be written to disk before its modification is effective. The ordering requirement is violated if the second data is then written to disk. 2. Until dow_order is called, the writes of each data are unordered relative to each other. If the second data is modified before the call to dow_order, the second modification can become effective on disk before the modification of the first data has propagated to disk. DOW Subsystem Data Structures The data structures used for representing the DOW nodes (operation entries) and their ordering linkage (order entries) exist in an ordering store. The DOW ordering store is constructed from two types of data structures, dow-nodes (identifying operations) and dow- link-elements (identifying ordering among operations). Dow-nodes represent operation entries in the ordering graph and dow-link-elements represent linkages (ordering) between graph nodes. Fields For Operation Entries Of Ordering Store (DOW-Node - FIG. 7 Each DOW-node contains information identifying the operation specified by a graph node as well as other information about the dow-node itself. Storage for dow-nodes is obtained from a statically configured array 97, as shown in FIG. 7. Each node is identified by its dow-id, which is its index in this array. For convenience and memory economy, linked lists of dow-nodes are constructed using dow-ids rather than memory addresses. In FIG. 7, the fields of dow-node ordering store entries for node NI and N2 from an array NI, N2, ..., Nn of nodes are shown. Each node includes the following fields: Free list linkage. Linkage for a doubly linked list of unused dow-nodes. Hash list linkage. Linkage for a doubly linked list of in-use dow-nodes, hashed by identity. Used to speed searches for a dow-node for a particular operation. Flush chain linkage. The Flush Chain Linkage (FCL) is a linkage for the doubly linked list of dow-nodes whose operations are to be executed. Predecessor count. The number of predecessor nodes. Dependent count. The number of dependent nodes. Synch. Variable. A variable for synchronization. DOW State. Tracks state information such as whether the dow-node' s operation is ready to be initiated, whether the operation has been initiated, whether the operation has completed, or whether the nodes' predecessors have been searched. Hold Count. A field used for counting. Type. The type of operation represented by the node, for example a write of a page, a write of a buffer, or a deferred procedure call. Identity. Parameters of the delayed operation that the dow-node represents: -32- SUBST1TUTE SHEET (RULE 26) For a page write, the identify field specifies a inode and offset which identifies the page. For a buffer write, the identity field specifies a device number and block number which identifies the buffer. For a deferred procedure call, the identify field specifies the address of the procedure and an argument to be passed to the procedure. For each dow-node, there are two linked lists of dow-link-elements, termed the predecessor list and the dependent list. The predecessor list for a dow-node is a doubly linked list of dow-link-elements which point from that dow-node to the dow-nodes of its predecessors in the graph. Similarly, the dependent list for a dow-node is a doubly linked list of dow-link-elements which point from that dow-node to the dow-nodes of its dependents in the graph. As with dow-nodes, storage for dow-link-elements is obtained from statically configured arrays; each dow-link-element is identified by its dow-link-id, which is its index in this array; and linked lists of dow-link-elements are constructed using their dow-link-ids rather than their memory addresses. Fields For Order Entries Of Ordering Store (DOW-Link Element! - FIG. 8 In FIG. 8, the fields of DOW-Link-Element (DLE) ordering store entries for node Dl, D2 and D3 from an array 99 containing entries Dl, D2, ..., Dm are shown. Each entry includes the following fields: Linking Element. Linkage field for forward and backward chaining of DLEs for forming lists. -33- SU3STITUTE SHEET (RULE 26) DOWID. The dow-id of the predecessor or dependent dow-node to which the dow-link- element points. For example, consider a link A→B in an ordering graph. The dow-nodes for A and B would each have two lists of DLEs, one for dependents and one for predecessors. One of the DLEs on A's dependent list would contain in its dow-id field the dow-id of B. Similarly, one of the DLEs on B's predecessor list would contain in its dow-id field the dow-id of A. The two DLEs — one on the dependent list for A and the other on the predecessor list for B are called inverse-links of each other. A DLE contains an additional field identifying its inverse-link, but this is omitted in FIG. 8 for simplification. DLE Arrays - FIG. 9 While there are two DLE lists (one for predecessor dow-nodes and the other for dependent dow-nodes) for each dow-node, the lists are not anchored at any field of the dow-node structure. Instead, the anchors for these lists are provided by two special arrays 101, 103 of DLEs. This structure is shown in FIG. 9. The arrays 101, 103 serve as anchors of predecessor and dependent lists for each of the DOW nodes. Placing the storage for the heads of these lists in special DLE arrays as shown in FIG. 9 simplifies the linked list management. Except for this detail, the anchors can be viewed simply as parts of the dow-node structure that are given separate storage. Example Of Dow-Node And DLE Structures - FIG. 10 FIG. 10 contains an example of the organization of the dow-node and DLE structures for representing the ordering graph of FIG. 4. In this example, the anchors for -34- SUBST.TUTE SHEET (RULE 26) the predecessor and the dependent dow-nodes lists are treated as extensions of the dow- node as a simplification for purposes of explanation. Each DOW node 105 includes a DOW linkage with predecessors 107, a DOW linkage with dependents 109, and a node identifier (device, block number, etc.) 111. Each DLE 113 includes a previous link element 115, a next link element 117, and a DOW node identifier 119. Consider dow-node for A. Its predecessor list 107 is empty; its dependent list 109 contains DLEs 1 and 2. The dow-id 119 for DLE 1 is the dow-node 105 for B while the dow-id 119 for DLE 2 is the dow-node 105 for C. In this way, B and C are identified as dependents of A. Next consider the dow-node for B. Its predecessor list consists only of DLE 3. The dow-id field of DLE 3 contains the identifier for A thus recording that A is B's sole predecessor. The dependent list for B also consists of only one element, namely, DLE 4. The dow-id field of DLE 4 identifies D as the sole dependent of B. In a similar manner, the other dow-nodes in the organization of lists in FIG. 10 represent the ordering links of FIG. 4. Executing the Ordering Graph In addition to primitives for constructing the ordering graph, the delayed ordered writes facility implements the mechanisms to carry out the operations represented in the ordering graph in the order specified by the graph. Execution of a node in the ordering graph is defined as the operation of performing the action that is represented by the node; it may be, for example, either the writing of a buffer to secondary storage or the invocation of a deferred procedure call. Execution of the ordering graph consists of the procedures that are followed by the DOW subsystem to ensure that executions of nodes in the ordering graph are performed in the prescribed order. Execution of nodes in the ordering graph generally starts when a kernel subsystem, such as a file system module, requests an operation on a buffer corresponding to a node in the ordering graph. When this happens, the DOW subsystem must mediate and ensure that all operations that must precede the requested operation are performed before the requested operation and in the proper order. In this way, a request from a kernel subsystem for carrying out a specific action, translates for the DOW subsystem into an execution of the node that represents the action in the ordering graph. The execution of that node, in turn, may require executions of other nodes in the ordering graph that are predecessors of the node. In addition to an externally requested operation causing the need for such execution, the DOW subsystem itself needs to undertake node executions in response to a dow order, if, the addition of a specified ordering would cause a cycle in the ordering graph. This happens, for example, in a situation such as the following. Suppose that in the ordering graph, a chain of links, {A→B, B→C, C-D} exists among nodes A, B, C, and D. Next, suppose a client of the DOW facility requests, via dow order, the ordering D→A. Evidently, the desired ordering cannot be added to the graph without first removing one of the links that already exists between these nodes. The policy followed in the DOW subsystem is to issue a node execution either for A or D (the choice between executing A or D is made by the DOW subsystem, and is based on some optimality criteria). When the operation that is represented by a node in the ordering graph is completed, the DOW subsystem removes the links between the node and its dependent nodes, since the completion of that operation removes the ordering constraint that existed between that operation and others needing to follow it. So when node A, in the above example, is executed, the link A→B can be removed; this then permits the link →A to be added without creating a cycle. Thus, the DOW subsystem may initiate the execution of one or more DOW nodes to occur, in order to accommodate a new ordering need specified by a client of the DOW subsystem. The starting node in the ordering graph that is requested to be executed, is called the requested node. The DOW implementation performs node execution by searching the ordering graph (or sub-graph), starting from the requested node and identifying all the nodes that are predecessors of the requested node; it then searches each of these predecessor nodes to find their predecessors, and so on. Each identified node is marked with a special flag, so that it is recorded that the node must be executed as soon as its predecessors are executed. The nodes identified and flagged for execution in this manner are called pruned nodes. Searching upward in this manner, the DOW implementation identifies one or more nodes whose execution must be done first; these are nodes that have no predecessors. After identifying the nodes whose operations must be performed first, the DOW subsystem initiates these operations; they can be performed concurrently if there are multiple such nodes. Then, when these nodes have been executed, the DOW implementation traces back towards the requested node: it follows a method of initiating the operations on each of the pruned nodes whose predecessors have completed, and as outstanding operations complete, finds more pruned nodes that can be executed next-- until the requested node is reached. Thus the DOW implementation meets the requirement that all the operations that need to be performed before the requested operation can be undertaken are indeed performed. In the trivial case, if there are no nodes which must be executed before the requested node, the DOW subsystem can initiate the operation that corresponds to the requested node. The actual implementation of the search for nodes to be pruned, and the carrying out of the actions that the nodes represent, is the result of two independent agents: a dow j strategy function, and a dowjlush daemon, communicating through a shared data structure called the dow lush_chain. The dow_strategy function searches the ordering graph and identifies the nodes that need to be executed, and places these nodes on the dow_flush_chain, which is a queue of nodes. The dowjlush_daemon is a kernel process; it removes nodes from the dow_flush_chain and initiates their associated operations. For the DOW subsystem to be able to mediate in this manner, the file system implementations that use the DOW facility must replace their calls to the device driver write strategy routines, with calls to the dow strategy routine. When dow_strategy receives a disk write request for a buffer, it searches for a graph node corresponding to the buffer. If no such node exists, or if the node exists but has no predecessor nodes, then dow_strategy simply forwards the buffer to the device driver by calling the device driver's write strategy routine. On the other hand, if the node corresponding to the operation has one or more nodes preceding it in the graph, the dow strategy function does not call the device driver directly. Instead, it searches for predecessor nodes and marks them pruned, and then proceeds to do the same with these predecessor nodes. When continuing this way, dow strategy reaches nodes that have no predecessors, it places them on the dow_flush_chain for execution by the dow_flush_daemon. The dow_flush_daemon checks the dow_flush_chain periodically, and for each node on the flush chain, the dow_flush daemon initiates the needed deferred operation. When a deferred operation on a buffer completes, the DOW subsystem receives control via a callback mechanism. Since the deferred operation is now completed, all dependence links between its corresponding node and other nodes in the graph are dismantled. If the node whose execution just completed was the last predecessor of some other graph node, and the latter node had been marked "pruned", then the latter graph node is now considered ready for execution. It is therefore placed on the dow_flush_chain, where it would be picked up by the dow_flush_daemon. Again, when the operations represented by these nodes are completed, their dependence links are dismantled, which may move additional nodes to the dow_flush_chain. The process continues in this way, until the operations for all nodes preceding the originally requested node have been performed. At that point, the requested node is itself moved to the dow_flush_chain for handling by the dow_flush_daemon, which proceeds to call the needed device driver write strategy function. This completes the process of executing the requested node. Execution of nodes in the ordering graph may be initiated for reasons other than a direct call to the dow_strategy function by the file system implementation, or because of the need to keep the ordering graph acyclic. Each deferred write operation is given a delay limit; when me limit is reached, and the operation is still pending, the operation is initiated by the DOW subsystem itself. This in turn may result in a graph search similar to that initiated by the dow_strategy routine. A deferred procedure call is not given a delay limit; it is carried out immediately after its last predecessor is executed. Example FIGs. 11 through 14 illustrate this process using the ordering graph of FIG. 4. Note that the ordering graph of FIG..4 was derived from the example of FIG. 3 (rm filel fϊle2 file3), by the use of DOW ordering graph construction method described in TABLE 5. -39- HEET RULE 26) Daemon Write Request - FIG. 11 In this case, suppose that a system daemon requests a write for one of the buffers; specifically, for the buffer that contains the inodes for files file2 and file3. This write call will be intercepted by the dow_strategy function, which first looks for a node corresponding to the requested operation; in this case, it is node C. This situation is depicted in FIG. 11. Insertion Into Dow Flush Chain - FIG. 12 On finding node C, and seeing that there is at least one node preceding it in the graph, the dow_strategy routine searches upward through the graph and marks C and its predecessor A as "pruned". Since A is at the top of the graph, and has no dependence upon any other graph nodes, it is inserted into the dow flush chain (see FIG. 12), from which it will be selected by the dow flush daemon. Move To Dow Flush Chain - FIG. 13 The dow_flush_daemon executes node A by writing the directory buffer to disk. Upon completion of this write, the link from A to C is dismantled. Since C is marked pruned and has no other predecessors in the graph, it is moved to the dow flush chain (FIG. 13). Move To Dow Flush Chain - FIG. 14 Subsequently, the dow_flush_daemon removes node C from the dow_flush_chain, and executes it by writing the buffer to disk. Upon completion of this write, the links between node C and nodes E and F are removed. Since E and F are function nodes, and all nodes preceding them in the ordering graph have been executed, they are moved to the dow_flush_chain (FIG. 14). Thus, after the buffer containing the inodes for files 1 and 2 is written to disk, the functions that return their disk blocks to the free list can be safely invoked; this is done by the dow_flush_daemon as it visits the dow_flush_chain and processes the nodes E and F. Following this sequence of events, of the original graph nodes, only nodes B and D, remain. At some future time, these nodes will migrate to the dow_flush_chain either because of explicit requests to perform their operations, or perhaps due to expiry of the delay interval permitted on these operations. Additional Design Considerations The additional design issues in creating the DOW mechanism divide into • MODULARITY: Implementing the mechanism as a modular subsystem within the kernel. • ERROR RECOVERY: Allowing a file system implementation to recover from an error during a delayed ordered disk write. • DEADLOCK AVOIDANCE: Preventing deadlocks resulting from the addition of ordering dependencies to existing resource dependencies in the kernel. These design considerations are briefly described in the next three subsections. In these subsections, reference is frequently made to races between agents performing computational operations. This term, "race", is used broadly in the Operating Systems literature to describe the uncontrolled access or modification of an operational variable because of overlapped actions of multiple processes or interrupt handlers, which causes system state to become inconsistent. Modularity The DOW mechanism was created as a modular service within the operating system kernel, separate from the other kernel subsystems with which it must coordinate to ensure deadlock free execution. As a modular service, DOW cannot have access to private data within the memory management subsystem or the disk device drivers; DOW cannot, therefore, reliably infer such data as whether a page has been modified or is instantaneously being written to disk. To circumvent this problem, the DOW subsystem independently tracks information about the status of directory pages. This DOW version of information can become stale in rare circumstances. This poses a problem which is described below, along with a solution that has been implemented. A requirement on the dow_flush_daemon is that it must issue all of its own write requests to the file system implementation, as asynchronous writes. This requirement arises from the consideration that if the dow_flush_daemon were to wait for a write to complete, and the node corresponding to the write operation has predecessors that need to be handled by the dow flush_daemon during the graph execution procedure described previously, then an impasse develops. The impasse can be removed by directing all page writes to a separate daemon that can write pages synchronously, but at the cost of some loss of performance. With this as the background, staleness of page- modification information tracked independently by the DOW subsystem creates the following problem. There are two conditions in which a call for asynchronous writing of a page can return without causing a disk operation to occur. These are, (1) the page is already being written to disk by a disk driver (since the asynchronous write cannot wait), or, (2) the file system implementation finds that. the page has not been modified since the last time it was written to disk (usually this happens when there is a race with some other instance of write of the same page). From DOW's standpoint, there is uncertainty, in case (1), about whether the disk write that is in progress (or has just completed) recorded a specific modification, or whether the modification raced with the disk write, and in case (2), about whether the modification state in the DOW data structure is clear at the same time that the modification state in the page is clear. These uncertainties would not arise at all, if DOW subsystem could access the page structures (used by the memory management subsystem) under the cover of the appropriate memory subsystem locks; but such access would compromise the modularity of the DOW and the memory subsystems. However, the likelihood of races leading to either of the above uncertainties is low. The DOW subsystem takes advantage of the low likelihood of the races, by using this fail- safe algorithm. The dow_flush_daemon attaches a tag to the DOW node identifying itself as the owner of the corresponding page write, and if the write reaches dow_strategy function, then dow strategy changes the tag so that dow_flush_daemon can discover later that this has happened. In the infrequent cases when the dow_flush_daemon discovers that an attempt to write a page asynchronously failed, it hands the page over to another daemon that is specially created for writing pages synchronously. Error Recovery For file system implementations which use delayed ordered writes, many of the write operations are handled asynchronously by the dow_flush_daemon. However, in the event of an I/O error, the file system implementation may wish to regain control of the operation, in order to take some recovery action for the error. DOW makes provision for this, by allowing a file system implementation to register routines to be called in the event of an error. If an error occurs, the DOW subsystem can call the registered routine, passing it information regarding what operation failed and why. -43- SU3STITUTE SHEET (RULE 26) Deadlock Avoidance One of the effects of deferred execution of disk writes is that new possibilities for process and system deadlocks arise. Listed below are three broad deadlock situations that can arise with the DOW scheme. While these deadlocks can be addressed by certain standard techniques for deadlock avoidance (see, for example, A. C . Shaw, " The Logical Design of Operating Systems, " pp. 224-227, Prentice-Hall, 1974), the resulting computational overhead may degrade performance significantly. Hence, for each of the deadlocks situations listed below, more details follow, describing the specialized solutions that are simple and efficient and have been used with the DOW implementation. • I/O Inter-dependencies: I/O inter-dependencies created by DOW could give rise to cycles. Furthermore, file system implementations frequently combine multiple disk reads or disk writes for reducing overhead, in a operation called "clustering '. Such I/O clustering could create new, hidden inter-dependencies. • Resource Inter-dependencies: Performing I/O requires resources. A potential for deadlock exists when DOW subsystem attempts to acquire resources, and these attempts conflict with other resource allocation strategies used by the kernel. • Memory Exhaustion with Blocked Pageout Daemon: The Pageout daemon is a system process that is used to free up memory. A special memory exhaustion deadlock arises when the pageout daemon is forced to wait for a sequence of delayed ordered writes to complete. I/ lnter-denendencies An obvious deadlock condition arises if the ordering graph does not remain acyclic. This condition is prevented by cycle checking in dowjprder. To perform exact cycle detection, that is, to identify exactly the situations in which a cycle arises, requires that the DOW subsystem either perform an exhaustive search with every addition of a link to the ordering graph, or, maintain a transitive closure (that is, node-to-node reachability information) over the full ordering graph. Both methods of determining exact connectivity are computationally expensive. The DOW implementation uses the following simple, but fail-safe heuristic in lieu of performing exact cycle detection. Adding a link A→B to the ordering graph is permitted if either (1) A does not have a predecessor node, or (2) B does not have a dependent node. Otherwise, the DOW subsystem executes one of A or B before permitting the link A→B. While the above heuristic successfully detects true cycles and prevents their occurrence, it has the potential for inferring cycles that do not exist and thereby cause some loss of efficiency from node execution. However, the heuristic is very successful in avoiding false cycles because of a characteristic of DOW usage. The construction of an ordering graph by a file system implementation usually proceeds linearly, as in the example of TABLE 5, with predecessors nodes created first and dependent nodes added in sequence. The likelihood that two pre-forrned chains of dependence links ever fuse is very low; so that as new nodes are added to an existing ordering chain, they go to the end of the chain. In other applications of the DOW mechanism, a more sophisticated heuristic or accurate cycle detection may be more beneficial. In addition to cycles, I/O interdependence could result from I/O clustering that is frequently performed by file system implementations. Clustering is a performance optimization in which read or write operations on two or more contiguous disk regions are combined before being presented to the disk drivers. With DOW, clustering presents a deadlock potential, since it may create undetectable I/O dependency cycles. A simple example of such a cycle is when two writes are combined as a single I/O but in which one operation has a direct or indirect DOW dependency linkage with respect to the other operation. Inter-dependence arising from clustering can be avoided by a range of solutions. A general, exhaustive solution would be to cover an entire cluster unit with a special DOW graph node, so that the individual dependence links for each member of a cluster are brought together as dependence links applying to the special DOW graph node for the cluster unit. Another solution is to modify clustering so that the I/O operations are not combined, but issued in quick succession, so that the disk driver can exploit the spatial proximity and sell perform streamlined accesses to disk. For DOW usage, a simple solution has been implemented. This consists of selectively disabling clustering for those disk blocks that are represented in the ordering graph as subjects of delayed writes. For UFS, this solution applies entirely to directory pages. It is seldom the case that the file system implementation has the opportunity for combining multiple neighboring pages of the same directory in a single disk write, so the loss of clustering for directory page writes has a minimal performance impact. Resource Inter-dependencies With DOW, a write operation undertaken by some process may end up having to write out other delayed buffers purely as a side effect. This gives rise to a interdependence, between the original process and other processes, for resources they each hold and which are needed to complete these additional delayed writes. The following example illustrates this problem: • Process Pa holds buffer Y locked, and issues a synchronous write for it. • A buffer (or page) Z must precede Y to disk, so an attempt is initiated (which may or may not be in the context of Pa) to acquire the appropriate lock on Z. • Process P2 holds Z and is waiting to acquire Y before it can release Z. Resource dependence cycles are commonly prevented by using resource hierarchies by which all subsystems perform resource acquisitions. In hierarchy based allocation, each resource category is assigned a hierarchy level, and resource acquisition is permitted only in an increasing (or decreasing) order of hierarchy levels. This ensures that two agents attempting to acquire two resources do not each acquire one of the two resources and then wait indefinitely for the other resource. Thus, a hierarchy allocation rule may have prohibited the allocation of Z to a process that holds Y as a simple means of preventing a resource interdependence from arising. It is difficult or impossible to apply hierarchy rules to the operation of the dow_flush_daemon. Activities of the dow_flush_daemon cause the dismantling of pre¬ existing links in the ordering graph, so that new links can be added, and so that dependent nodes are readied for execution. If a hierarchy rule forces the dow_flush_daemon to wait for a resource such as a specific buffer, and the process holding that buffer waits until the dow_flush_daemon can succeed in removing an ordering link in the graph, then an impasse develops between the two processes. One solution is to have the operating system maintain an explicit knowledge of resource ownerships, and force a process to release a specific resource (to break the deadlock), and fall back to a point from which it can re-initiate its operation. Generally this solution degrades performance noticeably. With DOW usage, a less general but simple and effective solution exists. In this solution a file system implementation that is a DOW client is required to observe this rule: A process is not allowed to hold a resource (e.g., a page or buffer) which is represented in the ordering graph as the subject of a write operation, while blocking for another resource that is also similarly represented. This solution is not restrictive because a directory page, or a buffer containing structural information, needs to be held locked by a process in two cases: • An ongoing device driver operation requires the page (or buffer) to be locked. Device driver operations do not take indefinitely long time to complete, and do not need additional pages or buffers locked. Thus only one resource is held at a time. • The process needs to lock out a page (or buffer) for preventing it from being modified by other processes. This happens when a process needs to either read the data contained in the page (or buffer), or modify the data. The file system implementation can ensure that in such cases, only one page (or buffer) is locked at a time, for a read or write access. There are a small number of instances in the UFS file system implementation that are modified for enforcing the above rule of holding one resource at a time. In all these instances, the file system implementation was previously holding multiple buffers or pages in the course of applying updates. The previous policy of simultaneously holding more than one page or buffer in this way was arbitrary and hence was easily corrected. Memory Exhaustion with Blocked Pageout Daemon The pageout daemon handles lists of free but modified pages; it has to write them to disk before they can be available for fresh use. In order to submit a page to a disk driver, the pageout daemon uses a memory unit called "buffer header" to record some auxiliary information about the page, and then passes the address of the buffer header to the disk driver. Normally, the memory needed for this purpose is obtained from a dynamic kernel memory allocator (KMA), to which it is returned as writes complete. To permit graceful system recovery under extremely severe memory conditions, the kernel maintains a small, "contingency" memory pool for critical uses. If KMA cannot furnish the needed memory to the pageout daemon, then the kernel provides the needed memory from this contingency pool, and as the page writes complete, returns the memory to the contingency pool. When the DOW mechanism is used, the dow_flush_daemon is provided memory from the contingency pool as well, for the asynchronous page writes that it needs to perform, if KMA cannot furnish the needed memory. As the number of deferred page writes increases, the deferred writes pose a threat to the ability of this contingency pool to cover them in the event of a severe memory exhaustion. If pageout daemon cannot continue to operate in this situation, then a system deadlock can result. This deadlock is prevented by detecting that the count of deferred page writes due to DOW use has crossed some threshold. When this happens, new dependence creation by the DOW mechanism is disabled temporarily, until the count has been reduced. In the meantime, the system is forced to revert to using synchronous writes instead of creating new ordering dependencies. This operation is done transparently by having dowjorder perform the synchronous writes directly on behalf of the file system implementation. Performance Gain From Delayed Ordered Writes Comparison of system performance with and without the use of delayed ordered writes in UFS shows that dramatic gains have been achieved by replacing synchronous disk writes with DOW. The measurements were made on a UNIX System V Release 4.2 MP Operating System, running on a single Intel 486/33 Mhz processor with the IDE disk subsystem. The benchmark used for measuring system performance was the System Performance Evaluation Cooperative's Software Development Environment Throughput (SPEC SDET) benchmark (see System Performance Evaluation Cooperative, 057.SDET Benchmark: A User's Guide). The comparison is drawn by normalizing the measurement data to the results obtained without the use of delayed ordered writes. The SPEC SDET benchmark simulates a multi-user workload in a program development environment and measures throughput as a function of the number of simulated users. In this benchmark, each user is simulated by the execution of a UNIX shell script that is composed of a randomized sequence of commands. A representative script consists of commands to edit files, compile and link programs, create, remove, and copy directories and files, and text formatting and spell-checking documents. While each script executes a different sequence of these commands, all scripts are composed of the same aggregate command mix, so that the total work done by each of the simulated users is identical. In the absence of DOW usage, the performance of the benchmarked system is found to be limited by the speed with which read/write I/O is performed to disk. Normalized System Throughput - FIG. 15 FIG. 15 compares the normalized system throughput with and without DOW usage. DOW usage improves the SPEC SDET measure of system's peak performance by more than a factor of two. This happens as the benchmarked system moves from being disk bound in the base case to becoming bound by the processor execution speed with DOW usage. Disk Write Operations Reduction - FIGs. 16 and 17 The reduction in disk write operations is confirmed by FIG. 16 which shows that the number of disk write operations reduces by 85% the number without the use of DOW. An added benefit from the reduction of synchronous writes is a 50% drop in the aggregate number of process context switches, as shown in FIG. 17. Decrease In Disk Service Time - FIG. 18 An additional indirect benefit of using delayed ordered writes is a decrease in the average disk service time, as shown in FIG. 18. The decrease in disk service time occurs because the dow flush daemon can issue multiple concurrent disk requests (since its disk operations are not synchronous), and thus enable the disk driver to better schedule these disk writes for best disk access performance. Network File System Environment - FIG. 19 The computer system 3 of FIG. 19 is a server system that connects to a client system in the form of computer system 203. The computer system 3 of FIG. 19 like in FIG. 1 is composed of hardware 5 and software 6. The hardware 5 includes one or more processors 10, typically a central processing unit (CPU), main storage 11, input/output (I/O) in the form of secondary storage 12 and other input/output devices 13-1, ... 13-N. The software 6 includes an operating system 14 and user (application) programs 15. The computer system 3 executes user programs 15 in the hardware 5 under control of the operating system 14. A common instance of the operating System 14 is the UNIX* operating system. The client computer system 203 of FIG. 19 is composed of hardware 205 and software 206. The hardware 205 includes one or more processors 210, typically a central -51- Si INSTITUTE SHEET (RULE 26) processing unit (CPU), main storage 211, input/output (I/O) in the form of input/output devices 213-1, ... 213-N. The software 206 includes an operating system 214 and user (application) programs 215. The computer system 203 executes user programs 215 in the hardware 205 under control of the operating system 214. A common instance of the operating system 214 is the UNIX operating system. The I/O devices 13-1 and 213-1 in the server system 3 and the client system 203, respectively, connect the systems 3 and 203 together through a network 50 to form a Network File System (NFS). The network 50 is any conventional local -εrea network. An example of the use of delayed ordered writes in place of synchronous writes to improve response time and throughput in the Network File System is described. The Network File System (NFS) permits sharing of files between different computer systems connected via a network. NFS allows processes located on one computer system, such as NFS client system 203, to access files on a (usually) different computer system, such as server system 3. On an NFS server system 3, several processes called server processes execute in order to provide the necessary file access services to client system 203. When a process running on the client system 203 wishes to access a file on the server system 3, it sends a request through the network to the server system 3. The request is handled by one of the server processes, which performs the operation specified by the request, and then sends a response back across the network to the client. The response may include data or status information. Before it sends a response back to the client, the server process must ensure that all data modifications associated with the request have been written to disk. For example, on a file write request, the server process must write the file data to disk along with any -52- SU3STITUTE SHEET (RULE 26) structural modifications such as the inode and indirect blocks, wait for those writes to complete, and then send the response back to the client. Server processes typically use synchronous writes to meet this requirement. For example, to service a write request, a server process uses synchronous writes to write data, inode, and, if necessary, indirect block modifications to disk. Since the server process waits for each synchronous write to complete before proceeding, this use of synchronous writes guarantees that the data will be on disk before the response message is sent. Typically, a server process takes these steps, in time order, to service a client request for writing a file: 1. Acquire lock protecting file data structures. 2. A. Modify in-memory copy of indirect block, if necessary. B. Synchronously write buffer containing indirect block to disk, if modified. 3. A. Modify in-memory copy of file data. B. Synchronously write buffer containing file data to disk. 4. A. Modify in-memory copy of inode. B. Synchronously write buffer containing inode to disk. 5. Release lock protecting file data structures. 6. Send response message back to user. One major drawback of this scheme is that if multiple requests arrive for the same file, the server processes handling these requests will each need to acquire the same lock (in step 1, above). One process at a time would acquire the lock, perform steps 2, 3, and 4. and then release the lock for another process to acquire. The time for which the lock is held includes the duration of time that each of the synchronous disk writes in steps 2B, 3B, and 4B take. Thus, each server process will hold the lock for a long duration before allowing another server process to perform work for the same file, and thereby reduce the ability of the NFS server to provide fast response and high throughput to its clients. A second drawback in the above scheme is that the disk is likely to be under utilized. Because the synchronous writes are serialized, each is sent to the disk driver one at a time. The disk driver is thus forced to schedule the writes in the order in which they are requested, even if an alternate order would be more efficient. Also, little or no overlap of work happens between the disk driver and the server processes, since the disk driver stays idle during the interval between the completion of one write and the initiation of the next, and since the server process needs to wait for each of the disk writes to complete. An alternative scheme would be to use delayed ordered writes in place of synchronous writes. In this scheme, the server process could instead issue delayed ordered writes, and specify an ordering relationship between each write and a deferred function call which would signal the server process when all the writes have completed. Instead of holding the lock across all of its operations, a server process would need to hold the lock only during the modifications of in-memory copies of the information that is modified; and the time spent waiting by a server process for disk write completions would not inflate the lock hold time. Specifically, in the DOW-based scheme, server process would take the following steps to service a write request: 1. Acquire lock protecting file data structures. 2. Create DOW node for function call to signal the server process. 3. A. Modify in-memory copy of indirect block, if necessary. B. If the in-memory copy of the indirect block has been modified, establish an ordering specifying that the function which signals the server process is to be called after writing the buffer containing the indirect block. C. If the indirect block has been modified, issue delayed or asynchronous write to disk of buffer containing indirect block. 4. A. Modify in-memory copy of file data. B. Establish an ordering specifying that the function which signals the server process is to be called after writing the buffer containing the in-memory copy of the file data. C. Issue a delayed or asynchronous write to disk of the buffer containing the file data. -54- SUBSTITIJTE SHEET (RULE 26) 5. A. Modify in-memory copy of inode. B. Establish an ordering specifying that the function which signals the server process is to be called after writing the buffer containing the in-memory copy of the mode. C. Issue a delayed or asynchronous write to disk of the buffer containing the inode. 6. Release lock protecting file data structures. 7. Wait for signal (coming from function) that the disk writes have completed. 8. Send response message back to user. This scheme addresses the two drawbacks of the previous scheme. First, the file lock is only held during the time that the in-memory file state is modified, and the DOW graph is being constructed; it is released before the disk writes complete. This means the lock is held for much less time on each write, and lock contention is reduced. The reduced lock contention in turn means that each server process acquires the lock sooner, and is able to begin servicing its request more quickly. Secondly, in this scheme, each write request is handed to the disk driver before the previous one completes. This allows the disk driver to schedule the disk jobs more efficiently, and tends to keep the disk queue full, which also makes more efficient use of the disk. Network File System Directed Acyclic Graph - FIG. 20 FIG. 20 depicts the directed acyclic graph for the network file system of FIG. 19. Conclusion The present invention provides a facility called Delayed Ordered Writes (DOW), which is used by a file system implementation to schedule the writing of a set of data items from primary to secondary storage so that the writing of these items occurs in a specific, desired order. Use of this facility makes it unnecessary to employ synchronous disk writing for guaranteed ordering among disk writes. The performance benefits of using this facility are significant. Disk writes are reduced by nearly an order of magnitude for typical UNIX operating system workloads because of the much improved disk write caching that is possible with delayed writing. In addition, context switching is reduced as well, which improves the productive utilization of the processor. The DOW usage and performance gains were measured in the context of the UFS file system implementation in a recent version of the UNIX Operating System (System V, Release 4.2 Multi-processor UNIX Operating System). DOW can be used equally beneficially with other file system implementations, such as the AT&T UNIX System V (S5) file system. It may also be used, for example, to extend the benefits already achieved in some file system implementations from the use of techniques such as disk logging. The DOW facility is available as a modular service, which will facilitate its integration into other UNIX Operating system implementations. While it is available as a mechanism for enforcing ordering among the writing operations, the policy for determining the necessary ordering is maintained with the clients of the DOW facility. Furthermore, a DOW client retains the ability of enabling or disabling the DOW optimization at run time, and to apply the optimization selectively among the write operations that it needs to perform. With DOW use, a file system implementation obtains dramatic improvement of performance without losing file system media compatibility and with minimal modification of code structure. Use of delayed ordered writes in some applications can increase parallelism, thereby improving performance without necessarily reducing the number of disk writes. -56- SUBSϊiTυϊE SHEET (RULE 26) A program listing that is an actual embodiment, in combination with a UFS file system, of the present invention appears in the attached LISΗNG APPENDIX which includes the following modules: LISTING APPENDIX MODULES Master Configuration file (in dow.cf directory) System Configuration file (in dow.cf directory) dow.h Header file describing all data structures and convenient macros. dow_cancel.c File containing function for removing operation entries. dow_check.c File containing functions for correctness checking. dow_create.c File containing functions for creating dow nodes for buffers, pages, functions. dow_flush.c File containing functions for dow_flush_daemon. dow handle.c File containing some of the functions for executing dow nodes and to wait for pending executions to complete. dow_io.c File containing driver layer functions. dow_leaf.c File containing functions explicitly for executing dow nodes that have no predecessors. dow order.c File containing dow_order function. dow_prune.c File containing code for pruning a dow graph dow_util.c File containing functions for allocating and releasing dow nodes. dowlink util.c File containing functions for allocating and freeing ordering entries. While the invention has been particularly shown and described with reference to preferred embodiments thereof it will be understood by those skilled in the art that various changes in form and details may be made therein without departing from the spirit and scope of the invention. J lldent '(3(1 Jkern: fβ/dow.cf/Haater 1.1' 3 lldent 'SHeader: $' 3 $version 1 4 Sentry lnlt poβtroot 5 dow dow - 0 0 0 33 rn 8 1 lldent '(3(l)kern:fβ/dow.cf/Syβtem 1.3* 2 lldent '$Header: $' 3 Sveralon 1 4 Sloadable dow 5 dow Y O O O O O O O O -1 £ 1 l ldent m (d(l )kern : fs/dow. h 1 . 6 ' ■ 3 lldent "SHeader: $ ' 3 4 II f deflned(_cpl uspl u3) 5 extern "C m ( 6 lendl f 8 l fndef _FS_DOW_H 9 Ideflne _FS_DO»_H 10 " 11 llfdef KERNEL 12 13 I Include <fs/bυf . h> 14 llnclude <fs/vnode . h> 15 llncl ude <utll/kβynch. __> 16 llncl ude <utll/typeβ . > 17 ._ 18 typedef shor .dowid_t; C; 19 typedef short dowlinkid_t; CO • 20 21 /. -H 32 * A note on DOH structures and struncture linkages. C". .33 • ni . 24 * Each dow structure is used to represent one unit of deferred actiont (~s 25 * a write or a deferred function. When not in use, unless a hold is __C 9 26 * active on a dow structure, the structure is placed on a free list |X5 27 * for allocation to a new use. —. 28 • 3 ' 39 * When in use, a dow structure is placed on lose hash chain and one of CZZ 30 * three flush chains -- with one exception. The exception is when a dow m 31 * structure is "aborted", but cannot be freed due to an existing hold r 33 » by soae context. In this case, the dow structure is Barked as having _<2? 33 • been abolished ( "DOKjBOHE"), and is not placed on any hash chains. .34 * This fact is exploited to union the freelist linkage with the hash 35 * chain linkage in the dow structure. 3b » 37 * There are three flush chainst (a) leaf flush chain, (b) non-leaf, 38 * "pruned" flushed chain, and (c) an aged flush chain. The flush 39 • chain Membership determines how a dow structure is handled through 40 • various operations, and is described in βoae detail in dow_ j prunβ.c 41 * In brief, flush chains are used to divide work aaong different 42 • dow functions by isolating those actions that need to be performed 43 * quickly from those that do not have an associated urgency. 44 * ♦5 46 47 typedef struct dow | 48 union { 49 struct I 50 dowld t dowfreenext; 51 dowld t dowfreeprev; 52 ) dowfreelinks; 53 struct ( 54 dowid_t dowhashnext; 55 dowid t dowhashprev; 56 ) dowhashllnks; 57 ) dow_linkβ; 58 dowid_t dow flushnext; 59 dowld_t dow_ lushprev; 60 uchar_t dow_βpare; /* free space */ 61 uchar_t dow_level; /• level depth i currently unused */ 62 uchar_t dow_dep_cnt; /• nuaber of inediate dependents */ 63 uchar_t dow_ant_cnt; /* nuwber of i_u_ediate antecedents */ 64 /* 65 • sync variable to signal waiters on 66 * the DOW INTRλNS state. 67 68 The hash bucket SVβ are used, on ther other hand, 69 to iapleaent a paeudo sleep lock for signalling 70 the aodify-buβy exchange between dow_βet__od and CO 71 dow_βtrateg . 72 */ 73 sv t dow sv; 74 75 uchar_t dow_βtate; O ___: ff_ 76 /* m 77 • dowjtype specifies whether it is a page, a buffer, 3 78 * a general function, or a non-blocking function 79 V ro 96 /* pageio buffer header pointer */ 97 98 * we should not rea y need to rewewber 99 * aize for a delayed write buffer, since we 100 * expect that a waiting variant of blookup 101 * auat find the buffer if the DOH is aarked 102 * aodifled. however, we reaeaber it anyway, 103 * for now -- for convenience. 104 V •105 union ( 106 long dowbslze; /« block size for a buffer dow */ Λ07* long dowlen; /* length of unit of a "page" dow 108 ) dow_u3; 109 /* 110 * dow_Bθd_lock coun i for pages only. He could union it 111 * with the dow_bsize field, above. 112 •/ 113 short dow mod lock; 114 /• 115 * b_iodone b_iochain linkage 116 V 117 vo1 (*dow_b_iodone) ( ) ; 118 void *do.w b iochain; DEBUG dowid t dow_debug_haβhid; dowld_t dow_debug_ luβhid; short dow_debug_cnt; tate values DOU NODIFIED 0x01 DOH 1NTRANS 0x03 DOW FLUSH 0x04 DOW IOSETUP 0x08 DOH PRUNE 0x10 DOW GONE 0x30 135 136 137 * coBBon coapound tests of dow structure state: following are useful. • 138 V 139 Ideflne DOW_MOD1 NTRANS (D0W_M0DIFIED / D0H INTRANS) 140 Ideflne DOH FLOSHINTRANS (DOW FLUSH I DOW_INTRANS) 141 Ideflne DOH MODPRUNE (DOW_HOD1FIED / DOW_PRUNE) 142 143 144 145 .146 * dow_type values 147 V 148 Ideflne DOW ISBUFFER 0x01 149 Ideflne DOW ISPAGE 0x03 150 Ideflne DOH 1SFUNC 0x04 includes DOH ISHJNC •/ froa dow order nowalt 200 Ideflne DOW ID TO_P(x) ((void *)(t(dow_tab[(x)J))) 201 Ideflne D0W_ P_ 7O_ ID f i daddr) ( ( (dow_ t )(ldaddr)) - (i(dow_tab(0) ))) 202 Ideflne DOW HOLD(x) ( (dow_ tab l(x)t).dow hold) 203 Ideflne DOW LEVEL(x) ((dow_tab I (X)) ) .dow_level) 204 Ideflne DOW_DEP_CNT(x) ( (dow_ tab I (") 1 ) ■ dow_dep_cnt) 205 Ideflne DOW_ANT_CNT(x) ( (dow_ tab I (")I ) -dow_ant_cnt) 206 Ideflne DOW_ TIMESTAMP (X ) ( (dow_ tab I (x) I ) ■ dow_ timestamp) 207 Ideflne DOW_ FREENEXT(X) ( (dow_tab I (x) I ) .dow_ free next) 208 Ideflne DOW FREEPREV(x) ( (dow_ tab I (x) I ) ■ dow_ freeprev) 209 Idefine DOW HASHNEXT(X) ( (dow_ tab [ (x)l ) .dow ^ hashnext) 210 Ideflne DOW HASHPREV(x) ((dow_tab !(*)})• dow_hashprev) 211 Ideflne DOW FLOSHNEXT(X) ( (dow_ tab [ (x)] ) ,dow_flushnext) 212 Ideflne DOW FLUSHPREV(x) ( (dow_tab l(x)l ) .dow_flushprev) 213 Ideflne DOW SVP(x) (t(dow_tab !(*)]) .dow_sv) 214 Ideflne DOW STATE(x) ( (dow_tab l(x)J) .dow_βtate) 215 Ideflne DOW_TYPE(x) ( (dow_ tab I (X) 1 ). dow_ type) 216 Idefine DOW_DEV(x) ( (dow_ tab l(x)l ) .dow_dev) 217 Ideflne DOW VP(x) ( (dow_ tab l(*)l) -dow_vp) 218 Ideflne DOW FUNC(X) ((dow_tab I (x)J ) .dow_func) 219 Ideflne DOW IDENTI X) ( (dow_ tab l(x)}).dow_ldentl) 220 Ideflne D0W_BLKN0(X) ( (dow_tab l(x)] ) .dow_blkno) 221 Ideflne DOW OFFSET(x) ( (dow_ tab l(x)l). dow_offset) 222 Idefine DOW ARGP(X) ( (dow_ tab l(x))).dow_argp) 223 f define DOW_IDENT3(x) ((dow_tab t(x)l).dow_ldent3) 224 Ideflne DOW BP(X) ( (dow_tab t(x)l)-dow_bp) 225 Ideflne DOW BSIZE(X) ( (dow_ tab I (x ) ] ) . dow_bslze) C/_ 226 Ideflne DOW LEN(X) ( (dow_ tab l(x)l).dow_len) 227 Ideflne DOW_M0D_ 3CK(x) ( (dow_ tab m t (x) I ) . dow_mod_lock) 228 Ideflne DOW_B_IOCHAIN(X) ( (dow tab I (x) ) ) . dow_b_lochaln) 229 Ideflne DOW B IODONE(X) ( (dow_ tab I (x) I ) • dow_b_lodone) 33 230 Ideflne DOW SPARE(X) ( (dow_ tab [ (x) ] ) . dow_spare) 231 232 llfndef DOW KLODGE ro 233 Ideflne DOW_TRACKED 0x01 n 234 Ideflne DOW POTPAGED 0x03 235 Idefine DOW STRATTED 0x04 .236 Ideflne DOW WRITTEN 0x08 237 extern void mar_c_vp_of fβet_dows(vnode_t *, off_t , uchar_t); 238 extern void check_vp_of fβet_dowβ(vnode_t *, off_t ); 239 Ideflne MARK_VP_OFFSET_DOWS(x, y, z) mark_vp_offset_dows((x), (y), (z)) 240 Ideflne CHECK_VP_OFFSET_DOWS(x, y) check_vp_offset_dowa((x), (y) ) 241 leJse 242 Idefine DOW TRACKED 243 Ideflne DOW_PUTPAGED 244 Ideflne DOW STRATTED 245 Ideflne DOW_WRITTEN .246 Ideflne MARK_VP_OFFSET_DOWS(x, y, z) 247 Ideflne CHECK_VP_OFFSET_DOWS(X, y) 248 lendif 249 250 251 llfdef DEBUG 252 Idef lne DOW_DEBUG_HASHlD(x) ( (dow tabl (x) ] ) . dow debug hashld) 253 Idefine DOW DEBUG FU)SBlD(x) ( (dow tabl (x) J ) . dow_debug_fluβhld) 254 Ideflne DOW_DEBUG_CNT(x) ( (dow tabl (x) I ) . dow debug cnt) 255 lelse 256 Ideflne DOW DEBUG HASHID(x) 257 Idefine DOW_DBBUG_FLυSHID(x) 258 Ideflne DOW_DEBUG_CNT(x) 259 lendl f 260 261 /• 262 * DOW_CHEAF_l.EI.__ and DON_CBEAP_HOLD are used to adjust the hold 263 * count without doing auch else. 264 •/ 265 Ideflne DOW_CHEAP_BOLD(x) (++(DOW_H01D( (x) ) ) ) 266 Ideflne DOW_CHBAP_RELB(X) ( - - (DOITHOLD((X) ) ) ) 267 268 Idefine .DOW_DEP_MAX 33 269 Ideflne DOW_ANT_MΛX- 33 270 Ideflne DOW_AGB_TlX (US • 5) /* 5 seconds «/ 271 Idefine FLUSHDELTAHAX (HZ • 180) /• ISO seconds -- "infinite dow delay" •/ 272 Idefine MAX_RECUR 7 273 d 274 /• —I 275 * DOW IMK structuresi v 276 • ϊ > 277 • The dowlink structures are used in linking up dows into chains of en ^ 278 * antecedent or dependent structures. Since these relationships can J 279 * be one->aany in each direction, we cannot use fields within dow ^ _ ^ 280 • structures for encoding the*. So we use the dowlink structures; 32 281 * each dowlink structure encodes a single dependence. f= 282 »/ m 283 typedef struct do _link [ ro 284 /* - 285 * the dowlink_next/dowlink_prev linkages double aβ free list 286 * linkages for non-aotivβ link structures; furthermore, the 287 • dowlink prev linkage la used for doubly linking the free 288 * list ONLY in DEBUG aode. 289 •/ 290 dowlinkid_t dowllnk_next; 291 do linkld t dowlink_prev; 292 /• 293 * Suppose this link is on a chain that specifies the antecdentβ of 294 * a dow, say X. If this link specifies the dependencei (X --> X), 295 * then the following two fields identify) 296 * (a) the inverse link: (T <-- X) -- on T's list of antecdentβ 297 * (b) the dowid, T. 298 * 299 * Similarly, if the link specified an antecdence relationship, 300 * say, (X <-- I) , then the inverse link would be the one on K'a 301 * list of antecdentβ that specifies (8 --> X). 302 V 303 dowllnkid t dowlink lnverβe;/* the inverse link */ 304 owld t dowllnk do ld; /* the antecdent/dependent dowid */ 305 llfdef DEBUG 306 /• 307 * the dowlink_debug_lhead field identifies the link chain head. 308 •/ 309 dowlinkid_t dowllnk_debug_lhead; 310 /« 311 * dowllnk_debug_cnt is used only by llnkheaders. but since this 312 * is a DEBUG node field, we don't try to union it away with something 313 * elβe in order to βave βpace. 314 •/ 315 short dowlink_debug_cnt; 316 lendlf 317 ] dowlink ; 318 £? 319 Idefine DOWL1 K NEXT ( 1 ) ( (dow_llnk_tah( ( I) ] ) .dowllnk next) 5 320 Ideflne DOWLINK_PREV(i) ( (dow_llnk_tab( (1) J ) .dowlink_prev) 321 Ideflne D0WL1NK_INVERSE(1) ( (dow_llnk_tab[ ( 1)]) .dowlink_inverse) Ξ 322 Idefine DOWLINK DOWID(l) ( (dow_llnk_tab( (1 ) ) ) .dowllnk_dowld) CZ 323 ^j 324 llfdef DEBUG 325 Ideflne D0WL1 NK DEBUG ΪDOW ( 1 ) \ CO 326 <(dow_link_tabl(i)J) .dowllnk_debug_lhead * DOW_TABLE_SIZE) 327 Ideflne DOWLlNK DEBUG LHEAD(l) ( (dow_link_tab( (i )) ) .dαwllnk_debug_lhead) fc 328 Ideflne DOWL1 NK_DEBUG_CNT ( 1 ) ( (dow l nk tabf (1 ) ] ) .dowlink_debug_cnt) 329 eJse < 3~3 330 Idefine DOWLINK_DEBUG_HYDOW(l) r^ 331 Idefine DOWLΪNK_DEBUG_LHEAD(l) m≡ 332 Ideflne DOWL1 NK DEBUG CNT ( 1 ) r ^o 333 lendlf 334 335 336 /• 337 * structure for iochaining the untracked pageio function, to prevent 338 * potential reβource deadlockβ when tracking pageios for which dow 339 * atructurea could not be allocated. 340 V 341 typedef struct dow_io_utp { /* utpt UnTrackedPageβ */ 342 struct buf *dlu_bp; • 343 void (*diu_func)() j 344 void «diu _ chain; 345 ) dow_lo_utp_t; 346 347 Ideflne MAX UNTRACKED PAGES 64 348 349 /• 350 • dow_io_utp_tab is an array of dow_io_utp structures, each used to track 351 pages in transit that do not have DOWs associated with thew, due to 352 failure to allocate the dow structures. 353 •/ 354 extern 355 extern dow structures array •/ 356 extern dowlink structures array */ 357 extern I free dows */ 358 extern I free dowlink structures */ 359 extern I untracked in-transit pgs */ 360 extern global spin lock */ 361 extern 362 extern SV for dow resource wait */ 363 extern SV for dowlink res. wait */ 364 extern 365 extern ol dow_lo_utp_t alloc •/ 366 t/ϊ C3 O —. O __c 30 m 399 Ideflne DOWLim_FREE_SV_INIT( ) _- V_Iwrτr«dowlln*_free_βv 400 Ideflne DOWLlNK_FREE_SV_WAlT( ) SV_WΛiτf «do-/lijι*_/ree βv PRIBUF, tdow_mutex) . 405 Ideflne DOW_FLUSH_EVENT_CLEAR( ) EVENT_CLEAR(tdow_fl ush_event) 406 Idefine DOW_FLUSH_BVENT_WAIT( ) EVENT_WAIT(tdow_flush_event, (PRIBUF * 1) ) 407 Ideflne DOW_FLOSH_BVENT_BROADCAST() EVENT_BROADCAST(tdow_flush_event, 0) 408 Idefine DOW_FLUSH_EVENT_INIT() EVENT_ INIT(tdow_fluah_event) 409 410 411 Ideflne DOH AVAIL(x) (dow_f reecount >- (x) ) 412 Ideflne DOWLINK_AVAIL(x) (dowllnk_f reecount >- (x) ) 413 414 415 The dow structures are organized as a statically allocated array. 416 The array alao includes space for a aet of apecial dow atructuresi 417 these are the dow structures that are used as anchors for the control 418 lists, nawely the hash chains, the flush chains, and the freelist. 419 420 flush CO 421 chain 122 heads 425 I I I I I I I I I I I I I I I I I I I .426 +-+-+-+-+-+-+-+-+-+ +_.+_.+.+ +_.+_.+-+-4 _____ 427 |<- usable dow atructs >|<-- hash ->| \ m 428 chain heads free chain head 429 430 DOH array 431 432 The first DOH_TAB E_SIEE elements are the DOH structures 433 to be used in setting up ordering information. _π 434 435 The next DOH_EASHHIDTH elements are used aβ heads for 436 doubly linked DOH hash chains. 437 438 The next 3 eleaents are used as heads for three doubly linked 439 flush chainst 440 leaf chaini dowa that have, no antecdents and are ready 441 for completing deferred action, 442 pruned chain: dowβ that 443 - either have antecdents but have been pruned 444 (i.e., all their antecdentβ have been either 445 pruned or moved to the leaf chain). 446 - or have been proceββed and/or aborted, and are 447 waiting for their holds to go to 0, so that they 448 can be freed. If abort processing has been 449 completed, then the dows are not on hash chains. 450 aged chaini active dowβ that are not on the other two chains. 451 452 Please refer to the notes section for prune( ) faaily of functions 453 for aore detaila on how the flush chains are populated. 454 455 The last 1 elewent is used aa head of a free liat (singly 456 linked normally; doubly linked in debug node) . 457 458 459 460 461 462 The dowlink structures are organized aβ a statically allocated array, 463 juβt as the dow βtructureβ are. However, the control lists are different. 464 For convenience, a set of dowlink βtructureβ serve aβ anchors for 465 linked liatβ of dependentsi one anchor for each usable dow atructure. 466 Similarly, a second set of dowlink structures are used aβ anchors of 467 linked lists of antecedent*, one per usable dow atructure. 468 These contolllng atructureβ are placed at the beginning of the dowlink 469 structure array.. CO 470 ____: 471 Next coae all the usable dowlink βtructureβ. CD 472 C 473 These are followed by a single dowlink atructure that serves aβ the 474 anchor for the free chain of dowlink structures. s 475 476 free chain 477 dependents antecedents head 478 chain chain \ 479 +- ♦ 480 I 'anchors | anchors | usable dowlink structures I I 481 + +. + —+-+ 482 DOHLINK array 483 484 The first (2 * DOH_TABLE_SIIE) entries are uβed aβ heads of 485 link chainsi for dependent and antecdent chaina for each of the 486 DOH atructure. Entries k and (DOW_TABI_E_SIz__ ♦ k) respectively 487 serve aa dependent and antecdent link chain heada for the DOH 488 structure whoβe index la k. 489 490 The next (DOH__.imS___λTIO • DOH_TABX.E_SIZE) entries are the 491 real link entriea that can be allocated and uβed for setting 492 up linkages. 493 494 Finally, the laβt entry in the DOHLINK array βerveβ aβ the 495 head of a free chain. The chain iβ βingly linked except in 496 debug aode, when it iβ doubly linked. 497 498 499 Ideflne D0H_TΛBLE_S1ZE 500 500 Ideflne DOW HASHWIDTH 31 SOI Idefine DOW LEAF FLUSHHEAD (DOW ARRAYSIZE - 4) 502 Idefine DOW_PRUN_FLUSHHEAD (DOW ARRAYSIZE - 3) 503 Idefine DOW_AGED_FLUSHHEAD (DOW ARRAYSIZE - 3) 504 Ideflne DOW_FREEHEAD (DOW_ARRAYSIZE • 1) 505 Idef ne DOW ARRAYSIZE (DOW_TABLE_SIZE + DOW HASHWIDTH + 3 + 1) 506 Idef ne DOW FIRST HASHBUCKET DOW_TABLE_SIZE 507 Ideflne DOW LAST HASHBUCKET (DOW_FIRST_HASHBUCKET f DOW HASHWIDTH 1) 508 Idefine DOW HASHBUCKET ( is what, ls_whlch) \ 509 ((((ulong_t)(lβ_what) + (ulong_t) (Is which) ) % DOW HASHWIDTH) \ " 510 DOW TABLE SIZE) 511 512 Ideflne DBPENDENT_LINKS 0 /* froa each dow to lta dependents */ 513 Idefine ANTECDENT_LI NKS 1 /* froa each dow to ita antecedents */ 514 Idefine DOW_LINKSRAT10 8 515 Ideflne DOWLI NK TABLE BASE (3 * DOW_TABLB_SIZE) 516 Idefine DOWLI NK_NAXFREE (DOW LINKSRATIO * DOW_TABLE_SIZE) 517 Idefine DOWLINK ARRAYSIZE (DOWLINK_TΛBLB_BASE DOWLI NK NAXFREE + 1) 518 Ideflne DOWLINK FREEHEAD (DOWLINK_ARRAΫSIZE - 1) 519 Ideflne DOWLINK_DEP_LINKHEAD(dow_ld) \ 520 ((dowliπkid_t)<(dow_id) + (DEPENDEWT_ INKS * DOW_TABLE_SIZE)) ) 521 Idefine DOWLINK_ANT_LINKHEAD(dow_id) \ CzD 522 ((dowlinkid_t)((dow_id) + (ANTECDENT LINKS « DOW TABLE SIZE) ) ) 523 524 525 526 • We use an arbitrary negative dowid t aβ an invalid dowid return value, o 527 • and another arbitrary negative dowlinkid t aβ an invalid dowlinkid C _rO ( 528 • return value. 3_.9 530 331 Ideflne DOW BADID (-3319) 33 532 Idefine DOW_NONE DOW_BADlD /* useful aynonya */ 533 Ideflne DOWLINK BADID (-39448) ' 534 Ideflne DOW BAD 1OD0NE ((void (*)())(0xffffffff)) 535 Ideflne DOW BAD IOCBAIN ((void *) (OxOcOcOcOc) ) 536 537 538 539 Following aacroβ perait easy range checks. 540 541 542 Ideflne VALID DOWID(l) \ 543 (((i) >- (dowid t)O) St ((i) < (dowid_t)DOW_TABLE_SIZE. ) 544 545 Ideflne VAL1D_HASH_BUCKET(1 ) \ 546 (((1) >- (dowid_t)DOW_TAB E_SIZE) tl \ 547 ((i) < <dowid_t)(DOW_TABLE_SIZE + DOW HASHWIDTH) ) ) 548 549 Ideflne VALID_FLUSHHEAD(1) \ 550 (((1) >- (dowid_t)(DOW_TABLE_SIZE * DOW HASHWIDTH) ) It \ 551 ( ( 1 ) < (dowld_t) (DOW_TABLE_SI ZE + DOW HASHWIDTH + 3 ) ) ) 552 553 Idefine VALID DOWLINK_ ID(j) \ 554 ( ( ( j ) - (dowl inkid t) DOWLI NK TABLE BASE) tt \ 555 ( ( j ) < (dowliπkid_t) (DOWLINK_TABLE_BASE * DOWLINK MAXFREE) ) ) 556 557 Ideflne VALID DOWLINK HEAD(j) \ 558 (((J) - (dowllnkld_t)0) tt ((j) < (dowllnkld_t)(2 * DOW_TABLE_SIZE) ) ) 559 560 * Following aacros perait consiβtecy checks for various doubly linked lists. 561 V 562 Ideflne DOW_HASHLINKS_SANB(l) \ 56) ((DOW_HASHPREV(DOW_HASHNEXT(i)) — (i)) tt \ 564 (DOW_HASHNEXT(DOW~HASHPREV(i)) — (i))) 565 566 Ideflne DOW_FLUSHLINKS_SANE( 1 ) \ ((DOW FLUSHPREV(DOW_FLϋSHNEXT(l)) — (1)) It \ (DOW_FLUSHNEXT(DOW_FLOSHPREV(i)) — (1))) Idefine D0WL1NK_LINKS_SANB(1) \ ( (DOWLIHK_NEXT(DOWLINK_PREV(i)) -- (i)) it \ (DOWUNK_PREV(DOWLINK_NEXT(i)) —» (i))) Idefine DOWLlNK_ILINK_SANE(l) (D WLINK_lNVERSE(DOWLINK_INVERSE(l ) ) — (1 ) ) Ideflne EMPTY_DOWLINK_LIST( list head) ((llsthead) -- DOWLINK_NBXT( (listhead) ) ) Idefine EHPTY_DOW_FRBELIST(listhead) ((llsthead) — DOW_FREENEXT( (llsthead) ) ) Idefine EMPTY_DOW_HASHLIST(llsthead) ((llsthead) — DOW_HASHNEXT( (llsthead) ) ) Ideflne EHPTY_DOW_FLUSHLIST(lBthead) ( (lsthead) — DOH_FLUSHNEXT( (lβthead) ) ) llfdef DEBUG /* * Macros for DEBUG field updates. Id Veflne DOW DEBUG_BASHBNTBR(id, bucket) ( \ 587 ASSERT(VALlD_DOWID(id)); \ 588 ASSERT(VALID_HASH_BUCKET(hbucket)); \ 589 ASSERT(DOW_DEBUG_HASHID(ld) — DOW BADID) ; 590 DOW_DEBUG_HASHID((id)) - (hbucket); \ 591 ++DOW_DEB0G_CHT((hbucket)); \ 592 CHECK_HASH_CHAIN(hbucket); \ 593 ) 594 595 Idefine DOW_DEBUG_FLUSHENTER( id, f Ihead) I \ 596 ASSERT(VALID_DOWID(id)); \ 597 ASSERT(VALID_FLUSHHEAD(fIhead)); \ 598 ASSERT(DOW_DEBUG_FL0SHID(id) -- DOW BADID); 599 DOW_DEBUG_FLUSHID((id)) - (fIhead) ι \ 600 ++DOW_DEBUG_CNT((flhead))» \ 601 CHECK_FLUSH_CHAIN((f Ihead)); \ 802 ) 603 604 Ideflne DOW_DEBUG_HASHLEAVE(ld) 605 ASSERT(VALID_DOWID(id)); 606 hbucket - DOW_DEBUG_HAS 607 ASSERT(VALID_HASH_BUCKET 608 DOW_DEBUG_HASHID((id)) - 609 --DOW DEBUG CNT( hbucket '610 ASSERT (DOW_DEBUG_CNT ( hb 611 CHECK_HASH_CHAIN(_hbucke 612 DOW_HASHINVAL( ( id) ) ; \ 613 ) 6H Hi Ideflne DOW_DEBUG_FLUSHLEAVE(ld) ( dowld t _t Ihead) \ 616. ASSERT(VALID_DOWID(id)); \ 617 Jl Ihead - DOW_DEBUG_FLUSHID( (id)) ; \ 618 ASSERT(VALID_FLUSHHEAD(_flhead)); \ 619 DOW_DEBUG_FLUSHID((id)) - DOW BADID; \ V? (20 --DOW_DEBUG_CNT(_fIhead); \ § 62t ASSERT(DOW_DEBUG_CNT(_fIhead) >- 0); \ CO 6?2 CHECK_FLOSH_CHAIN(_fIhead); \ —, 633 DOW FLUSHINVAL((ld)); \ ^ tai ) J $26 Ideflne DOW_DEBUG_FRBEENTER(ld) ( \ :£ (jj ASSERT(VALID_DOWID(id)); \ Frj ' 628 ASSERT(DOW_DEBUG_HASHID(id) — DOW BADID) ; \ HI 629 ASSERT(DOW_DEBUG_FLUSHID(id) — DOW_BADΪD); \ ^ _ 630 DOW_DEBUG_HASHID((id)) - DOW FREEHEAD; \ P έjl DOW_DEBUG_FLUSHID((id)) - DOW_FREEHEAD; \ 632 ++DOW_DEBUG_CNT((DOW_FREEHEAD)); \ rπ 633 ASSERT(DOW_DEBUG_CWT(DOW_FREEHEAD) — dow freecount); \ S? . • ^ 651 Ideflne ENPTY_IODONE_LINKAGE(ld) ( (DOW_B_IODONB(ld) — ■ DOW BAD IODONE) tt \ 652 (DOW B IOCHAIN(ld) — DOW BAD IOCHAIN) ) 653 654 lelse 655 Ideflne DOW_DEBUG_HASHENTER( id, hbucket) 656 Ideflne DOW_DEBUG_HASHLEAVE(ld) 657 Ideflne DOW_DEBUG^FLUSHENTER( id , flhead) 658 Ideflne DOW_DEBUG_FLUSHLEAVE(ld) 659 Ideflne DOH_DBBUβ_FREBENTBR( Id) 660 Idefine DOW_DEBUG_FREELEAVB( id) 661 Ideflne DOH_DEBUG_IODONE_INIT(ld) 662 Idefine EMPTY_IODONE_LINKΛGE(id) B TRUB 663 lendlf 664 665 llfdef DEBUG 666 667 Idefine DOWLI K_DEBUG_BNTER( link, head) ( \ 668 ASSERT(VALID_DOWLINK_ID(link)); \ CO 669 ASSERT(VALID_DOWLINK_HEAD(head)); \ j= 670 ASSER ( DOWLI NK_DEBUG_LHEAD( link) — • DOWLI NK_BADID) ; \ CO 671 DOWLINK_DEBUG_LHEAD(link) - head; \ _ 673 ++(DOWLINK_DEBUG_CNT(head)); \ i 673 CHECK_DOWLINK_CHAIN(head); \ ~i 674 1 rπ 675 Idefine DOWLim_DBBUG_LEAVB(llnk) I dowllnkld_t llnkhead; \ ϊ C_vj 676 ASSERT(VALID_DOWLINK_ID(link)); \ f-^ ' 677 llnkhead - DOWLI NK_DEBUG_LHEAD( link) > \ rή 67β ASSERT(VALID_DOWLINK_HEAD(_linkhead)); \ JUj 679 DOWLINK DEBUG LHEAD(llnk) - DOWLI NK BADID; \ Λ 680 --(DOWLINK_DEB0G_CNT(_linkhead)); \ f≡ 681 ASSERT(DOWLINK_DEBUG_CNT(_linkhead) >- 0); \ 682 CHECK_DOWLINK_CHAIN(_linkhead); \ 683 ] 684 685 Ideflne DOWLINK DEBUG FREEENTER(llnk) ( \ 686 ASSERT(VALID_DOWLINK_ID(link)); \ 687 ASSERT(DOWLINK_DEBUG_LHEAD(llnk) — DOWLINK_BADID) ; \ 688 DOWLINK_DEBUG_LHEAD(link) - DOWLI K_FREEHEAD; \ 689 ++(DOWLINK_DEB0G_CMT(DOWLIMK_FREEHEAD)); \ 690 ASSER (DOWLINK DEBUG_CNT(DOWLI K_FREEHEAD) — dowlink freecount); \ 691 I 692 693 Idefine DOWLINK_DEBUG_FREELEAVE(llnk) ( \ 694 ASSERT(VALID_DOWLINK_ID(llnk)); \ 695 ASSERT(DOWLINK_DEBUG_LHEAD(link) — DOWLI NK FREEHEAD ) ; \ 696 DOWLI NK_DEBUG_LHEΛD( link) - DOWLI NK BADID; \ 697 --(DOWLINK_DEBUG_CWT(DOWLINK_FREEHEAD)); \ 698 ASSERT(DOWLINK_DEBUG_CNT(DOWLINK FREEHEAD) — dowllnk_freecount); \ 699 ) 700 701 703 lelse 703 Ideflne DOWLINK_DEBUG_ENTER(llnk, head) 704 Idefine DOWLINK DEBUG EAVE(llnk) 705 Ideflne DOWLI NK_DEBUG_FREEENTER( link) 706 Ideflne DOWLINK_DEBUG_FREELEAVE( link ) 0^ lend if 708 709 710 llfdef DEBUG 711 Ideflne DOW FREE BADINIT(x) dow free badlnlt(x) 712 Ideflne DOW DEBUG INlT(x) dow debug lnlt(x) 713 Ideflne DOWLINK_FREE_BADINIT(x) dowllnk_free_badlnlt(x) 714 Ideflne DOWLINK_DEBUG_INIT(a, b) dowllnk_debug_lnlt(a, b) 715 lelse 716 Ideflne DOW_FREE_BADINIT(x) 717 Ideflne DOW_DEBUG_INIT(x) 718 Idefine D0WLlNK_FREB_BADINIT(x) 719 Ideflne DOWLlNK_DEBUG_INIT(a , b) V- 720 lendlf → 73? llfdef DEBUG ^j 724 Ideflne CHECK_HASHDUP(a, b, c, d) check_hashdup((a), (b), (c) , (d)) m . 725 Ideflne CHECK_HASH_CHAIN(x) check_hash_chaln((x) ) ζj-> . 7'26 Idefine CHECK DOWLINK CHAIN(x) check_dowllnk_chaln( (x) ) j ^ * 737 Idefine CIIECK DOW LINKAGE(x) check_dow_llnkage( (x) ) m ' 72^ Idefine CHECK_ANTECDENTS_PRUNBD(x) check_antecdents_ρruned( (x) ) 729 Ideflne CHECK_FLUSH_CHAIN(x) check_flush_chaln((x)) __D 730 Idefine CHECK HASH(x) check_hash((x) ) 731 Ideflne CHECK_ON_FLUSHCHAIN(x, f Ihead) check_on_fluεhchaln((x), (flhead)) m 732 Ideflne CHECK_NOTON_FLUSHCHAIN(x, flhead) check_noton_flu8hchaln((x), (flhead)) 73J Ideflne CHECK OTON ANY FLUSHCHAIN(x) check_noton_any_f luβhchaln( (x) ) 734 Idefine CHECK_HASH_REMOVED(x) check_hash_removed( (x) ) 35 Ideflne CHECK_DOH_FREELlST() check_dow_freellst() 736 Idefine CHECK_NOTFREE(x) check_notfree((x)) 737 Idefine CHECK DOWLINK FREELIST check_dowllnk_freellεt 738 Idefine DOW_EXlSTS(x, y) dow_exlstβ((x), (y)) 739 Idefine DOW VP ANY ( vp ) dow_vp_any( (vp) ) 740 lelse .741 Ideflne CHECK_HASHDUP(a, b, c, d) 742 Ideflne CHECK HASH CHAIN(x) 743 Ideflne CHECK_DOWLINK_CHAIN(x) 744 Ideflne CHECK_DOW_LINKAGE(x) 745 Ideflne CHECK_ANTECDENTS_PRUNED(x ) 746 Ideflne CHECK_FLUSH_CHAlN(x) 747 Ideflne CHECK HASH(x) 748 Idefine CHECK_ON_FLUSHCHAIN(x, flhead) 749 Ideflne CHECK_N0T0N_FLUSHCHA1N(X, flhead) 750 Ideflne CHECK_N0T0N_ANY_FLUSHCHAIN(x) 751 Ideflne CHECK HASH REMOVED(x) 753 Ideflne CHECK_DOW_FREELIST( ) 753 Ideflne CHECK OTFREE(x) 754 Ideflne CHECK_DOWLINK_FREELlST() 755 Ideflne DOW_EXISTS(x, y) 756 Ideflne DOW VP ANY ( vp ) 757 lendlf 758 759 llfdef DEBUG 760 Idefine DOW HASHINVAL(x) I \ 761 DOW_HAS_ NEXT( (x ) > - DOW BADID; \ 762 DOW_HASHPREV( (x ) ) - DOW_BADID; \ 763 ) 764 Ideflne DOW_FLUSHINVAL(x) f \ 765 DOH_FLOSHNEXT((X)) - DOW BADID; \ 766 DOW_FLUSHPREV((x)) - DOW_BADID; \ 767 ) 768 lelβe Idefine DOW ASHINVAL(x) Ideflne DOT_FUUSHINVAL(x) lendlf llfdef DEBUG extern void dow_free_badlnit(dowid_t); extern void dow_debug_init(dowid_t); extern void dowlink_free_badlnit(dowllnkld_t); extern void dowlln debug init(dowlinkld_t . dowlinkld_t ); extern void check_fluβh_chain(dowid_t ); extern void check_on_fluβhchain(dowid_t , dowid_t ); extern void check_noton_fluβhchain{dowid_t , dowid_t ); extern void check_noton_any_fluβhchain(dowld_t ); extern boolean_t on_some_fluβhchain(dowld_t ); extern boolean_t dow_exlβtβ(long , long ); 787 extern dowid_t dow_vp_any(vnode_t *); 788 extern void check_antecdentβ_pruned(dowid_t ); 789 extern void check_dow_freeliβt(); 790 extern void check_notfree(dowid_t ); 791 extern void check_haβhdup(dowid_t , dowid t , long , long ); 792 extern void check_haβh(dowid_t ); 793 extern void check_haβh_chain(dowid_t ); 794 extern void check_dowlink_chaln(dowlinkld_t); 795 extern void check_dow_linkage(dowlinkid_t); 796 extern void check_dowlink_freellβt(); 797 extern void check_haβh_removed(dowid_t); 798 799 lendlf 800 801 extern buf_t * dow_buf fer(dowid_t) ; 803 extern void dow_bdwrl te (buf_t * ) ; 803 extern Int llnkage_detect(dowid_t , dowld_t ) ; 805 llfdef _1F_NEEDED_ 806 extern void dow_βtart_abort(dowid_t ); 807 extern void dow_flniβh_abort(dowid_t ); 808 lendl f 809 8l6 extern void dow_abort(dowid_t ) ; 811 extern void dow_abort_range(vnode_t *, off_t , int ); 8)2 extern void dow_abort_rele_l(dowid_t ); 813 extern dowid_t dow_alloc_l(vold) ; T)14 extern dowld_t dow_alloc(vold) ; 815 extern dowid_t dow_alloc_l(void) ; 816 extern void dow_arrayinit(void) ; 817 extern void dow_clearmod(dowld_t ); 818 extern dowid_t dow_create_page(vnode_t * , off_t , Int, ulnt_t ) ; 919 extern dowld_t dow create_page_l(vnode_t *, off_t , Int , uint_t ); 820 extern dowid_t dow_create_buf(dev_t , daddr_t , long , uint_t ); 821 extern dowid_t dow_create_func(vold (*)(), void *, ulnt_t , boolean_t ); • 822 extern void dow_flush(dowid_t ); 833 extern void dow_βtart_fluβh_tiroeout(vold) ; 834 extern void dow_fluβh_tlmeout(void) ; 825 extern void dow fluβh daemon( ) ; 83$ extern void dow_fluβh_headina(dowid_t , dowid_t); 827 extern void dow_fluβh_re ove(dowid_t ); 828 extern void dow_ luβh_taillna(dowid_t , dowid_t ); 829 extern "void dow_free(dowid_t ); 830 extern void dow_handle_async(dowld_t ); 831 extern void dσw_handle_aβync_l(dowid_t ); 832 extern void dow_handle_βync(dowid_t ); 833 extern void dow-_handle_aync_l(dowld_t) ; 834 extern void dow_inlt(dowid_t , long , long , uchar_t ); 835 extern void dow_inahaβh(dowid_t , dowid_t ); 836 extern void dow_io_utρ_βetup(buf_t •); 837 extern void dow_io_utp_rele(bu _t *); 838 extern void dow_buf_iodone(buf_t *); 839 extern void dow_page_iodone(buf_t *); 840 extern void dow_untracked_pageio_done(buf ^ t *); 841 extern void dow_iodone(dowid_t ); 842 extern void dow_iodone_inβert(dowld_t , buf_t •, void (*)()); 843 extern void dow_iodone_reβtore(dowid__t , buf_t *); 844 extern void dow_iofluβh(dowld_t ); fl45 extern void dow_lntrans_wait(dowid_t ) ; 846 extern void dow_iowait(dowid_t ); 847 extern void dow_iowalt_l(dowid_t ); 848 extern dowid_t dow_lookup(long , long ); 949 extern dowld_t dow_lookup_page(vnode_t *, o f_t); 850 extern int dow order no_wait(dowid t , dowid t ); 851 extern int dow_order(dowid_t , dowld_t , uint_t ); 853 extern void dow_proceaβ_leaf_func(dowld_t, void (*)(dowld_t)); 853 extern void dow_proceββ_leaf_lodone(dowld_t ); 854 extern boolean_t dowjproceaβ_leaf_ lush(dowld_t ); 855 extern int prune_βearch(dowid_t , int , boolean_t ); 856 extern void prune(dowld_t ); 857 extern void prune_antecdents(dowld_t ); 858'extern void dow_rele(dowld_t ); 859 extern void dow_rele_l(dowid_t ); 860 extern void dow_reπ.haeh(dowld_t ); 861 extern void dow_startmod(dowld_t ); 862 extern void dow_βtartmod_rdlock(dowid_t ); 863 extern void dow_atart_nod_wrlock_l(dowid_t ); 864 extern void dow_drop_modlock_l(dowid_t ); 865 extern void dow_clear_ odlock_l(dowid_t ); 866 extern void dow_set_nod(dowld_t . clock t ); 867 extern void dow_βtrategy_buf(buf_t *); 868 extern void dow_βtrategy_page(buf_t *•, vnode_t *, o _t , int); 869 extern void dowllnk^addlink(dowlinkid_t , dowlinkid t ); 870 extern dowlinkid_t dowlink_aHoc(void); 871 extern void dowlink_arrayinit(void); 872 extern void dowlink_breaklink(dowllnkld_t , dowid_t , dowid_t ); 873 extern void dowlink_free(dowlinkid_t ); 874 extern void dowlink_init(dowlinkid_t , dowlinkid_t , dowid_t ); 875 extern int dowlink_ akelink(dowid_t , do id_t ); 876 extern void dowlink_aublink(dowlinkid_t ); 877 878 lendlf /* _K_*NEI, •/ 879 llf deflned( cpluspluβ) 880 ) 881 lendlf 882 883 lendif /* _PS_DOW_H •/ 1 lldent '@(l)kern- fa/dow cancel c 1.5' 2 fide/it '$Header: $' 3 4 llnclude <fβ/dow.h> 5 llnclude <fβ/fs_hler h> 6 llnclude <io/conf h> 7 llnclude <αιem/kmem . h> 8 llnclude <mem/page.h> 9 llnclude <svc/clock.h> ' 10 llnclude <utll/c n_err.h> ■ 11 finclude <utll/debug Jι> 12 llnclude <utll/ghler.h> 13 linclude <utiJ/flysmacros_/.h> • 14 linclude <utll/var h> is */ 49 1 50 DOW MOTEX UNLOCIt ( ) ; 51 52 53 54 void 55 dow_abort_rele_l(dowid_t id) 56 Abort the apecified dow atructure. Walt for any outatanding 57 10 to complete, and then wark the atructure aβ unaiodified and 58 "gone". If there are no antecdenta, then aiwulate the 59 completion of 10 on thia dow; otherwiae, wait until the io-done 60 proceaaing la performed on thia dow after all lta antecdenta 61 have been handled. 62 if ll 91 92 we wuβt wait for any 10 that haa been atarted on the 93 dow, to coarplete; thia lncludea DOW_IHTRAN__ and DOW_IOSETUP 94 caaea. 95 96 Otherwiae, if 10 ia not ongoing or iuinent, we have to 97 wait until all antecedenta coaplete before returning frow 98 thia function. To enaure that thia happena promptly, we 99 prune the id, if it ia not already pruned. 100 101 102 if (DOW STATE(id) t (DOW FLUSHINTRANS | DOW IOSETUP) ) ( L03 IC4 If (DOW STATE(id) t DOW FLUSH) { 105 DOW MOTEX UNLOCK ( ) ; 106 LBOLT_WAIT( PRIBUF) ; 107 ) else { 108 do lo ait l(id); 109 J L10 DOW_MUTEX_L0CI. ( ) ; Lll goto etart_over; iia L13 114 ASSERT((DOW_STATE(id) t (D0W_G0NE|D0W_FLUSHINTRANS |DOW lOSETUP)) 0); 115 L16 L17 fluah denon inhexltβ the reβponaibility of calling dow Lodone L18 * if thia dow haa antecedenta. function abort ahould iaplr the abaolute L19 * diβaantllng of the function aetup ltaelf (and ahould therefore be Lao * βynchronoua) . 121 L23 12) if ((DOW YPE(id) t DOW_ISFUNC) tt (DOW STATE(id) t DOW_MODIFIED)) ( 124 if (DOW ANT CNT(id) > 0) ( 135 prune(id),• 126 do _io ait_l(id) ; CO 127 DOW MUTEX LOCKO; 128 I L29 JO * Can we be certain aa to which fluβh chain thia id could 131 * be on, baaed on lta DOW_STATE? If βo, way be nice to ϋ L32 * verify tinder DEBUG that DOW_DE__UG_r__USHID natchea it. 133 V L34 do _fluβh_remove(ld) ; 23 L35 dow_remhaβh(ld); L36 DOW STATE(id) - (DOW_G0NE|DOW_PRUNE|DOW_INTRANS); 137 DOW TIMESTAMP(id) - INT_MAX; 138 dow_iodone(id); 139 dow_rele_l(id); 140 return; 141 142 143 if (DOW ANT CNT(ld) 0) ( 144 prune(id) ; 145 /* 146 * before we unhaah, we need to ensure that no-one ataya 147 * blocked on the aodlockl β */ 149 If (DOW TYPE(ld) —• DOW ISPAGE) { 150 dow_clear_modlock_l(id) ; 151 1 152 dow_rernhash(i ); 153 DOW STATE(id) - (D0W_G0NE|D0W_PRUNE); 154 /• 155 * Since we juβt cleared the HOD atate, it ia 156 • aafe aa well to reaet the tiaeetaap. 157 V 158 DOW TIMESTAMP(id) - 1NT MAX; 159 160 161 we are leaving upto dow_iodone the job of removing thia id 162 froa ita haah chain ao that dow_lookupa cannot find it after 163 that point. 164 165 on aecond though, it aeeaa advantageous to do it right 166 now, aince it ia unclear why we need to guarantee that 167 lookupa can find thia id after thia point. 168 but, rOX NOW, let ua atick with the policy of letting dow_iodone perfora the haah reaoval for aborted dowida. Thia haa two advantageai (1) it will be poβaible to catch error(a) if a DOW_GONE id coaeβ through dow_iodone wore than once, (2) auch of the other code ia written to the aββuaption that dow_iodonβ will be reaponaible for unhaahing (though that can change, when we want to follow the new policy). 33 180 Thia iβ a special caaes we cannot eaploy either 181 of dow_lntranβ_wait OS dow_iowait_l in order to 182 wait for a aignal froa thia id, aince in thia caae 183 we juat want to wait until the upward filtering of 184 IO coapletiona finally reachea thia dow. iowalt ia 185 deaigned only to wait ao long aa the "current" Modification 186 haa not been flushed out -- and here there ia no auch 187 aodification to fluβh. 201 dow_ luβh_remove(ld) ; 202 /• 203 * before we unhaβh, we need to enaure that no-one ataya 204 * blocked on the aodlockl 205 •/ 206 If (DOW TYPE(id) —■ DOW ISPAGE) ( 107 dow_clear_modlock_l(id) ; 208 ) 209 dow_remhaβh(id); 210 DOW STATE(ld) - (DOW_GONE|DOW_PRUNE|DOW_INTRANS); 211 DOW_TIMESTAMP(id) - INT_MAX; 212 dow_iodone(id); 213 CHECK_HASH_REMOVED(id) ; 214 ASSER (DOW_DEP_CNT(id) —• 0); 215 316 dow rele l(id); 217 return; 218 219 OP 220 221 void - 222 dow_abort(dowid_t id) C. —I 223 Abort the apecified dow atructure. Wait for any outatanding 224 10 to coaplete, and then aark the atructure aβ unaodified and ci 225 "gone". If there are no antecdenta, then aiarulate the rJ 226 coapletlon of 10 on thia dow; otherwiae, wait until the io-done 227 proceaalng ia perforaed on thia dow after all ita antecdenta 228 ' have been handled. 229 230 Calling/Exit State: 231 dow_autez not held by caller; acquired within, and releaaed ro 232 before return. The function can block, ao the caller nuat 233 < not hold any locka. 234 */ 235 236 void 237 8__^i^*«_^«<.-.i< .f v S8| ' 238 ( 239 ASSERT ( KS HOLDOLOCKS ( ) ) ; 240 ASSERT(getpl ( ) — PLBASE) ; 241 if ( IVALID_DOWID( id) ) 242 return; 243 244 βtart_over : 245 246 DOW_HUTEX_LOCK ( ) ; 247 ASSERT(DOW_ROLD( id) > 0 ) ; 248 ASSERT( (DOW_STATE( id) S DOW GONE) — 0 ) ; 249 /* 250 * dow_abort auat be called only for thoae Ida that are 251 * currently possessing identity. Before returning, this 252 * identity will be destroyed (the hold only preβerveβ 253 * the dow structure, not its hash identity. It ia aaauaed 254 • that the caller has followed aoae algoritha to enaure 255 * that concurrent calls to dow_abort would not be aade for 256 * the aaae dowid. 257- 258 CHECK_HASH(id); 259 260 /• 261 * we auβt wait for any IO that haa been atarted on the 262 * dow, to coaplete; thia includea DOW_INTRANS and DOW_IOS__TUP 263 * caβea. 264 •/ 265 266 If (DOW STATE(id) t (DOW FLUSHINT ANS | DOW IOSETUP)) ( 267 260 if (DOW STATE(ld) t DOW FLUSH) { 369 DOW_MUTEX_UNI_OCK(); 270 LB0LT_WA1T(PRIBUF); 271 ) else ( 272 dow_iowait_l(ld); 273 ) 274 275 goto βtart_over; 276 ] 277 378 ASSERT( (DOW_STATE(id) -_ (DOW_GONE|DOW_FIuSHI TRANS |DOW_IOSETUP) ) — 0) ; 279 • g 280 /* ? 381 * fluah deaon inheritβ the rββponβibility of calling dow_iodone j ϊ 282 * if thia dow haa antecedenta. function abort ahould iaply the abaolute 283 * disaantllng of the function setup itaelf (and ahould therefore be an 384 * synchronous). ~~~^ 285 •/ 286 287 if ((DOW_TΪPE(id) C DOW_ISFUNC) -l (DOW STATE(id) t DOW_MODIFlED)) { 388 if (DOW_ANT_CNT(id) > 0) ( 289 prune(id); 390 dow lowait_l(i ); 391 DOW_M0TEX_L0CK(); 393 I 393 /* 394 * Can we be certain aa to which flush chain thia id could 395 • be on, baaed on ita DOW_STATE? If ao, way be nice to 396 * verify under DEBUG that D0W_DE_.UG_FLUSHID Batches it. 397 •/ 398 dow_fluβh_remove ( id) ; 399 dow_re_nhaah( id) ; 300 DOW STATE( ld) - (DOW_GONE |DOW_PRUNE |DOW_INTRANS) ; 301 DOW TlMESTAMP(ld) - INT_MAX; 303 dow lodone(ld); 303 CHECK_HASH_REMOVED(id); 304 DOW HUTEX UNLOCK(); 305 return; 306 ) ■ 307 iOff if (DOW ANT CNT(id) > 0) ( 309 prune(ld); 310 /* 311 * before we unhaβh, we need to enaure that no-one ataya 313 • blocked on the aodlockl 313 •/ 314 if (DOW TYPE(id) -- DOW ISPAGE) ( 315 dow_clear_modlock_l(id) ; βlβ ) 317 do remhaeh( ld) ; 318 DOW STATE( ld) - (DOW_GONE |DOW PRUNE) ; g 319 /• ~ CD 330 * Thia ia a apecial caaei we cannot eaploy either __} - 331 * of dow_intrana_wait OR dow_lowait_l in order to ~__j 333 * wait for a aignal froa thia id, aince in this caae CZ 323 * we juet want to wait until the upward filtering of r-rj 334 " * 10 coapletiona finally reachee thia dow. iowait ia ff) 33$ * deaigned only to wait ao long aa the "current" Modification -J-. ) 326 * haa not been fluahed out — and here there ia no euch rr i « 337 * Modification to fluβh. -328 V 339 DOW SV WAIT(id); 330 llfdef DEBUG 331 DOW_MUTEX_LOCK ( ) ; 333 ASSERT (DOW_H0LD( id) > 0 ) ; Cn 333 ASSERT (DOW_DEP_CNT( id) — 0 ) ; ' 334 ASSERT (DOW_ANT_CNT ( id) — 0 ) ; 335 DOW_MUTEX_UNLOCK ( ) ; 336 lendlf 337 return ; 338 ) else ( 3i9 340 /* 341 * Can we be certain aa to which fluβh chain thia id could 343 * be on, baaed on ita DOW_STATE? If ao, nay be nice to 343 * verify under DEBUG that DOW_DEUG_FLUSHID natchea it. 344 •/ 345 346 dow_fluβh_remove(ld) ; 347 /. 348 * before we unhaβh, we need to enaure that no-one βtayβ 349 * blocked on the aodlockl 350 */ 351 if (DOW TYPE(id) —■ DOW ISPAGE) ( 353 dow_clear_modlock_l(id); 353 1 354 dow remhaβh(id); 355 DOW STATE(id) - (DOW_GONE|DOW_PRUNE|DOW_INTRANS); 35β DOW TIMESTAMP(id) - INT_MAX; 357 dow iodone(id); 358 ASSERT(DOW_DEP_CNT(Id) — 0); 359 DOW_MUTEX_UNL0CK(); 360 return; 361 ) 363 ) 363 ► 364 /• 365 • rold it for the intrana operation ia ia acquired and 394 ) 395 396 if (DOW_STATE(id) t (DOW FLUSHINTRANS | DOW IOSETUP) ) { 397 if (DOW_STATE(id) C DOW FLUSH) ( 398 DOW_MUTEX_UNLOCI.(); 399 LBOLT_WAIT( PRIBUF); 400 ) else ( 406 ASSERT((DOW STATE(id) t DOW GONE) — ■ 0); .01 /* 408 * handling function dowat 409 • 410 * what to do with function done? nothing special needed, ' 411 * becauaei IP antecdent count > Oi 415 * dow_p-.oceaa_leaf__.u-_c will handle a function dow 416 * that doea not have ita MODIFIED βtate aet, in one of two 41? * waya depending in whether hold ia 0 or not; if hold count ' 418 * la 0, then the dow will be freed. Otherwiae it will be tV - 419 ' * queued onto the aged liat ao that whenever the laat rele < 450 * occurβ, dow_rele will know to free the dow. (dow_rele '_! 421 * handlea function dowa differently in thia way). C _3Z 44*323 • ELSE, we will call dow_iodone here itself? cn « 425 DOW STATE(id) «- -D0W H0DIFIED; 'f, 426 if (DOW_ANT_CNT(id) -- 0) ( rπ - 7 if ( (DOW_DEP_CNT(id) > 0) || _| 428 ((DOW TYPE(id) t DOW ISFUNC) — 0)) ( 429 /• ( — 430 * Can we be certain aa to which flush chain r^ 431 * thia id could be on, baaed on ita DOW_STATE? If .432 * ao, nay be nice to verify under DEBUG that ro en 433 * D0W_DEUG_FLUSHID Batches it. 434 • DOW_AGED_FLUSHHEAD, perhaps? 435 */ 436 dow_f1U8h_remove(id) ; 437 DOW STATE(id) |- DOW INTRANS; 4_)8 DOW TIMESTAMP(id) - INT MAX; 439 ASSERT ( (DOW_STATE( id) C (D0W_FLUSH |D0W_M0DIFIED| 4 .0 DOW IOSETUP ) ) — 0 ) ; 441 dσw_iodone ( id) ; 442 ) 443 ) 444 DOW HUTEX DNLOCKO ; 445 return; 44* ) 1 lident '@(l)kern:fs/dow_check.c 1.3" 3 lldent *$Header: $' 3 4 llnclude <fa/dow.h> 5 llnclude <fa/fe_hler.h> 6 llnclude <lo/conf .h> 7 llnclude <mem/kmem . h> 8' linclude <meπι/page . h> 9 llnclude <svc/clock.h> 10 linclude <utll/cmn_err.h> 11 llnclude <utll/debug.h> 12 linclude <util/?hier. Jι> 13 llnclude <utll/syB acroa_f.h> i4 llnclude <utll/var.h> 15 16 llfdef DEBUG 17 18 /* ) id are pruned. ^ 34 link - ant lhead - DOWLINK_ANT LINKHEAD(id) ; ^ 35 36 ASSERT(VALID_DOWLINK_BEAD(link) ) ; 37 ASSERT(DOWLlNK_LINKS_SANE(link)); 38 39 while ((link - DOWLINK NEXT(llnk)) I- ant lhead) ( 40 ASSERT(VALID_DOWLINK_ID(llnk)); 41 ant_id - DOWLINK_DOWID(link); 42 ASSERT(VALID_DOwTD(ant_id)); 43 ASSERT(DOW_STATE(ant_id) t (DOW_PRUNE|DOW_INTRANS) ) ; «« 1 45 return; 46 ) 47 48 /* 49 « void 50 • check_flueh_chain(dowid_t f luah_header) 51 Debugging support to verify that indicated fluah chain • 53 (headed by "fluβh_header") ia βane and has the right S3 number of itens on it. 54 55 Calling/Exit Statei 56 dow___Λitex ia held by caller. '57 58 59 void 60 .61 i ' 62 int count - 0; -S3 uchar_t prune_βtate - 0; .64 dowld t Id; 65 . _66 ASSERT(DOW_MUTEX_OWNED( )) ; ' 67 . eβ ASSERT(. (fluβh header -- DOW LEAF FLUSHHEAD) || 69 (flush ieader -- DOW PRUN FLUSHHEAD) || "70 (fluβh header ~ DOW_AGED_FLUSHHEAD) ); "71 ■ 72 count - DOW_DEBUG_CNT( luβh_header); .73 74 If (fluβh_header I- DOW_AGED_FLUSHHEAD) [ 75 prune βtate - DOW PRUNE; . 76 ) 71 m I 78 for (id - DOW_FLUSHNEXT(flush_header) ; id t- fluβh_header; 79 id - DOW FLUSHNEXT(id)) ( 80 ASSERT( (--count) >- 0); __0 81 ASSERT(DOW_FLUSHLINKS_SANE(Id) ) ; £ 82 ASSERT((DOW_STATE(id) t DOW PRUNE) — prune βtate) ; rπ≡ ' 83 ASSERT(DOW_DEBUG_FLUSHlD(id) -- flush_header) ; > en .84 1 "85 ASSERT(count -- 0); ' * 86 ) 87 -88 /• 89 * void '90 * check_on_fluahchain(dowid_t x, dowid_t fluah_header) . " . 1 101 dowld t id; 103 103 ΛSSERT ( ( f luβhjieader — DOW_LEΛF_FLUSHHEAD) | | 104 ( f luβh_header — DOW PRUN FLUSHHEAD) I I 105 ( f luβh_header — DOW_AGED_FLUSHHEAD) ) ; 106 107 if (fluβh_header — DOW_AGED_FLUSHHEAD) ( 108 ASSERT((DOW STATE(x) 4 DOW PRUNE) — 0); 109 I else ( 110 ASSERT( (DOW STATE(x) t DOW_PRUNE) I - 0 ) ; Ul I 112 ASSERT(DOW_DEBUG_FLUSHID(x) -- luβhjieader) ; 113 for ( id - DOW_FLUSHNEXT( flueh_header) ; id I - flushjieader; 114 id - DOW FLUSHNEXT(id)) ( 115 ASSERT(VΛLID_DOWID(id)); 116 if (id -- x) { 117 return; 118 ] 119 ) g? 130 /* £ j 131 *+ a dow atructure waa not found on the proper fluβh chain. CO 122 *+ kernel software error. C. 134 if (fluβh_header -- DOW_LEAF_FLUSHHEAD) t → • 125 cmn_err(CE_PANIC, « g 126 "dowid %d not found on leaf fluβh ehaln\n*, x); _C i 127 ) else if (flush header — DOW_PRUN_FLUSHHEAD) { m 128 cmn_err(CE_PANIC, __J 129 "dowid %d not found on pruned flush chain\n", x); ^-A 130 ) else ( ^ 131 cmn_err(CE_PANIC, m 132 'dowid d not found on aged fluβh chaln\n", x); 133 J -~* 135 ) 136 137 /• 138 • void 139 • check_noton_fluβhchain(dowld_t fluβh_header, dowid t x) 140 * Debugging βupport to verify that indicated dow, x, ia not on 141 • the apecified fluβh chain (headed by "flushjieader"). 142 • 150 dowld t id; 151 152 ASSERT( ( f luβhjieader ~ DOW LEAFJ'LUSHHEAD) I I 153 (fluβhjieader -- ■ DO >RUN_FLUSHHEAD) || 154 ( luβhjieader — DOW_AGED_FLUSHHEAD) )> 155 156 ASSERT(DOW_DEBUG_FLUSHID(x) I- fluβhjieader); 157 159 for (Id - DOW_FLUSHNEXT(fluβh header); id I- fluehjieader; 159 id - DOW FLUSHNEXT(id)) { 160 ASSERT(id I- κ); 161 ) 163 ) 163 ) t Indicated dow, i, ia not on DOW BADID) ; the fluβh chains, falβe otherwiae. 191 dowid_t fh; 192 193 fh - DOW DEBUG FLUSHID(id). 194 195 if ((fh — DOW AGED FLUSHHEAD) I I 196 (fh — DOW PRUN FLUSHHEAD) II 197 (fh — DOW_LEAF_FLUSHHEAD)) I 198 CHECK_ON_FLUSHCHAIN(id, fh); 199 return (B_TRUE); aσo ) 201 202 ASSERT( IVALID_D0WlD(f ) ) i 203 ιeturn(B_FALSE); 204 205 306 307 boolean_t 208 dow_exiβtβ(long identl, long ident2) 309 Return B_T1UE if the dow of the βpecified identity exiβta, 210 B_FALSE otherwiae. 211 212 Calling/Exit Statet 213 Hone. 214 215 Reaiar a1 216 Anβwβr atale unleβa higher level aeriallzation enβureβ 217 otherwiae. , ident2); ; βhid) ( tl) tt (DOW_lDENT2(i) — ldeιιt2)) ( i) C DOW GONE) — 0); 237 DOW MUTEX JNLOCK ( ) J 238 return (retval ) ; 239 340 241 242 /* 243 * dowid_t 244 * dow_vp_an ( node_t *rp) 245 * Return a dowid if the dow haβ a page identity in the βpecified vp. 246 • Return DOW_BADID otherwiβe. 247 • 248 • Calling/Exit State 1 249 • None . 250 251 * Senarkai .25 • Answer atale unleaβ higher level aerlallzation enβurea 2 « .3 • otherwiβe. NO HOLD IS PLACED ON SETUSNED id. 154 255 dowid t 25β foXBj $t* odύJi.'*rbl 357 ( 238 dowld_t haβhid; 259 dowld_t id; 260 261 DOW HUTEX LOCK( ) ; 2 _I 263 for (haβhid - DOW_TABLE_SIZE; 264 haβhid < (DOW TABLE SIZE + DOW_HASHWIDTH); haβhid++) ( 265 366 ASSERT(DOW_HASHLINKS_SANE(haahid) ) ; 267 for (id - DOW HASHNEXT(haβhid) ; id I- haβhid; 268 id - DOW HASHNEXT(id)) ( 269 C£i 270 if ((DOW IDENTl(id) -- (long)vp) tt t 2 l (DOW TYPE(id) -- DOW_ISPAGE)) [ ζj j 272 DOW_M0TEX_0NL0CK ( ) ; _Ti 273 return(id); → 274. ) → 3li ) 276 ) 277 DOW_MUTEX_ϋNLOCK( ); 27Θ return (DOW BADID); 279 ) 280 281 282 299 if ((DOW lDENTl(ld) — (long)vp) tt 300 (DOW_TYPE(ld) — DOW ISPAGE) tt 301 (DOW_IDENT2(id) >- offβet)) ( 302 DOW SPARE(id) - marker; 303 304 30S 306 DOW HUTEX ONLOCK( ); 307 return; 308 312 l iiif^^ii^ ' ^^ ^^^' v^ ^^ 313 dowid_t haβhid; 314 dowld t id; 318 CD —4 —I m d); id); 332 call_demon(); 333 ) 334 1 335 336 DOW_HUTEX_ONL0CK()|- 337 return; 338 ) 339 '340 lendlf 341 342 /* 347 • Calling/Exit Statet 348 • DOW Butex held by caller. 349 350 400 for (y - DOW HASHNEXT(hb); y I- hb; y - DOW HASHNEXT(y)) { 401 if (y - x) I 402 ASSERT(count — 0); 403 ++count; 404 ) else I 405 ASSERT((11 I- (long)DOW_IDENTl(y)) || 406 (12 I- (long)DOW_lDENT2(y)))i 407 408 I 409 ASSERT(count — l)j 410 411 413 413 • void 41 • check_haah(dowid_t id) 41S • Verify that id ia on the correct haah chain. 416 • 417 • Calling/Exit State i 418 • DOW arutex held by caller. 419 •/ £ 420 void 421 % ' 422 I 423 dowid_t hbucket; 424 hbucket - DOW_HASHBUCKET(DOW_IDENTl(ld), DOW_IDENT2(id) ); 425 ASSERT(DOW_DEBUG__ASHID(id) — hbucket); 426 ASSERT((DOW_STATE(id) t DOW GONE) -- 0); 427 CHECK_HASHDUP(id, hbucket, DOW_IDENTl(id), DOW_lDENT2(ld)); 428 I 429 430 431 void 433 check_haβh_chaln(do id_t hb) 433 Verify that the haah chain at bucket hb la conaiatent. 434 435 Calling/Exit State■ 436 DOW Biitex held by caller. 437 438 r of iteaa and verify that they nka, Batch 447 448 449 do id_t x; 450 int count - 0; 451 ASSERT(DOW_HASHLINKS_SANE(hb)); 452 for (x - DOW HASHNEXT(hb); x !- hb ; x - DOW HASHNEXT(x) ) ( «fS3 ASSERT(DOW_HΛSHLINKS_SANE(X)); 454 ++count; 455 ASSERT(count <- DOW DEBUG CN (hb)); 456 ASSER ((DOW STATE(X) t DOW GONE) — 0); 457 1 ASSERT(DOW_DEBUG_HASHID(X) " hb); 458 ) 459 ASSERT(count — DOW DEBϋG CNT(hb) ) ; 460 ) 461 462 /* 463 * void 464 * check_haah_reaoved(dowid_t x) 4SS * Verify that dowid x haa been unhaahed. 466 • D); turea anchored at hd; link - DOWLINK NEXT(link)) { )); CNT(hd) ) ; 498 J 499 ASSERT(count — DOWLI NK_DEBOG_CWT ( hd )) ; 500 J 504 check_dow_llnkagβ(dowlinkid_t βy_link) 505 Verify that the reciprocal linkage between "ay__link" and the 506 inverae thereof ia correct. For a link that, for exaaple, 507- encodea the dependence (X --> Y), the inverae link would 508 encode the antecdentce (X <-- X). Thia function verifiea that 509 each link correctly identifiea both ita own dow atructure and 510 the dow atructure with which the dependence/antecdence 511 relationship. 513 513 Calling/Exit Statet 514 Caller holda dow autβx. 51S 516 517 void 516 519 I 520 dowid_t my_dow, other_dow; 521 dowllnkld_t inv_llnk; t 522 523 ASSERT(DOWLINK_ILINK_SANE(uιy_link)); 524 -H \ 525 inv_link - DOWLINI._INVERSE(my_link); _D 526 my_dow - DOWLINK_DEBϋG_MΪDOW(my_llnk); se -__ l 527 other_dow - D0WLINK_DEBUG_HYD0w7inv_link); ) 528 529 ASSERT(my dow —■ DOWLINK_DOWID(inv_llnk)); 530 ASSERT(other_dow — DOWLINK_DOWID(πy_link)); _0 531 I 533 533 ro 534 • void 535 • check_dowllnk_ reellβt() 536 • Verify that the llat of free dowlink atructureβ ia conalatent. 537 * 538 • Calling Exit Statet 539 • Dow autex held by caller. 540 DOWLI NK FREEHEAD; 546 int count - 0; 547 548 ASS ER ( DOWLI NK LI NKS SANE ( X ) ) ; 549 550 whi le ( (X - DOWLINK NEXT (X ) ) I - DOWLI NK_FREEHEAD) ( 55i ASSERT(DOWLINK_DEBUG_LHEAD(x) — DOWLINK_FREEHEAD) I 552 ASSERT(DOWLINK_PREV(DOWLINK_NEXT(x)) — X); 553 ++count; 554 ASSER (count <- dσwliπk_ reecount) ; 555 556 ASSERT(DOWLINK_PREV(DOWLI K NEXT(x)) x); 55? ASSERT(count -- dowlink_freecount) ; 558 559 560 563 print_dow(dowld_t 1) 564 Debugging support routine, expected to be called froa the kernel 565 debugger ( DB), to print the varioua fields In the indicated 566 dow atructure. Alβo printa the antecdent and dependent link 8*7 chaina. Hating the linkid, next-linkid, and the dowid of the 568 connected antecdent or dependent dowa. 596 debug_printf( ■ "); 597 if (DOW STATE(i) 6 DOW IOSETOP) 598 debug_printf("I"); 599 else 600 debug j >rintf(" "); 601 if (DOW STATE(i) t DOW FLUSH) 603 debug_printf ("F"); 603 else 604 debug_printf (" • ) ; 605 if (DOW STATE(i) t DOW INTRANS) 606 debug_printf ("W"); 607 elae 608 debug_printf ( " ■ ) ; 609 if (DOW STATE(i) t DOW MODIFIED) 610 debug_printf ("M"); 611 elae chain: ", 636 elβe if (DOW_DEBOG_FLOSHID(i) — D0W_PRUN_FL0SHHEAD) ( 637 debug_printf("prun "); 638 ) 639 else if (DOW_DE_JOG_FLOSHID(i) — DOW_AGED_FLUSBHEAD) ( 640 debug_printf("aged "); 641 I 642 else if (DOW_DEBUG_FLϋSHID( I) — DOW FREEHEAD) [ 643 debug_printf ("free "); 644 ) 645 else if (DOW_DEBUG_FL0S__ID(i) — DOW BADID) ( 646 debug_printf ("none? "); 647 ) 648 else ( 649 debug_prlntf ("???? ")ι 650 1 651 debug_printf("\n\n"); S52 653 link - headlink - D0WLINK_ANT_LINKHEAD(1); 654 debug_printf("antecdentβ llβt (curr/next/dow DLH): »6d %6d 6d %6d\n*, 555 link, 656 DOWLINK NEXT( l ink ) , 657 DOWLINK_D0WID( llnk) , 658 DOWLINK_DEBUG_LHEAD( llnk ) ) ; 659 while ((link - DOWLINK_NEXT(1ink)) r- headlink) ( 560 debug_print (" %6d %6d %6d %6d\n", 661. link, 662 DOWLINK_NEXT(link), j}63 DOWLINK_DOWID(link), 664 DOWLINK_DEBUG_LHEAD(link)); 665 ) 866 debug_printf("\n"); 667 U 668 link - headlink - DOWLINK_DEP_LINKHEAD(i); j i j 669 debug_printf("dependent list (curr/next/dow/DLH): %6d %6d %6d %6d\n*, ζn 570 link, ____ 671 DOWLINK_NEXT(link), ^ 672 DOWLINK_DOWID(link), —I 673 DOWLINK_DEBOG_LHEAD(link)); m , B7 while ((link - DOWLINK_NEXT(link)) I- headlink) ( 5 ~ 7 * 075 debug_printf(" *6d %6d %6d %6d\n", m 0 676 link, " " J ' 677 DOWLINK NEXT(link), 678 DOWLINK_DOWID(link), j l 679 DOWLINK_DEBOG_LHEAD(link)); ,'= 680 1 rrl 681 debug_printf("\n\n"); £? 683 -2 i 83 $84 ) 685 686 /• 687 * roid 688 • find_do_r(lo__g Identl, long ident2) 689 • rind the haahbucket with the provided haah identity flelda, 690 * and print the haahbucket and the dowid (if found on the haah 691 • chain). $93 • Calling/Exit Statet t\9$ " None. 6^4 V 695 void 696 *£ £ *i.(iσι* id^ti, Ibtog id*_rt.J) 697 ( 698 dowid_t hb - DOW HASHBUCKETJidentl, identJ); 69§ dowid t i; 700 01 debug arlntf ("f lnd_dow: hashbucket - %d\t", hb); . 02 for (i - DOW HASHNEXT(hb); 1 I- hb; 1 - DOW HASHNEXT(i) ) ( 703 If (DOW_IDENTl(i) « identl tt D0W_1DENT2(1) — ident2) ( 704 debugjprlntf ("dowid - »d\n", l)j 705 return; 706 ) 707 1 708' debug_printf("\n"); 709 710 J 711 713 lendlf ≤ 2 CO X 16 17 do id_t 18 dow_create_buf(dev_t dev, daddτ t blkno, long baize, uint_t flag) 19 Lookup the apecified <deτ, blkno> to find an associated dow, <.o , 20 if one eziata, and return it held. If a dow does not eziat, 21 create one. Return with a hold on the dow. flag apecifiea 22 whether blocking ia permitted for dow atructureβ. 3 24 Calling/Exit StateI 25 Caller does not hold dow___ute_ . Even if the flag apecifiea no wait, 26 the caller ia not expected to call thia function on an Interrupt t o o 27 path or while holding other locks; while this is not a retireme t J r I 28 for this functionality, it ia implied in the current implementation 29 (because DOW_MUT__X_L0CK( ) and DOH_MϋTEX_tmi.0CK( ) assmae that the 30 caller was at baaepl. 31 32 Remarksi m 33 34 PERFi 35 He could acquire the dow_mutez inaide the function and releaae 36 it before returning. It iβ a performance iasue whether we can 37 hope to cover several calls to dow_interface with one lock 38 round trip. 39 / 40 41 llfdef DEBUG 42 /* teaαvβ after funca are tested */ 46 dowid_t 47 ^oir ϊea * Hu__(iev -fc ' άβv aάΛi_ l fel-tno, i* iϊizi, 'uiάέ fe Utiiji 48 ( ~ ~ 49 dowld t id) 50 dowid_t haahbucket; 51 52 ASSERT ( S_HOLD0LOCKS()); 53 ASSERT (getplO — PLBASE); 54 55 DOW MUTEX OCK ( ) ; 56 57 while ((id - dow_lookup(dev, blkno)) — (dowld_t)DOW_BADID) t 58 59 if ((id - dow alloc lO) — DOW BADID) [ 60 if (flag t (DOW_NO_WAIT | DOW_NO_RESWAIT) ) { 61 DOH_MUTEX_ONLOCK ( ) ; 62 return (DOW BADID); 64 DOW_FREE_SV_WAIT ( ) ; 65 DOW_M0TE_._LOCK ( ) ; 66 continue; 67 ) 68 ) 69 70 ASSER (VALID_DOWID( id)); 71 do _init(ld, (long) dev, (long)blkno, DOW_ISBUFFER)ι % 73 DOW_CHEAP_HOLD(id); r_j 73 DOW BSIZE(ld) - bβize; Cl 74 DOW_BP(ld) - NOLL; ^ I " 0 77 haahbucket - DOW_HASHBUC_.ET(dev, blkno); " ^ 7β dow_lnβhash(id, haβhbucket); —I 79 dow_fluβh_taillnβ(id, DOH_AGED_FLOSHHEAD|; g 80 C 81 CHECK_HASHDOP(id, haahbucket, dev, blkno); f^j 82 DOH_MUTEX_ONLOCK(); ro 83 return(id); 3 84 ) 85 86 /« 87 * Succβaaful lookup. There ia no need to wait for INTXJUIS or 88 * HOD atatea to clear. Not* that dow_lookup() created a hold on 89 * Id before returning it to ua. 90 •/ 91 llfdef DEBUG 92 ASSERT(VALID_DOWID(id))> 93 ASSERT(DOW_TrPE(id) — DOW ISBUFFER); 94 ASSERT(DON_BSIZE(id) " bβize); 95 haβhbucket - DOH_HASHBUCKET(dev, blkno); 96 CHECK_HASHDOP(id, haahbucket, dev, blkno); 97 lendlf .98 D0W_H0TEX_0ML0CK(); 99 return(id); 100 I 101 102 dowid_t J03 dow_create_fu__ctlo__(void (*func)(), void *argp, uint_t flag, 104 boolean_t func_can_block) 105 106 Lookup the apecified <func, argp> to find an aaaociated dow; 107 if one exiβta, and return it held. If a dow doea not eziat, 108 create one. Return with a hold on the dow. flag apecifiea 109 whether blocking ia permitted for dow structures. 110 111 func_can_blockι B_FAI.SE if it ia known that the function ia 112 a non-blocking function in all invocationβ; B_TRUE otherwiae. 113 114 Calling Exit Statei 115 Caller doea not hold dow_autex. It say be acquired, and releaaed 116 and reacquired if allocation ia a blocking allocation. The Butex 117 will be dropped before return. 118 119 Eventhough the caller may specify non-blocking allocation, it will 120 be aaβujaed that the caller ia at plbaae. (convenience). 121 ς_> 122 Reaarka■ 123 124 PERT: I2S We could acquire the dowjautez inaide the function and releaae o 126 it before returning. It ia a performance iaaue whether we can CO -C U7 hope to cover aeveral calla to dow_lnterface with one lock 128 round trip. 12$ / 130 ____; 131 dowid t 132 m 13 boolean_t func_can_block) 134 ( JUS dowid t id; 136 dowld t haahbucket; 1J7 3.39 DOW MUTEX_ 0CK() ; 139 140 while ((id - dow_lookup( (long)func, (long)argp)) — (dowld_t)DOW_BADID) ( 141 142 i f ( ( id - dow_alloc_l ( ) ) ~ DOW BADID) ( 143 i f ( f lag t ( DOW_M0_WAIT | DOW NO RESWAIT ) ) I 144 DOW MUTEX UMJOCK ( ) ; 145 return (DOW BADID) ; 150 1 151 1 152 153 ASSERT(VALID_DOWID(id)); 154 dow lnlt(ld, (long)func, (long)argp, 155 (func_can_block ? DOW ISFONC D0W_ISF0NC_HBLK))j 156 DOW CHEAP HOLD(id); 157 DOW BP(id) - NULL; 158 159 haahbucket - DOW_HASHBUCKET((long) unc, (long)argp); 160 dow_ioe_ιaah(id, haβhbucket); 161 dow fluah_tallinβ(id, DOW_ΛGED_F _SHHEAD); 162 CHECK_HASHDUP(id, haahbucket, (long)func, (long)argp); 163 D0W_M0TEX_0NL0CK(); 164 llfdef DEBUG 165 ++func_creat»; 166 lendlf 167 retu n(id); 168 1 169 3 170 171 • Succesaful lookup. There ia no need to wait for INTRΛMS ox 173 • MOD atatea to clear. Mote that dow_lookup() created a hold on 173 • id before returning it to ua. •174 V 175 llfdef DEBUG 176 ASSERT(VALID_DOWID(id)); 177 ASSERT(DOW_TYPE(id) t D0W_ISF0NC); 178 haahbucket - DOW_HASHBUCKET((long)func, (long)argp); 179 CHECK HASHDUP(Id, hashbucket, (long)func, (long)argp); f - 180 lendlf 181 DOW_M0TEX_UN ΪCK(); 182 return(id); 183 ) 184 /• 185 TODOl 186 accept a len argueaent 187 return badld if off+len croaaea pageboundary 188 Batch offaet to offaet C PAGEMASK 189 190 */ 191 192 193 • dowid_t 194 • dow_create_page(vnode_t *vp, off_t offaet, int len, ulnt_t flag) 195 • Lookup the apecified <vp, offaet> to find an aaaociated dow, 196 • if one exiata, and return it held. If a dow doea not exiat, 197 • create one. Return with a hold on the dow. flag apecifiea 198 • whetheri 199 • (1) blocking ia permitted for dow atructurea and 200 • (2) dow create ia being called froa dow_atrategy in which caae. 201 (a) blocking iβ not peraitted, and 302 (b) if dow resource ia not available, other dow_create( ) callβ 203 auat be diaabled (failed or blocked) in order to disable 204 the DOW optiaizatlon until the count of un-tracked page 205 pushes dropβ to 0. (Thia ahould be extremely improbableI ) 206 707 Calling/Exit Statet !_90' Caller holda dow_autex. It aay be releaaed and reacquired if 209 allocation ia a blocking allocation. 210 ing . 236 Calling/Exit Statei 237 dow_mutex held by the caller. The dow_autex ia held on return. 238 It aay be dropped and reacquired if flag βpecifieβ waiting la 239 tolerable. 240 / 241 242 dowld t 243 244 I -is dowld t id; ' 246 dowid t haahbucket; 247 -248 ASSERT (DOW_MUTEX_OWNED( ) ) ; 249 250 whi le ( ( id - dow_lookup_page ( vp , of f βet) ) ( dowid_t) DOW_BADID) ( 252 If (untracked_pageio > 0) ( 253 return (DOW BADID); 254 ) 255 256 if ((id - dow_alloc_l()) -- DOW BADID) I 257 if (flag t (DOW_NO_WAIT | DOW_NO_RESWAIT)) { 258 return (DOW BADID); 259 ) elae ( 260 DOW_FREE_SV_WAIT(); 61 DOW MUTEX_LOCK(); 262 continue; 263 ) 264 ) 265 1 lldent • (§( I )kern: fs/dow flush.c 1.7' • 2 lldent "$Header: $' 3 • 4 llnclude <fs/dow.h> 5 linclude <fβ/fs_hler.h> 6 linclude <io/conf.h> * , 7 llnclude < e /kπιem . h> " β llnclude <me /page.h> ' 9 llnclude <proc/proc . h> '10 linciude <svc/cloc . h> "11 linclude <svc/errno.h> 13. linclude <util/c_niii_err.ii> ]j3 linclude <util _.ebug./ι> *14 linclude <util/g__ier.lι> '15 llnclude <utll/mod/moddefs.h> 16 llnclude <utll/syamacros_f .h> '17 llnclude <utll/var.h> 18 CO _ ' 19 /• C3 5θ • TODOJ S_3 21 • Write a debug routine that can be called periodically to verify Z) 371 • that DOM_STATE, DOW_DEBUG_Ft.U__HID, DOW_DEBUG_HASHID for all the .33 * dowβ are conaiatent with each other. 1 24 • ς- > 25 * One main conce ni to verify that if a dow geta to the pruned liat, and __C "9 26 * ia Modified or ioaetup, that it will get written. He don't have anything P£_j Λ 27 * that walks the pruned liat (doea not quite make βenae), and we are depending —I 28 * on the fact that between the iodone proceaaing bubbling up and the pruning ^g 39 * froH above and fluah deaon'a leaf proceaaing, we have covered all aeana by — 30 * which dowa will get proceaaed without external nudging. i≡ 31 •/ OJ " 33 STATIC clock t dow_fluβh_daemotι_woke - 0; 34 STATIC off_t dow_pageβync_o f - (-1); 35 STATIC βv_t dow_pageβync_av; 36 STATIC lwp_t *lwp_dowfluβhd; /* dow_fluah daeaon lwpp •/ 37 STATIC vnode_t *dow_pageaync_vp - NULL; 38 STATIC boolean_t dow_pageβync_hando f - B_FALSE; ' 39 STATIC boolean_t dow_unloading - B_FALSE; 40 ' 41 void dow__pageβync_daemon(); 2 4J void dowinit(void); .44 void dowpostroot(void) ; 45 STATIC int dow load. oid) ; 46 STATIC int dow_unload(void) ; 47 STATIC k_l pid_t dow_pageβync_lwpid; 48 STATIC k lwpld t dow fluβh_lwpid; 49 STATIC told t dow timeid; 50 51 Ideflne DRVNAHE 'dow - Delayed Ordered Wri tes dri ver' 53 37 dow_load(voi ) 58 Load the dow Module. Call apawn_aya_lwp 59 to create our daeMonβ aa WPβ of ayaproc. 60 61 Calling/Exit Statei 62 Mo locka held on entry and exit. 63 64 leturn valuet 65 Oi ia returned on aucceaa. 66 It ia returned on failure, if we can't 67 start the daeaona. Thia will cauae 68 the Module load to fail. 69 '70 STATIC int 71 72 I co 73 int error; 74 75 dowinitO; 2 76 /• 1 77 * He don't aet LHP_DETAC___ED ao we can O 78 * wait for theae daeaona to exit _x 79 * if we try to unload the Module. 80 */ 81 if (βpawπ_βyβ_lwp(Sdow_fluβh_lwpld, 0, dow_fluβh_dae_non, NULL)) IX. 82 return 1; 83 84 if (flpawn_ayβ_lwp(*dow_pageflync_lwpid, 0, dow_pageβync_daemon, NULL)) { 85 /* 86 * Kill the dow_fluβh daeaon 87 * and cancel the tineout. 88 V 89 1 101 102 return 0; 103 ) 104 105 /* 106 • STATIC int Ϊ07 * dow_unload(void) 108 * Unload the dow Module. Tell the daeMona to exit. 109 * Halt for the daeMona to exit. Cancel the tiaeout. 110 * 111 * Calling/Exit Statei 111 * Ho locks held on entry and exit. error; li -_ 119 dow_unloadlhg - B_TRUEj £ 130 j 121 DOW_FLUSH_EVENT_BFOADCAST(); -__? 122 error - wait_βys_lwp(dow_fluβh_lwpld) ; —I 123 if (error) ( *—i 124 cmn_err(CE_NOTE, "dow_unload: wait for dow_fluβh error d\π", m i 125 error) ; CΛ - 136 ) r_Eπ O 137 138 SV_BROADCAST(tdow_pageβync_βv, 0); 139 error - wait_ays_lwp(dow_pageaync_lwpid); 130 if (error) ( 131 cmn_err(CE_NOTE, "dow_unload: wait for dow_pagesync error %d\n", 1'32 error); ro 133 ) cr> 134 135 untimeout(dow_tlmeid); 136 return 0; 137 1 138 139 /* 140 * void 141 • dow_βtart_fluβh_tiMβout(roid) '143 * Allocate apace for configuring a periodic tiaeout. 143 • 144 * Calling/Exit Statet 145 • Called at PLTIHEOUT. 146 */ 147 148 void 149 dow_-.t_,rt_tiu.1i_ti_aeo-ittvoi4-j 150 ( 151 void *co - itimeout_allocate( _M_SLEEP); 153 dow_tlmeid - itlmeout_a(dow_fluah_timeout, (void *)NULL, 153 (10 I T0_PERI0DIC) , PLTIMEOUT, CO); 154 155 156 157 • void 158 * dow_fluβ___tl«eout(void) 159 * dow fluah deβon tiaeout routine, firea every 10 ticka. 160 * Hakeup dow fluah deMon if there are iteaβ on the leaf fluah 161 * chain, or the age fluβh chain lβ non-eMpty and the dow fluβh deMon 163 • haa not been nudged for DOW_AGE_TIX clock ticka. 171 pl_t βavepl; 173 173 / • 174 firat, check to aee if aoMething needa pruning. 175 176 savepl - D0H_HϋTEX_L0CK(); X 177 if (IEMPTY_DOH_FL0SHLIST(DOH_LEAF_FLUSHHEAD) || 178 ( IEMPTY_DOW_FLUSHLIST(DOW_AGED_F USHHEAD) tt 179 ((lbolt - DOH_AGE_TIX) > dow_ϊluβh_daemon_woke) ) ) ( 30 180 dow fluβh_dβeπιon_wo e - lbolt; 181 DOW_FLUSH EVEWT_BROADCAST(); 183 ) 183 DOW_HUTEX_ϋNLOCK_SAVEDPL(aavepl); 184 return;. 185 186 187 /< 188 ▼old 189 dow_fluah_daeaκ>n(void *arg) 190 SyateM LHP to fluah delayed wxitea or execute deferred actiona 191 whoae antecedentβ have been written, and to Initiate the 193 pruning of thoae deferred writea/actiona that are overdue. 193 194 Calling/Exit Statei 195 The LHP blocka until βignalled by the DOH βyβteM that there lβ 196 work for it to do. 197 198 /* ARGSUSED •/ 199 void 300 a^ϊua_ *ae*rt : (vϊSi*: ϊ»ϊg 301 ( •303 dowld_t id; 303 int cycle_count; 304 205 u u_lwpp-»l_name - "dow_ lua d"; 306 lwp_dowfluβhd - u.u_lwpp; 307 208 dow_atart_fluah_timeout(); 209 310 for(;;) { 311 DOW_FLUSH_EVENT_WAIT(); 313 if (dow_unloading) 313 lwp_exit(); 314 DOW_MUTEX_LOCK ( ) ; 315 dow_ lush_daemon_woke - lbolt; 316 while ((id - DOW_FLUSHNEXT(DOW_LEAF_FLUSHHEAD) ) 21} I- DOW LEAF FLUSHHEAD) ( 318 ΛSSERT((DOW_STATE(id) t (DOW FLUSH | DOW PRUNE)) " DOW PRUNE); f (dow_proceaβ_leaf_flush(ld)) ( DOW_MUTEX_LOCK(); f (dow_pageβync_handoff) ( * Perhapa because dow_fluah could not * perfoxM a βynchronouβ page puah operation * t had to re-engueue the dow atructure * back on to the leaf chain. * * Set the dow_fluah_daenon_woke back to 0 * to enaure that the fluah daeMon geta an * early wakeup in thia caae, and break out * of the loop we are in. V dow_pageβync_handoff - B_FALSE; dow_fluβh_daemon_woke - 0; DOW_HUTEX_UNL0CK(); DOW_FLUSH_EVENT_WAIT(); DOW_MUTEX_LOCI.(); break; nt - 0; DOW FLUSHNEXT(DOW AGED FLUSHHEAD); - DOW AGED FLUSHHEAD; id - DOW FLUSHNEXT(id) ) { 249 ASSERT((DOW_STATE(id) t DOW PRUNE) -- 0); 250 if ((DOW TIMESTΛMP(id) <- (lbolt - FLUSHDELTAMA ) ) Ct 251 ((DOW STATE(id) t DOW MODIFIED) || 252 (DOW_DEP_CNT(id) > 0)) ) ( 353 prune(ld); 354 ASSERT(DOW_STATE(id) __ DOW PRUNE); 355 CHECK_NOTON_F USHCHAIN(id, DOW_ΛGED_F US__HEAD); 256 if (++cycle_count < 20) ( 357 goto reβcan; 358 } 359 goto done_acan; 360 I 261 /* elaei continue •/ 363 363 364 done_scan: 365 dow fluβh_daemon_wo e - lbolt; 366 /• 36? • now handle the leaf chain a aecond tlaie, If new work 368 * waa created due to above pruning. 369 370 371 while ((id - DOW_FLUSHNEXT(DOW_LEAF_FLUSHHEAD)) 373 I- DOW_LEAF_F USHHEAD) T 373 ASSERT((DOW STATE(id) t (DOW_FLUSH | DOW_PRUNE)) 374 -- D0W_PRUNE). 375 if (dow_proceββ_leaf_fluβh(id)) { CO 276 DOW_MUTEX_ OCI.() I 377 J 378 if (dow_pagesync_handoff) ( 379 /* 280 * Perhapa because dowjflush could not ' 281 * pertore a aynchronous page puah operation 282 * it had to re-enqueue the dow atructure 283 * back on to the leaf chain. 384 • 385 * Set the dow_fluah_daeaon_woke back to 0 286 * to enaure " that the fluah daeaon gets an break out 300 301 /<* 302 * void 303 * dow_pageβync_dae__on(void *arg) 304 <* Syatea LWP to fluah delayed page writea, if neceaaary, aynchxonoualy . 'JOδ * ork to doI */ I I ) ) I , (PRIBUF + 10), βdow mutex); c_vp, dow_pagesync_off); 335 if (Id I- DOW BADID) ( 336 /* 337 * Valid dow. He ahould proceed to fluah it only if 338 * all of the following are truei 339 • - it iβ a leaf level dow 340 * - it ia not GONE, lOSETUP, or INTRANS 341 * - it ia not already being fluahed 342 * - it iβ a ' odified 343 V 344 if (DOW_ANT_CNT(id) — ■ 0 ** 345 ((DOW_STATE(id) t (DOW_MODIFIED|DO _G0NE|D0W_FLUS__ | 346 DOW_I0SETUP|D0W_INTRANS)) — DOW MODIFIED) ) ( 347 prune(id); 348 if (dow_proceββ_leaf_fluβh(id)) ( 349 DOW_MUTEX_LOCI_ ( ) . 350 ] 351 } 3S2 dow_rele_l(id) j 353 354 355 ) /• for ( ;) */ 356 ) 357 358 359 void 360 dow_fluah(dowid_t id) 361 Thia function ia called for forcing out thoae antecdent delayed 362 writea that have not been explicitly initiated (due to a 363 V0P_PUTPAGE or a bwrite) theaβelvea. 364 365 MILL NOT BE ASKED TO HANDLE ABORTED or CLEA1-M0DIFIED DOWIDa. 366 Thia filtering ia done by the callexa. dow_fluah ia an internal 367 interface and ia invoked by dow______ndle_aync_l. dow_aeta_odify, 368 and by the dow_fluah_de__on, all of which bypaββ calling it if the dow βtate ia not MODIFIED or la aborted. Alβo will not be aβked to handle functionβ. The caller ia expected to have done the dow_flueh_reaove( ) on id. - Calling/Exit Statei cn 376 dow_autex held on the way in, but will be dropped before returning. 377 378 379 void 30 380 atfyttftW-Wtt W 381 ( 382 ASSERT(DOW_MUTEX_0WNED()); 383 ASSERT(D0W_STATE(Id) ~ (D0W_M0DIFIED | D0W_FL0SH I D0W_PRUNE)); 384 ASSERT((D0W_STATE(id) 6 DOW GONE) t DOW_GONE); 385 ASSERT(DOW_ANT_CNT(id) —- 0); 386 ASSERT((DOW_TYPE(id) <— DOW_ISPAGE) || (DOW_TYPE(id) DOW ISBUFFER))j 387 388 if (DOW_TYPE(id) ~ OOW_ISPAGE) { 389 ( 390 vnode_t *vp; 391 off_t offaet* 392 /• 393 * XXXi 394 * NEED aoae debug code to teat that the page 395 * ia in core ? 396 */ 397 DOW_CHBAP_HOLD(id); 398 vp - DOW_VP(id)» 399 of faet - DOW_OFFSET( id) t PAGEMASK; 400 DOW TIMESTAHP( id) - (clock t) (u . u lwpp) 448 449 450 CHECK_NOTON_ANY FLUSHCHAIN( id) ; . 451 DOW_MUTEX_UNL0CK ( ) ; 452 VOP_PUTPAGE( vp, of f βet, PAGESIZE, 0, βyβ_cred) ; 453 D0W_MUTEX_L0CK ( ) ; 454 if T(DOW_STATE( id) t DOW FLUSH) tt 455 (DOW TIMESTAMP( id) — ■ (clock_t) (u . u_lwpp) ) ) ( 456 CHECK_NOTON_ANY_FLUSHCHAIN(id); 457 DOW STATE(id) β- -(DOW_FLUSH|DOW_HODIFIED| 458 DOW PRUNE); 459 DOW STATE(ld) |- DOW INTRANS; 460 dow_lodone(id); 461 ) . 462 ) 463 dow_rele_l(id); 464 DOW_MUTEX_UNLOCK(); 465 return; 466 ) 467 ) elae ( 468 ( li69 dev._t dev; £ 470 int blkno; ^ 471 long bβize; C Λ 472 buf t *bp; _____ 473 i 474 dev - DOW_DEV(ld); —t , 475 blkno - DOW_BLKNO(id); rπ 476 bβize - DOW_BSIZE(id); ξ " " • 477 /* rr ~~~ 478 * Meed a debugging node function to be able to aaaert rr ~^J g • that the buffer by thia identity la in aeaory. X. ' 480 * 30 481 • = 482 * A9SraT(BP_IMC01-E(dev, blkno, bβize)); m 483 */ ro 484 /* •___? 485 * Aβ an optimization, we choose to call blookup, 486 * and only if blookup faila, drop the DOWJtUTBX and 487 * call bread. That way we can avoid the DOW_MUTEX 488 * round trip. 489 V 490 if ((bp - blookup(dev, blkno, bβize)) I- NULL) { 491 llfdef ASSERTFA1L 492 ASSERT ( (DOW_BP( id) — bp) I I (DOW BP( id) -- NULL) ) ; 493 feπdif 494 DOW BP( id) - bp; 495 bp->b_writeβtrat - dow_βtrateqy_buf ; 4 6 DOW_MUTEX_UNL0CK ( ) ; 497 bawrite (bp) ; 498 return; 499 J 500 /* 501 We don't need to raiβe the hold on the DOW in order .502 to enβure that while bread blockβ the DOW βtructure 303 doeβ not get deβtroyed/f eed. Thiβ iβ becauβe we have 5C4 already set the FLUSH βtate, which will keep dow_rele 505 and/or dow_lodone froa blowing uβ away. 506 However, we would like to initialize the b_wrlteβtrat 307 field after bread coapletea, βo we should deposit a 508 hold ao that we uniforaly apply the 509 "no reference without holding" rule. 510 511 512 DOW_CHEAP_H0 D(id) ; 513 DOW_HUTEX_UNLOCK( ) ; 514 bp - bread(dev, blkno, bsize); 513 DOW_MUTEX_LOCK( ) ; 516 /* 517 while the above bread blocked, we had 318 D0W_FLUSH set: thiβ would cauae all 519 ' except the fluah deaon to akip handling 520 the dow; conversely, if the dow_fluβh 521 waa called froa outβide the fluah deaon, 522 the deaon itβelf will not Interfere with C O . 523 the caller aince the caller haβ taken the 524 dow off leaf chain. 525 526 thiβ aeana that an external bwritβ la the 527 only thing that can race with thia dow_fluβh 528 to write it out. 829 q S30 other eventβ that could possibly race 531 aret dow_abort and dow_clearaod. 532 533 both will wait while state -- DOW FLUSH, 534 so effectively we can ignore then. 535 536 WHEN we do wake up out of bread, the whole world 537 could have changedI So we juβt go ahead and let 538 bawrite (dow_βtrategy_buf) worry about it. Ne 539 could, however, teat whether NOD, FLUSH bita are 540 off and bail out with juβt a brelβe and perhapa 54i a dow iodonel 542 / 551 552 return; 553 1 554 ) 555 556 / 557 void 558 dow_iofluβh(dowid_t id) 559 Coaplete the deferred 10 puβh for pagea buffere on which a bwrite() 560 or a VOP_PUTPAGE( ) operation had been initiated but which could not 561 be written earlier due to dependencies. 562 For these ids, we coapletely trust the bp that is βtored in thea. 563 Note that the buffers in thiβ caae have not been brelae'd; their 564 ownership haa been implicitly passed on to the dow_fluβh_daeaon. 565 566 Keaarksi hoae of lush lready and before / DOW_I0SETUP) βo we can 600 then that (a) no one (except aay be aelf) owna the bp and 601 that (b) bp iβ not on the freeliβt. 602 S03 604 605 • before we iβsue the 10, we need to handle the poββibility 606 • of thiβ id being aborted, if the id haβ been aborted, we would 507 • not want to turn off the D0M_PRUNE atate. Me atill aubait the 60θ • IO that haβ already been βetup. 609 ' •/ 610 DOW TIMESTAMP(id) - INT_MAX; 611 312 βwitch(DOM_TYPE(id)) ( <S13 case DOW ISPAGE: 614 /* 615 TBDi handle blockβlze < pagesize (nio > 1) ' 616 caβeβ, by having the buffer chain available ' 617 in the dow atructure. To do thiβ, firβt 618 aove the buffer chain out of the dow Sl9 βtructure, and then iβsue the strategy 620 callβ one-by-one. CD C ' 621 622 Aβ each io completes, dow_pgiodone will be 623 called; when the last dow_pgiodone is called, 624 dow_iodone will be called on the dowld. 625 626 bp - dow_buffer(id) ; 627 ASSERT(bp I- NULL); 628 if ((DOW_STATE(ld) t DOW_G0NE) — 0) ( 629 dow_start_nod_wrlock_l(id); 6_-0 /* 631 * during the atartaod_wrlock call, we m 632 * could block, dow could get aborted 633 * aeanwhile. yet, becauβe of the ioβetup 51 * βtate of the page, the dow atill haβ a * hold and βo cannot becoae freed until * after dow_iodone getβ called. */ f (DOW STATE(id) t DOW GONE) ( DOW STATE(id) - (DOW GONE | DOW PRUNE I DOW INTRANS); else ( DOW STATE( id) - DOW INTRANS ; dow_drop_modlock_l ( id ) ; 646 ASSERT (DOW_STATE( id) t DOW PRUNE) ; 647 DOW_STATE ( ld ) - ( DOW_GONE | D0W_PRUNE 648 I DOW_IOTRANS) ; 649 ) 650 DOW MUTEX UNLOCK ( ) ; 701 void 702 dow_fluβh_tailinβ(dowid_t id, dowid_t fl_head) 703 Inβert the dow "id" at the tail of the fluβh chain. 704 705 Calling/Exit Statei 70* dow_anιtex held by caller, and held on return. The function 707 doeβ not block or drop the lock. 708 aβ appropriate. e function 739 740 void 741 742 i 743 ASSERT (D0W_MUTEX_0WNED( ) ) ; 744 ASSERT(VALID_DOWlD(id) ) ; 745 ASSERT (on_βome_ luβhcha in (id) ) ; 746 747 DOH_FLϋSHPREV(DOW_FL0SHNEXT(id)) - DOH_FL0SHPREV( id) ; 748 DOW_FLUSHNEXT(DOW_FLUSHPREV(id)) - DOW FLUSHNEXT(id) ; 7 9 750 DOW_DEBUG_FLUSHLEAVE( id) ; 751 ) 752 753 /• 754 • void 755 • dowinit(vold) 756 * Initialize the dow subsystem. 757 * 758 « Calling/Exit Statei 759 * Should only be called during βyβtea. βtartup - no locking iββueβ. 760 * 761 • Deacrlptioni 762 * Inltializea the dow data atructureβ. 763 */ 764 void 765 &_*init<»ota) 766 ( 767 dow_arrayinlt()j /* initialize the dow array •/ 768 1 ializationa. in() after Mounting root. wp(NP_STSPROC, *dow_fluβh_lwpid, LWP DE ACHED, NULL, dow_fluβh_daemon, NULL); r 784 £2 785 (void) epawn_lwp(NP_sySPROC, «dow_pageβyne_lwpid, LWPjjETACHED, NULL, 786 dow_pageβync_daemon, NULL) ; 787 J 1 lldent '@(l)kern:fs/dow_handle c 1 .3 ' 3 lldent 'SHeader: $ ' 3 4 llnclude <fa/dow. h> 5 llnclude <ta/fa_hler h> 6 llnclude <lo/conf h> 7* llnclude -mem/Jt βm . h> 8 llnclude <me /page . h> 9- llncl ude <svc/clock. h> 10 llnclude <utll/cmn_err. h> 11 llncl ude <utll/debug h> llnclude <utll/ghler. h> 13 llnclude <utll/ayβnacros_f h> .14 llnclude <utll/var h> 15 17 void lβ dow_handle_aβync(dowid_t Id) 19 ao Initiate operationa that would ultimately result In a O 21 write 10 for Id, If aoae operation la not already 22 underway. C . 23 24 Calling/Exit Statei 25 36 Caller expected to paaa In a dowld with a hold, if valid, 27 the hold will be not be releaβed by thia function before -18 it returnβ. 29 1 30 Remarksi by dow_handle_aβync_l . 38 DOW_MUTEX_L0CK(); 39 dow_handle_aβync_l(id). /* will drop the dow autex */ 40 return; 41 ) 42 43 /• 51 • Calling/Exit Statei 52 * 53 * Caller expected to paaa in a valid dowld with a hold. 54 * the hold will be not be releaaed by thia function before 55 • it returna. 61 uchar_t ld_βtate; 62 63 ASSERT(DOW_HOTEX_OWNED()); 64 ASSERT(VALID DOWΪD(id)); 65 id_βtate - DOW_STATE(id); 66 ASSERT(DOW .OLD(ld) > 0); 67 E|DOW_PRUNE)); ) I - 0) ( DOW_MODIFIED) { d) I- DOW PRUNE; I if (ld_βtate 4 (DOW IOSETUP | DOW_F ISH)) ( ASSERT<(DOW_STATE(ld) 4 DOW PRUNE) !- 0); If ((ld_atate 4 DOW_F OSH) -- 0) ( /• Huat be lOSETUP. Fluah it */ ASSERT(DOW_STATE(id) 4 DOW MODIFIED); dow_fluah_reπ_ove(id); DOW_STATE(id) I- DOW_FLUSH; dow_ioflush(ld); ) else ( * FLUSH ia aet. Thia id ia already being * handled by the DOW ayatea DO vW MUTEX UNIΛCK ( ) ; i return; I if ({id_βtate 4 DOW MODIFIED) — 0) ( 101 1103 * Thia could be either because id waa never 103 * Modified, or it waa either clear_Modified 104 * or aborted. 105 V 106 do _f luah_remove(id) ; 107 DOW STATE(id) I- DOW I NTRANS; 198 do _iodone(ld) ; 109 D0W_MUTEX_UN__OCK ( ) 110 return; 111 ) 112 /* 113 * Enaure that id geta out aoon, by putting it at the 114 * head of the leaf fluah chain. PKUHE aay or aay not be US * aet, ao we aet it in any caae. We want to let the fluah 116 * demon take care of it aince we don't want to block here. 117 V liθ U9 dow_flush_remove(ld) ; 130 DOW STATE(id) I- D0W_PRUNE; CΛ .151 dow fluβh headinβ(Id, DOW_ EAF_F ϋSHHEAD) ; cσ 132 DOW_HUTEX_ON 0CK( ) ; <n. Hi return; 124 125 ) /• if D0W_ANT_CHT(ld) — ■ 0 */ 126 127 /• If the id haa not been pruned, now ia the tiae to do it */ 128 if ((id βtate t DOW PRUNE) -- 0) ( X 129 prune(Id) ; 130 ] 131 30 ni CHECK_ANTECDEWTS_PRONED(id); 133 DOW HUTEX UNLOCK( ) ; 134 return; INJ ^5 3 136 13-7 138 void 151 * Caller expected to paaa in a dowid with a hold, if valid. 152 * the hold will be not be releaaed by thia function before 153 • it returns. 151 • 155 * Reaarkat ne by dow_handle_βync__l. . 194 ) 195 If (DOW ANT CMT(ld) — 0) { 196 If T(ld_state S DOW_INTRANS) I- 0) I 197 if (DOW_STATE(id) t DOW MODIFIED) ( 198 DOW_STATE(id) I- DOW PRUNE; 199 dow_intranβ_wait(ld); 200 DOW MUTEX OCK ( ) ; 201 if (((DOW STATE(ld) t DOW MODINTRANS) — 0> | | 103 (DOW STATE(id) t DOW GONE)) { 203 /* ■iaaion accoapliahed */ 2l?4 DOW_MUTEX_UNI_OC_.(); 205 return; 206 ) 207 /* elae wait for 10 to coaplete, below */ 208 ) 209 dow_intranβ_wait(id) ; 210 return; 211 J 212 213 if (id βtate t (DOW IOSETUP | DOW FLUSH)) [ 214 ASSERT (id βtate t DOW PRUNE); 215 If ((id βtate S DOW FLUSH) — 0) { 216 /* Muβt be lOSETUP. Fluah it */ 217 ASSERT(DOW_STATE(id) t DOW MODIFIED) ; 218 - dow_f lush_remove(id) ; CO 21? DOW STATE(id) I- DOW FLUSH ; Cg 220 dow iofluβh(id); ζ3 ' 221 DOW MUTEX LOCKO; 322 /* i 23? * and then, wait below —I " 224 " */ £ 225 1 t? 1 226 /* FLUSH ia aet. Thia id ia already being •/ fφj 217 /• handled by the DOW ayatea */ ni 328 dow_intrana_wait(id) ; 229 return; Λ 230 I r= 231 m 33 if ((id βtate t DOW MODIFIED) — 0) ( either the id waa never modi ied, or waβ 335 * either clear_«_odifled or aborted. 336 */ 237 DOW STATE(id) |- DOW INTRANS; 238 dow_fluβh_remove(id) ; 339 dow iodone(id); 240 DOW MUTEX JNLOCK() ; 341 return; 242 ) 243 244 /• 245 • Modified, and not being fluβhed/written. We can 246 * aaaert that id haa not been aborted, aince dow_abort 247 * would have cleared MODirv, or failed to proceed 348 * becauβe of a fluah in progreaa; but had the latter 249 * been the caae, the βubaequent 10 that haa occurred would 350 • have cleared MODIFY. 251 * 252 * Since we can tolerate blocking, let ia perfora the fluah 253 • right hereI 254 */ 255 if (DOW TYPE(id) £ DOW ISFUNC) [ 256 dow_flush_remove(id); 257 DOW STATETid) I- (DOW_FLUSH | DOW_ RUNE); 258 dow_proceββ_leaf_func(id, NULL); 25«. DOW_MUTEX_UNLOCK(); 260 return; 261 ) else ( 262 dow_flush_remove(I ); 263 DOW STATE(id) I- (DOW FLUSH | DOW PRUNE); 264 dow flush(ld); 265 D0W_MUTEX_L0CK { ) ; 266 dow_intranβ_wait(ld); 267 return; ' tate t DOW PRUNE) — 0) { rune(ld); HECK_ANTECDENTS_PRUNED(ld); t_l(ld); _- 1 -- - rt» a - <~TJ -rt 51 * tine to deque id froa ita fluah chain. 52 •/ 53 llfdef DEBUG 54 I (DOW STATE( id) « DOW PRUNE) ( 55 ASSERT (DOW_DEBUG_FI_USHID( ld) — DOW_I EAF_FI_USH_IEAD) ; 56 ) else ( 57 ASSERT (DOW_DEBUG_F__USHID( id) — ■ DOW_AGED_FLUSH__EAD) ; 58 1 59 lendlf 60 dow_f luβh_reπιove( id) ; 61 I 62 CHECK_NOTOM_AHY_FLUSHCHAlN(id); 63 DOW_STATE(ld) - D0W_1NTRANS; 64 dow_lodone_inβert(ld, bp, dow_buf_iodone); 65 DOW_TIMESTAMP(ld) - INT_MAX; 66 DOW_MOTEX_ϋN OCK{) t 67 (*bdevβw[getmajor(bp->b_edev)] .d_βtrategy)(bp); 68 return; 69 1 CΛ 70 C 71 ASSERT((DOW_STATE(ld) ft DOW FLUSH) — 0); ζ ^j 72 if <(DOW_STATE(id) t DOW_PRUNE) — 0) { 73 CHECK_OH_FI_OSHCBAIM(ld, DOW_AGED_FUJSH_EAD); Z l 74 ASSERT((DOW_STATE(id) t DOW_FLUSH) — 0); —. . '75 rune(ld); m ' 76 ) ξ ^ 77 CHECK_NOTON_FUISHCHAlM(id, DOW_AGEO_FI_USHHEAD); m - 78 r* * ! 79 dow_lodone_lnβert(id, bp, dow_bu _iodone)» „ 80 . DOW_STATE(Td) - (DOW_IOSET0P | DOW_MODIFIED | DOW PRUNE); 3 81 DOW TIMESTAMP(id) - (lbolt - FLUSHDELTAHAX); F 82 /* rr ' 83 * alnoe there are antecedenta, we could not have COM here 84 * fro___ dow_fluah. There ia not amch elae to do; we have -Ξ* 85 * already pruned the id, βo we can be outta here. 86 • 87 * in a βynchronoua bwrite call, the caller doea not do a 88 * dow_intra_Bβ_wait; rather, it will do a blowait() after 89 * calling thia strategy function. Control will return to 90 * the caller, in that caae, after the dow_iodone proceaaing 91 • haa been completed. 92 •/ 93 DOW_BP(id) - bp; 94 DOW_MOTEX_UNLOCK(); .95 return; 9* ) 97 98 /* 99 • THIS VERSION DOES MOT HANDLE blockβize < pageβize. See file 100 • arultt_bp_pagelo for how thia will be handled. 101 .102 ASSUMPTIONSi 103 blockaize >- pageaize 104 page cluatering diaabled selectively for DOW uaea. 105 106 107 108 void 109 dow_βtrategy_page(buf_t **bpp. vnode_t *vp, off t off, int len) 110 111 Perform dow setup for a page write/fluah requeat. If a dow 112 atructure exiatβ, and haa antecedenta, then the dow ia aarked li3 aa "lOSETUP" -- i.e., ready for a deferred call to the device 114 strategy routine. If the dow atructure haa no antecedenta, 115 then the IO ia submitted luediately. 116 If a dow atructure corresponding to the page doea not exist, then a dow atructure ia created. Thia allows the tracking of 119 intranβit pages for the DOW system, βo that if a dow_create( ) l_ιO were to occur on an in-tranβit page then the dow would correctly en 121 contain the "IHT__ANS" atate. Theae actiona are specific to co ι?_t page dowa βince a page-fluβh requeat can originate without 153 any resource locking (unlike a buffer flush request). 124 125 Finally, becauae aultiple page write requests can be in Hi progress at the βaae tiae (eventhough only one call to the 137 device strategy routine can reault at a tiae), the dow strategy 128 routine acquires the DOW__H0D_LOCK (pβeudo rwaleep lock) in 1J9 the write aode in order to clear the DOW_MODiriED state. 13 By clearing the MODIFIED atate under the cover of the D0W_M0D_0CK, 131 it is asaured that the MODIFIED atate ia not aet unless the 150 DOW MOTEX LOCK ( ) ,• 151 /• 152 * aaauae the caller haa enaured that dow_atrategy ia 153 * called only for the appropriate type of pagea (i.e., 154 * directory pagea, for example.) 155 •/ 156 157 id - dow_create_page_l(vp, off, len, DOW_NO_WAIT); 158 if (IVALID_DOWID(id)) ( 159 dow_io_utp_βetup(*bpp); 160 (++untracked_pageio); 161 DOW_MUTEX_U(.LOCK() I 162 (*bdevβ (getιuajor((«bpp)->b_edev)J d_βtrategy)(*bpp); 163 return; 164 ) 165 ASSERT(DOW_TYPE(id) — DOW ISPAGE); 166 /* 167 * The following aaaert ia true uhder the aaauaption that the file 168 * ayatea (or dow client) aeriallzea calla to dow_atrategy for the ry 169 * aaaβ page auch that only one call can be active through upto the CD 170 * point that biodone proceaaing ia done. ^ 171 */ :___} 172 ASSERT((DOW_STATE(id) S (DOW_INTRANS|DOW_IOSETDP|DOW_GONE)) — 0); Cj 173 ASSERT(DOW HOLD(id) > 0); m . 174 dow_Btart_mod_wriock_l(id)j CO _, .175 /* • - y ^ 176 * on return froa dow_atartaod_wrloc_t_l, the dow could have been J_J_j A 177 * aborted, hence in the reaalnder of thia function, we auat explicitly —. I 178 * account for that poaaibillty. CZ i1"80 . do • w/_iodone_inaert(id, *bpp, dow_page_iodone); fa 181 if (DOW_ANT_CNT(id) ~ 0) t .,- 182 if 7<DOW_STATE(ld) * DOW_FLUSB) — 0) ( S3 1 lβ 84 3 /** if thia write originated externally, now ia the 185 * tiae to deque id froa ita fluah chain. 186 •/ 187 llfdef DEBUG 188 if (DOW_STATE(id) t DOW_PROME) ( 189 ASSERT(DOW_DEBϋG_PLϋSHID(ld) — DOW_ EAF_FUSHHEΛD); 190 ] elae ( 191 ASSERT(DOW DEBUG^FLUSHID(ld) — DOW_AGED_FLUS__HEAD); 192 J 193 fendif 194 dow_fluah_remove(ld); 195 J 196 if (DOW STATE( id) S DOW GONE) I 197 DOW STATE( id) - (DOW GONE | DOW PRUNE | DOW INTRANS) ; 199 DOW STATE( id) - DOW INTRANS) 200 dow_drop_πtodlock_l ( id) j 20 * 1 ) SO} DOW TIMESTAMP(id) - INT_MAX; 303 DOW HUTEX UNLOCK ( ) ; 204 (*bdevsw|get_ma jor( (*bpp) ->b_edev) ) .d_βtrategy ) (*bpp) ; 205 return; 306 } • 203 If ((DOW STATE(id) t DOW PRUNE) ~ 0) [ 30$ CHECK_ON_FLUSHCHAIN(ld, DOW_AGED_FLUSHHEAD) ; J0 ' 9 ASSERT ( (DOW_STATE( id) t (DOW_FLUSH |DOW_IOSETUP |DOW_GONE) ) — 0 ) ; 210 prune(id); 311 ) 312 CHECK_NOTON_F__USHCHAIN(id, DOW ΛGED FLUSHHEΛD); 213 /• 214 * So we have antecdenta. We could not have cone here froa the 215 * fluah daeaon In that caae. Mor could fluah deaon have atarted on ua. 216 •/ 217 ASSERT((DOW_STATE(id) t DOW FLUSH) — 0) ; 218 LΛ 319 /» ς5 3)0 * EVENTBOUGH WE AXE MOT ABOUT TO TURN ON INTRANS, we keep MODIFIED 231 * OI-P If DOW GONE la aet. Thia la because DOW_GOMΪ waa set AFTER ^2 233 * all exiating aodificationβ that held relevance to the dow aubaystea ζ ^ 333 * had already cleared. After the atate ia βet to DOW_GONE, we do —~j 334 * not allow the creation of new antecedenta anyway, ao it ia not , 335 * clear how we eight end up here with a write unleaa the dow client 2? _ 336 * haa done nothing to enβure thia doea not happen, fl! * Λ 237 « _-j -(I .33d * The current write haa originated externally and coincidentally s-~ i 33$ * found the aborted DOW atructure in that easel So we just do what ~ 330 * we must -- paaa the write along, but don't infer MODIFY. rΞ 331 •/ 333 O? '3?3 if (DOW STATE(id) t DOW GONE) ( ' 23 DOW STATE(id) - (DOW IOSETUP|DOW GONE|DOW_P UNE) ; 335 ) elae { 236 DOW_STATE(id) - (DOW_IOSETUP|DOW_MODIFIED|DOW_PRUNE); 337 dow_drop_modlock_l(id); 338 ) 33$ 2<0 DOW BP(ld) - (*bpp); 341 DOW_MUTEX_UNI_OCK ( ) ; 343 /* 343 * In a aynchronoua VOP_FUTPAGE, the caller will do the biowait 344 * on each of the buffera that coaprise the page. Therefore, by 245 * the tiae that the laat biowait coapletea, dow_iodone will get 246 * called for the dowid. So we don't need to do a dow_intrana_wait 347 * in here. ~ 348 •/ 249 return; 250 1 251 353 358 359 Calling/Exit Statet 260 Called at interrupt level froa biodone. Acquires and xeleaaea 361 dow autez. 262 263 264 void 265 266 I 267 dowld_t id; 268 pl_t aavepl; savepl - DOW MUTEX LOCK(); id - DOW_P_TO_lD< (bp->b__niβc) ) ; ASSERT(VALID_DOWID(id) )7 ASSERT(DOW_HO D(id) > 0) ; ASSERT (DOW_DEV( id) -- bp->b_edev) ; ASSERT (DOH_B__f_MO( id) — bp->^b_blkno) ; ASSERT(DOW_TYPE( id) — ■ DOW_ISB0FFER) ; CHECK_N0TON_A Y_FUJSBCH M( id) ; DOW_CHEAP_RELfe(ϊd); dow_lodone_reβtore(id, bp); dow_iodone{i ); DOW_MOTEX_0NL0CK_SAVEDPL(βavepl); biodone(bp); 286 dow_page_iodone(buf_t *bp) 287 Perfora the chained iodone action for a dow on coapletion of a 388 page write. 289 390 Calling/Exit Statei 291 Called at interrupt level froa biodone. Acqulreβ and releaaea 292 dow autex. 293 301 savepl - DOW MUTEX 0C ) > 302 id - DOW_P_TO_ID((bp->b_miβc)); 3C3 ASSERT(VALID_DOWID(id) ) ; 304 ASSERT(DOW_H0LD( id) > 0); 305 ASSERT(DOW_VP(id) — bp->b_pagea->p_vnode); 306 ASSERT(((bp->b_flags _ B_PAGEIO) ti 307 (DOW OFFSET(id) — ( (o t) (bp->b_pageβ->p_offaet) + 308 (off_t)(bp->b_un b_addr)))) 309 || ((DOW OFFSET(ld) — ( (off t) (bp->b_pageβ->p_o faet) ♦ 310 (((unsigned long) (bp->b_un b_addr)) % PAGESIZE))))); 311 ASSERT(DOW_TYPE(id) —• DOW ISPAGE) ; 312 CHECK_NOTO_-_ANY_FI_ϋS_.CHAIN(id); 313 DOW_CHEAP_RE E(id) ; 114 dow_iodone_reβtore(id, bp); 315 dow_iodone(id)j 316 DOW_M0TEX_0NL0CK_SAVEDPL(βavepl); 317 biodone(bp); 31* 319 320 321 void 333 dow_untracked_pageio_iodone(buf_t *bp) 313 Perfora the chained iodone action for a dow on coapletion of a 334 page write, for which no dow waa created (becauβe of dow resource 335 exhaustion) . 336 Calling/Exit Statei 330 Called at interrupt level froa biodone. Acquires and releaaeβ 329 dow autex. 330 331 333 void 333 ao._u n t rBC ked_jp*,eio_ < _ό^(i&f_t »t» ) 334 I 335 pl_t savepl; 33. /• 337 « handle untracked page io protocol. 338 * 339 • paaa on to other iochain processing. 340 •/ 341 savepl - DOW_MOTEX_I_OCK( ) ; 343 (--untracked_pageio) ; 343 dow_io_utp_rele(bp); 344 DOW_M0TEX_0N 0CK_SAVEDPL(savepl); 345 biodone(bp); 346 ) 347 348 /• 349 • void 350 • dow_iodone( dowld_t id ) 351 On write 10 coapletion, (a) issue wakeupa to LHPa that are in 353 dow_intranβ_wait, (b) break dependencies and (c) execute actions 353 that can be, but need not be, deferred to the dow_flush_deaon, 354 for new leaf level dowa that are created aa a reault of (b) . 355 356 Calling/Exit Statei 357 dowjsutex held by caller, caller enaurea that the dowid ia held 358 if necessary. Thia function ia called at Interrupt level, and cannot headlink, link; o 393 V 393 dow_f1ush_remove(dep); 394 dow_proceββ_leaf_iodoae(dep); 395 396 ) /* while */ 397 398 399 * we have handled all the dependent links, next we need tot 400 401 - if (hold --> 0) free the dow atructure 402 - otherwisei 403 - signal blocked waitera 404 - if PRUNE'd and MODIFIED, reinsert on the leaf 405 fluah chain 406 - elae if GONE, then turn off HODIFX, unhaβh and 407 put away on the PKUNE liat (no one looka at it) 408 - else turn off all βtatea except MODIFY, and 409 insert on the tail of the aged flush chain. 4.0 / 411 ASSERT(DOW_HUTEX_OWNED( ) ) ; 413 ASSERT(DOW_DEP_CNT(id) — 0); 413 ASSERT(EMPTY_D0WLINK IST(headllnk)); 414 if (DOW STATE(ld) t DOW GONE) I 415 ASSER (D0W_STATE( id) — (DOW PRUNE | DOW GONE)); 416 CHECK_HASH_REMOVED( id ) ; 417 if (DOW HOLD(id) > 0) ( 418 if (DOW_SV_BLI_D(id)) ( 419 /• wakeup blocked waiterβ */ 420 DOW SV BROADCAS (id) ; CD 421 I <r 433 dow lush taillnsfid, DOW_PRUN_FLUSHHEAD) ; 423 CHECK_ANTECDENTS_PRUNED(id) ; 414 return; 436 ASSER ( IDOW_SV_BI_KD( Id) ) I Λ IΛ. 427 do _free( Id) ; 438 return; i 439 } 430 1 *>i CHECK_HASH(id); 432 If (DOW_HOI_D(id) — ■ 0) ( 433 /* there βhould be no blocked waitera . */ 434 ASSERTf I DOW SV_BLKD( Id) ) ; 435 dow_remhaβ_ι(ld) i 436 it (DOW TYPE(id) — DOW ISPAGE) ( 437 VN_SOFTRELE ( DOW_VP ( Id ) ) I 438 1 439 dow_f ree(ld) ; 440 return; 441 ) 442 if (DOW STATE(ld) t DOW PRUNE) ( 443 if (DOW STATE(id) t DOW MODIFIED) ( 444 dow_f lush_tai Una (id, DOW_LEAF_F USHHEAD) ; 445 ) else ( 446 /• 4--7 • soaeone turned on the PRUNE bit while laat 448 • IO waa in progress; no MOD atate waa deposited, 449 * however. Furthermore, thia dow haa not been 450 * aborted βince DOW GONE was checked earlier. 451 * just turn it back off and aend thia id to 453 * aged list. Since we got rid of all of itβ 453 * dependentβ, it iβ okay to turn off the PIUNE 454 * bit aince the protocol that "entire βubtree 455 * under a pruned dow ia Maintained pruned" ia 456 * not violated. 493 /• 494 • void 495 * dow_iodone_reatore(dowld_t id, buf_t *bp) 496 * Restore the iodone chain in the buffer bp after unlinking 497 • the dow_iodone action. 498 • 499 • Calling/Exit Statei 500 • Dow_.ra.tex la held by the caller who iβ at interrupt level. 516 * Calling/Exit Statei 517 • Called under dow xutex cover. 518 ; 1 dent '@(l)kern : fs/dow_leaf . c 1.3 ' 2 dent 'SHeader: $ " 16 dow_j>roceββ_leaf _func(dowid_t leafId, vo d (*called_froa)(do ld_t)) 19 30 Pxoceaa a leaf level dow that repreaenta a function. Called either 21 aa a reaαlt of the aat antecdent going away (during Iodone 22 proceaaing of the laat antecdent) or froa fluah deaon or handle 23 routinea that want to execute the leaf level dow function. 24 25 Thia function la written with the knowledge that (a) a unction dow 26 haa no dependenta and (b) that It ahould not be puahed to the aged ' 27 liat, βince functiona are to be executed in a tiaely ■anner. 28 29 Calling/Exit Statei 30 . dow_autex held on entry. Hay need to be dropped if the function ia 31 a blocking function. 32 33 If called_froa -■ dow_lodone, then the dow_autex la not dropped, 34 and if .the function can be execcuted without blocking then it ia 35 executed. dow_autex iβ held on return. 36 37 Otherwiae, the function will be executed (aubject to ita MOD atate 38 being aet). The dow_autex will be reacquired before returning. 39 40 Caller iβ expected to have reaoved the leafid froa any fluah chain 41 that it aay have been on. 42 / 50 ASSERT(DOM_MOTE)t_OHMED( ) ) ( 51 ASSERT(VA ID_DOWID(leafld))i ; 52 ASSERT(DOW_DEP_CNT(lea ld) « 0); 33 ASSERT(DOW_TYPE(leafld) t DOW ISFUNC); 54 /• 55 * we ahould either never be aborting a function, or be doing the 56 * abort aynchronoualy aince functiona can theaaelvea have no ' 57 * dependenta. In that caae, no one ahould ever get here with an 58 * dowid that iβ aarked DO JGOHE. 59 •/ 60 ASSERT((DOW_STATE(leafid) t (D0W_G0NE|DOW_I NTRANS) ) — 0). 61 CHECI._N0TON_ANY_FU.SHCHAIN(leafid); .62 CHECK H ASH (leaf Id); If (DOW STATE(leafld) t DOW MODIFIED) { If (DOW TYPE(leafid) — DOW_ISFUNC_NBI_l.) ( an't block blocking one. H) -- • 0)> I_USHHEAD) ι ••93 ] .84 /* .85 * we will need to drop the autex before we can execute the .,86 • function. In preparation, we aet the "DOW_J_l»πtΛHg" state .87 */ ,58 DOW STATE(leafld) - DOW INTRANS; !β9 funcp - DOW_FWNC(leafid); 90 argp - DOW_ARGP(leaf id) ; ,9\ DOW_MUTEX_UN OCK ( ) ; 92 (<* uncp)(argp); 9J DOW MUTEX IJOCK ( ) ; . , 95 goto done_execute; .!»6 ) 97 98 /• , ,99 * elβei DOW_MODIFIED -- 0. we have theae alte nativeai 100 « 101 treat it aa a "clear-aodifled/aborted" caae, whereby we juat 102 proceed to handle It as a dow whoae execution haa already 103 happened. 104 105 a problea with (1) la that It requires that In the uaual caae 106 (no abort/clear-aiod), we auat never have a function dow that ia 107 ■arked aa unmodified -- i.e., dow_crβate_func auat perfora 108 dow_aetaod. but that ia unacceptable, aince the client ezpecta 109 to control the firing of thia function in relation to aoae other 110 aetup work being completed (i.e., only after dow order haa 111 coapleted). but we cannot puah the function dow to the aged liat 112 either, aince then we don't have a guarantee about who will do 113 the final releaae of the dow (i.e., not being able to diatinguish 114 between whether a clear-aod waa called or whether a aet-aod waa 115 _not_ calle .) 116 .117 owing to coaplieationa (1) and (2), we handle auch dowa juat a 118 little differently aa followst we aasuae that for a function 119 dow, 'if it ia NOT MODIFIED and MOT HELD, then it can be treated 120 aa having been clear-aodifled; elae we ahould treat it aa a 121 dow on which a aet-aodify aay yet happen. In thia caae, when 122 the final dow_r*lβ doea coae through and it finda the function ς*> 123 dow in a clear-aod atate, It juβt getβ rid of it (which ia 124 appropriate, for it would do the βaae for any dow that haa no 125 dependents). 126 127 Thua we chooae alternative (3). See coaaent in dow_rele_l() for C 128 function dowa. 129 130 if (DOH HOLD(leafld) — 0) ( 131 DOH_STATE(leafid) - 0; 132 goto done_execute; 133 1 134 rv_> 135 DOW STATE(leafid) t D0W_PRUNE. σ_» 136 DOWJTIMESTΛMP(leafld) - INT MAX; /• unaodified, βo doean't aatter •/ 137 dow fluβh_tallina(leafid, DOW_AGED_P ϋSHREAD); 138 return; 139 140 done execute: 141 /• 142 • basically, thia ia specialized iodone proceaaing for functions. 143 V 144 ASSERT(DOW_MOTEX_OWNED()) I 145 dow_remhash(leafid); 146 DOW STATE(leafid) - (DOW_G0NE|D0W_PRUNE); 147 if (DOH HO O(leafid) > 0) I 148 if (DOW_SV_BLI_D(leafid)) ( 149 DOH_SV_BROADCAST(leafid); 150 I 159 return; lβO 162 163 void 164 dow_proceaβ_leaf_iodone(dowid_t id) 165 166 Called froa dow_iodone to proceaa each new leaf dow that IS7 reaulta froa breaking dependence links. 168 Caller ia expected to have reaoved the leafid froa any 169 fluah chain that it may have been on. Λ d CO CO 3m: 3 197 1 198 /• 199 * He need to enaure that we ahould not be here and have abo • waitera blocked on 10 coapletion for idl (Though thia 201 * ia tolerable, it ia not good, particularlf if the id aoa * ia unaodified). Hith aodified Ida, we expect that anyone 203 * that waita doeβ ao after pruning the id. leave the 204 * exiating tiaeataap on the id unchanged. 205 V 206 dow_f luβh_tail inβ( id, DOH AGED FLUSHHEAD) ; 207 return; 308 1 209 /* elae i pruned */ 210 i f (DOH_STATE( id) t (D0H_I0SETUP |D0H_H0DIFIED) ) { 211 if (DOH_STATE( id) t DOH IOSETUP ) ( 213 dow_f iuah headins ( id, DOH_I_EAF_FLUS__HEAD) ; 214 dow f luβh_tailinβ( Id, DOH LEAF FLUSHHEAD) , • 215 ] 216 return; 217 218 219 PlUNE'd,- but IMOD, !INTRANS, IlOSETUP, IFLUSH. May Naynot be GONE. 220 221 IF GONE! 223 223 we want to do what dowjlodone eight normally do for a CONE or 224 clear-aiodified dow, without calling it recursively froa here, 225 ao we do the following! 226 .227 BOLD »» 0, DEP_CHT -" 0 i unhaah and free 228 HOLD 1- 0, DEPJCHT - ■ 0 i unhaah, put on pruned liat 229 dow_rele will get rid of it 230 DEP CUT > 0 i don't unhaah. put back on 231 the leaf chain ao that 232 dowjlodone will be called on 233 it later. s 234 235 IF IGONE i Muat be either clear-aodifled or 236 not yet aet-aodified. In either caae, 237 we can let the fluah deaon handle the 238 appropriate βignalling of waitera, etc. 239 He take care of the aiaple caae here. 240 241 BOLD -» 0, DEPJCHT »» 0 i unhaah and free 242 Otherwiaei t reinaert to leaf fluah tail. 243 244 245 ASSERT(DOH_HUTEX_OHNED( ) ) ; 246 if (DOW STATE(id) t DOH_GONE) I 247 CHECK_HASH_REMOVED(ld) ; 248 if (DOH_DEP_CNT(id) > 0) ( 249 dow fluβh_tailinβ(id, DOH_l_EAF_FI_USHHEAD); 250 return; 351 J if (DOW HOLD(id) > 0) { 353 dow fiush_tailinβ(id, DOW_PRUN_F USHHEAD) ; 354 return; 355 ) 356 ASSERT( ID0H_SV_B _.D( id) ) ; 257 do _free(id); 258 return; 359 I 360 CHECK_HASH(id); 361 if ((DOH_DEP_CNT(id)— 0) tt 2'βa (DOH HOLD(id) — 0)) I 3'63 do _remhaβh(id) ; 364 ASSERT( 1DOH_SV_BLKD(id) ) ; 2*5 if (DOW TYPE(id) — DOW_ISPAGE) I 2t-6 VN_SOFTRF.LE(DOW VP(id) ); 36? ) 268 dow free(id); CO c 369 return; cσ: 3*0 ) O %n dow luβh_tailinβ(ld, DOW_LEAF_FLOSHHEAD) ; Hi return; 373 ) 37* 273 O 2 6 boolean t 277 dow_proceaβ_leaf_fluβh(do ld_t Id) 278 Perfora the appropriate fluah actiona for a dow that haa no 379 antecedenta. 30 380 m 381 Called with dow_autex held. May drop It before returning, 362 return: B TRUE Tf DOH_MϋTEX dropped. 383 384 Caller haa NOT reaored the id froa the leaf fluah chain; alao, 385 it auat only be on the leaf fluβh chain. 386 387 Calling/Exit Statei 388 Caller hold dow_autex, which iβ dropped if either fluah/iofluah 09 actiona need to perforaed. 290 . 391 boolean t 292 293 i 294 ASSERT(DOH_MUTEX_0HNED( ) ) ; 295 / • 396 * The caller of thia procedure haa obtained id froa the 397 * leaf fluah chain. Therefore, we can be certain that no one 298 * elae ia currently fluahing thia dowld. Purtheraore, we can 49 * be certain that the id haa been pruned. 300 301 CHECK_ON_FLUSHCHAIN(id, DOH_LEAF_FLUSHHEAD) ; 303 ASSERT((DOH_STATE(id) t ( DOW FLUSH1 NTRANS |DOW_PRUNE) ) — • DOH PRUNE); 303 llfdef DEBUG NTRANS)» 51 protocolβ followed by dow_fluβh_deaon and dow_βtrategy S3 will enaure that thiβ iβ done by pruning the 53 dependency aubtree that iβ rooted at the dow. 54 55 dow_abort will alβo participate in thia protocol. 56 57 (b) If any dow iβ pruned, then all ita dependenta current 58 and future will be pruned aa well. Thia haa iaplicationβ 59 on dow order. 60 61 (c) When a diβk .write doeβ take place, a dow reverta 63 to the non-pruned atate. 63 64 (d) Dow itrπuu-S -> -(DOW_ri_USH I DOH_IOSETOP | DOW_MODIPI D) 65 66 In eβtabliβhing a link, it ia of intereβt whether the 67 •relevant* Modification of the antecedent haβ already 68 been fluahβd to the diβk; if βo, the linkage la not 69 neceeβaxy (and ahould not be aade, if no event can be 70 guaranteed to occur that can break the link). 71 Siailarly, if the dependent ia already being written 73 to diβk, then linking cannot be coapleted until the 73 dependent write coapleteβ -- otherwiae, the impending 74 aodification of the dependent can becoae fluβhed to 75 * diak while the antecedent ia yet to be fluahed. i 76 Theβe yield the following! 77 m __c 78 IF antecdent iβ in βtatei 1 79 30 80 MODIFIED, but not INTSAHSt The relevant aodification of 81 the antecedent aay not be written to diak. So 83 a link ahould be created unleββ the dependent ro 83 iβ itrπtAHS, 3 84 85 INTKANS, but not HODIFIEDi The relevant aodification iβ 86 being written (potentially), and we could definitely 87 conclude that it ia written when the current write 88 coapletea. Either we wait for the write to coaplete 89 before aaking the link, or create the link and let 90 the write coapletion reaove the created link. 91 93 He follow the protocol that at write coapletion, 93 •11 dependency linka are reaoved. To enaure the 94 correctneaβ of thiβ, wβ handle the next caβe 95 βpecially- 96 97 INTKANS and MODiriEDi Since the relevant aodification of 98 the antecedent cannot be aββuaed to be written to 99 diβk on coapletion of the current write, we cannot 100 allow the reaoval of the dependency link in thia 101 caae. Therefore, if we aade the deβired linkage, 103 then the link would need to be flagged βpecially 1-.3 ao that write-coapletion doea not reaove it. 104 Inatead, we elect not to aake the link (or wait 105 until IO coapletea in order to aake the requeated 106 link). 107 108 not INTKAMS and not HODIFIEDi The relevant aodification 109 haa already been reflected to diβk; therefore, 110 there ia no need to establish the link. 111 1131 " IF dependent iβ in βtate: 113 114 FLUSH or INTRANS: The dependent iβ about to be written. 115 So do not eatabliah a linkage until after the 116 write coapletea. (The aodification of the 117 dependent that we do not want to write to diak 118 ahead of the antecedent lβ yet to occur βo the Λ 119 current write of the dependent iβ benign) . cz: 130 CD CO 131 In addition to the above, these βpeclal conditiona need to 132 be handledi 133 124 antecedent GON i (i.e., aborted)! In thia inβtance, 135 there iβ no conβtralnt on the scheduling of co 136 a write for the dependent. So we return o 127 aucceaβ without creating the linkage. 138 l_l9 dependent GONE: If the antecedent haa not been aborted, 30 1-30 then any pending write for it auat be forced out. 131 The linkage itβelf iβ not aade, but the atteapt 132 lβ treated aa a failure unleaβ the antecedent write 133 lβ not waited for. » 134 135 The above rulea (for the abort caβeβ) could be applied In 136 reverβe, βo that the dependent GONE -> βucceββ and 137 antecedent GONE "> failure/wait. We have elected the 138 firat aet of rulea becauae dependent aodificationa 139 are typically expected to occur in the future while 140 antecedent aodificationa have already occurred and βo 141 can be fluβhed out right now. 142 143 dependent PRUNE: Thiβ atate auggeβtβ that there iβ an 144 urgency about βcheduling a diβk write for the 145 dependent -- either becauβe βone write waa 146 initiated for the dependent or ita dependents 1«7 and cannot coaplete unless the dependent write 1.8 itβelf coapletea. In βuch caβeβ, we would like 149 to enβure that any linka we create alβo 150 carry thiβ urgency forward to the new antecedenta 151 to be added. An alternative aay have been to 152 treat thiβ βiailarly to dependent being in 153 INTRANS or FLUSH βtateβ (and ao waiting for 154 dependent write to coaplete); but we can get 155 better write caching by aaking the link right now. 156 So, if we aake the link, we auat enaure that 157 the antecedent iβ in a PRUNE βtate aβ well. 158 159 160 1*1 , 162 int 163 dow_prder_nowait(dowld_t dep_id, dowid_t ant_id) 164 165 Establish the deaired dependency linkage. Do not block 166 — return with appropriate failure indication if the 167 dependency could not be eβtabliβhed either becauβe 168 the atatuβ of the antecdent or dependent DOM atructureβ 169 ' indicated IOa in progreaβ or becauβe of a potential O 170 dependency cycle or becauβe of lack of linkage reaourceβ. cz 171 co 172 Calling/Exit Statei 173 dow_autex ia held by caller. Never dropped. If the id'a are 174 not invalid, they have poβitive hold countβ. The following I 175 codeβ are returned by the function! 176 CO 177 βucceββful. 178 179 DOH ANT BUST antecdent iβ being written to diβk. however, 180 itβ atate iβ MODIFIED aβ well; βo it iβ not 181 poaβlble to deteraine whether thia new link 182 can be reaoved when the 10 coapletea. hence 183 the link lβ not created. ro 184 185 DON DEP BUST dependent ia being written to diβk. if the 186 link were created and control returned to the 187 caller, then caller'a aodification of the 188 dependent could get written to diak by the 189 10 that ia in progreaa. (Thia doea not natter 190 if the antecdent βtate iβ not MODIFIED). 198 DOW_CREATE_OK the deβired link can be aade. 199 200 DOWLINK MORES no reaourceβ were available to establish the 101 deβired linkage. 302 203 DOW DEP GONE the dependent haa been aborted, the correct 204 recovery ia for the antecdent to be flushed. CO m —I o V - 230 if (ant_βtate 0) [ __σ 231 /* 232 * debugging notet 233 * unless a dow_clearaodlfy operation was done on the 234 * ant_id, we expect that the antecedent cannot 5? 235 * have any dependents (since the last write coapletion 236 * auβt have reaoved all the dependentβ) . So we aay 237 * want to introduce βuch a debug aode βtate, βo that 238 * the following aaβert can be placedi 239 * 240 * ASSERT(DOW_M0DCLEARED(ant_id) || 241 » DOM_DEP_CNT(ant_ld) — 0); 242 */ 343 return 0; 244 1 245 ASSERT((an βtate t (DOW_MODIFIED|DOW_GONE) ) 1- 246 (DOW MODIFlEDIDOW GONE) ) ; 247 If (ant βtate — DOW MODINTRANS) { 248 / • 249 * cannot allow caller to proceed paat thia point 250 * to aodifying the dependent, until the current 251 * 10 coapletea. .353 * Alβo, βince the antecdent iβ INTRANS, we can 353 * aββert that it haβ not antecdenta. 254 V 355 ASSER (DOW_ANT_CNT(ant_id) — 0); 356 return (D0W_ANT_BUSY). 257 J elβe if (ant βtate s DOW GONE) ( 358 /* MOD βtate should be clear, aβ aββerted earlier. */ 359 If (ant_βtate t DOW INTRANS) ( 360 /* 361 * the linkage iβ peraiββible in thiβ caae (βo 362 * long aβ dependent iβ not I TRANS), βince the 363 * antecdent INTRANS occurred _after_ the laβt 264 * βetaod operation (thiβ can be inferred froa 365 * the fact that abort haβ to have coae between 266 * the βetaod and the current INTRANS). 267 * 368 * however, we will inatead aak the caller to retry 269 * after the antecdent IMTRANS haa cleared! at that £ 370 * point we can return βucceββ without creating the ςS 271 * link. _2 273 V ZZ] 273 ASSERT(DOW_ANT_CNT(ant_ld) -- 0); CZ . 274 return (DOW ANT_BUSY); → - 275 I {fl 276 return 0; j j » 277 ) i 278 /* ____] 379 * At thiβ point, the antecdent lβ either MODIFIED or INTRANS .—. 380 * but not both; and it iβ not in an aborted atate. § 281 */ r= 283 if ((dep βtate S (DOW PRUNE|D0W_INTRANS)) !- 0) ( m 283 * 384 If ((dep βtate 4 DOW_FLUSHINTRANS) 1- 0) ( —' 285 7* 386 * there ahould be no antecdenta aince 10 initiation 387 * ia being done or 10 la in progress 288 •/ 289 ASSERT(DOH_ANT_CNT(dep_ld) — 0); Ϊ90 return (DOW_DEP_BUSY); 291 ) 292 /* dβp_βtatβ aay be DOW SONE, DOW_IOSETUP */ 293 if (dep_βtate t DOW GONE) ( 294 /* 295 * PRUNE auβt be set, MOD auβt be clear. 296 •/ 397 ASSERT( (dep_state t DOW MODPRUNE) — DOW PRUNE) ; 398 /* 399 * if dependent iβ aborted (or being aborted), then we 300 * βrpect the caller to fluah the antecdent (and wait 301 * until the fluah coapletea) before proceeding. 302 •/ 303 return (DOW DEP GONE) / 304 J 305 return (DOW DEP PRUNE) ; )06 ) 307 308 ASSERT((dep_βtate ft (DOW_GONE|DOW_FLUSHINTRΛNS) ) ~ 0); 309 310 If ((llnkage err - linkage_detect(dep_id, ant ld)) I- DOW_CREATE_OK) { 311 313 /* 313 • either the deaired link ezlata (llnkage_err ■ - 0) , 314, • or either there ia known to be a cycle or a - IS • cycle ia poaaible but not certain. 31.6 317 318 ASSERT( (linkage_err — DOW_POS_C»CLE) || 319 (llnkage err — DOW_DEF_CYC E) jj (Hnkage_err — ■ 0)); return linkage_err; re alaoat ready to create the link. WI_INK_AVAIt,(2)) { return (DOWLINK_N0RES) ; dowllnk_makelink(dep_id, ant_ld) ); 337 int 338 dow_order(do id_t dep, dowid_t ant, uchar t dow_order_ lag) .339 Eatabliah the apecified ordering. dow_order_flag can be either 340 DOW_NO_WAIT, D0WJN0_RESWAIT, or OW_; 0 iapTiea that all waiting la 341 tolerable. 342 343 ■eturna 0 if aαcceaafnl; a non-xero error code if unaαcceaaful. 344 The non-zero error code ia the aaae aa that returned by 345 dow_order_no_wait. 346 347 Calling/Exit Statei 348 Ho apln locka ahould be held by caller, unleaa D0W_H0_WAIT ia 3 9 apecified (in which caae blocking will not occur). 356 V P1 caβe DOW POS CYCLE : • t02 /* 4u3 * potentially, there aay be a chain of 404 * dependency froa antecdent to dependent. 405 * fluah the antecedent. it. ■ V 436 cmn_err(CE_PANIC, 437 "unexpected return code 0x%x from * 43? "dow^rde^nowait -", err); 439 /* H0T8BACHED •/ 440 )/* switch •/ 441 DOW_HUTEX_LOCK(); 4. ) «4j 1 *@(l) kern : fa/dow_prune . c 1 . 3 ' SHeader: $ " <fa/dow. > <fa/t a s hler. h> <io/conf . h> <mem/kmeπι . h> <mem/page . h> <avc/clock . h> <uti J/cran_e_cr . h> <util/deb__g. h> <util/ghier. h> <u ti l/aysmacroβ_ f . h> <util/var. h> Notea t here are three fluah chainsi a leaf chain, on which a dow appea β if and only if it haa no antecdenta and it araat be executed aoon. a non-leaf "pruned" chain, on which a dow appeara if it aruat be executed aoon but auat wait beeauae it haβ one or wore antecdenta that axe valid (i.e, MODIFIED and not aborted) . an ageliβt, on which dowa appear if there lβ no urgency for executing then. runing xeferβ to an operation that identifiea all eaf level a tecdenta/grand-antecdentβ of a dowid and ueueβ thoa on the leaf fluβh chain and eiaultaneouβly runea any non-leaf antecdent that haβ not been pruned lready. he dow βubroutineβ arαβt work to enaure that once a ow ia on liβtβ 1 or 2, that any antecdent that ia dded to it foxceβ the pruning of the antecdent aa well. or thiβ purposei - dow srder auat prune newly created antecedenta and wove the dependent dow off the leaf chain if it happena to be on the leaf chain. Alternatively, aβ a βiaplification, a dowid that iβ aarked aβ being pruned doeβ not accuaulata any antecedenta (OR, if it ia pruned and iβ on the leaf chain?) 51 S3 To aaintain the invariant that a dow id being pruned 53 auβt be on the leaf chain if it haβ no antecdentβ, , 54 5S - dow_iodone will aove any dependent that haa been ' 56 pruned and now haa no antecdentβ to the leaf chain. '57 58 He expect that functionβ auch aβ dow_handle_a nc, 59 dow_handle_aaync, dow_abort, dow_order, dow_atrategy, SO and the dow_fluah_d aon (which walks the aged chain) .«1 will call dow_prune on a given dow id or itβ antecdenta. .63 -63 The functionβ that populate the leaf fluβh chain all follow • 6< the protocol of enquing lOSETUP iteaa to the head of the fluah 65 chain and non-lOSETUP iteaa to the tail of the fluβh chain. .66 Nobody ever walkβ the "pruned" non-leaf fluβh chain directly, ; 67 βo we nay be able to get rid of it and βave aoae overhead. ! 68 For the aoaent, we keep it aince it helpa debugging. CO 69 cz ..JO - 71 '.?3 int " ,73 prune_βearch(dowld_t x, int recur_depth) -74 Prune each antecedent of x that haa not already been pruned. t73 Any leaf antecedent (i.e., one that haβ no antecedenta) βhould CO * 76 be added to the leaf fluβh chain if it ia not already on the 3: • 77 leaf fluβh chain. If the xecurβion depth exceedβ HAX__.ECUR, -78 return 1, elβe return 0. If we get an indication that a exceeded, then we do not aark x aβ prunedi _» to the age chain for future pruning, with ately adjuated to cauae the fluah daeaon to 84 Calling/Exit Statei 65 dowjautex held by caller. Hill be held across thia function. -86 .91 eaarka> .88 Noraally we do not expect to exceed HAX__ECUK depth. If we do, .. : ? 96 then we handle the boundary caβe in a special way. All dow-ida 91 that are found at depth " MΛX_RECDI are put at the head of 93 the aged liat. Subβe4]uently aa we return to upper layera of 93 recurβion, the dependent dowβ are enqueued at the tail of the aged 94 liat. 95 / .96 int 97 pru_«^ϊ*ireiι(doi)_4_€ %&. -.aei-αT^ap h, tooolSan t jpruήasβlij 98 99 dowllnkid t llnkhead; 100 dowlinkid t l ink; 101 do id_t y; 103 int err; 103 104 ASSERT(DOH_MUTEX_OHNED()); 105 ASSERT(DOH_ANT_CNT(X) > 0)j 106 107 108 • Caller enaureβ that x ia not INTRANS, or PRUNE. 109 • Fuxtheraore βince , our pruning protocol iβ that 110 • FLUSH or lOSETUP or GOME —> PRUNE, X cannot be in 111 • FLUSH, lOSETUP, or GOME βtateβ either. 113 113 114 iis ASSERT( (DOH_STATE(x) t 116 ( DOH_PRUNE I DOH_FI_ϋSHI NTRANS | DOH 30NE | DOH_10SETUP ) ) 0); 117 β to the if well). 138 - return 1. ); — - 0); I 207 - After all of x'a antecdentβ have been viβited aβ above, check 208 the accuaulated err valuei 209 it 0, then recuraion depth reaained bounded, 210 - if pruneael , then aark x aa pruned and aove it to 211 the pruned liat, 212 - elβe return 0 indicating βucceββ (without touching x) 213 214 elβe, we auβt have reached the recurβion liait. βo, we auβt 215 - return the non-zero error code to our caller, recall 216 that z waa not affected, βo we aay either xeβet the tiaeβtaap on x to 0 only If pruneaelf ia true, or do βo aven if pruneaelf la falae -- it doeβ not aake auch difference. ink I- llnkhead) ( y - DOWLINK DOWID(llnk). link - DOWLΪNK_NEXT(llnk); if (DOW_STATE(y) __ DOW_PR0NE) I CHECK_ANTECDENTS_PRUNED(y)| continue; 248 ) 249 i f (err) ( 250 / • βoae antecedent of x waβ not fully pruned */ % TP n I ro 301 302 i f ( (DOW STATE(X ) t ( DOW PRUNE | DOW_INTRANS) ) I - 0 ) [ 303 if (DOW STATE( X ) t DOW_PRUNE) { 304 CHECK_ANTECDENTS_PRUNED(x ) ; 305 return ; 306 ) 307 ASSERT(DOW_ANT_CNT(x) — 0 ) ; 308 CHECK_NOT0N_ANY_FLUSHCHAIN(X); 309 DOW_STATE(xy I- DOW PRUNE; 310 return; 311 ) elβe if (DOW_ANT_CWT(x) —■ 0) ( 312 CHECK_ON_FLUSHCHAIN(X, DOW_AGED_FLUSHHEAD); 313 dow_fluah_remove(x); Ϊ14 DOW STATETX) I- DOW_PRUNE. 315 dow_fluah_talline(x, DOW_LEAF_FLUSHHEAD); 316 return; ERT((DOW_STATE(x) C (DOW_PRUNE|DOW_IOSETUP|DOW_FLUSHINTRANS)) — 0); DOWjSONKi dow j abort (which will βet DOWJSONE ) for "x" will prune all antecdentβ of "x" (and aay in fact be calling thia function) + we require that dow_abort do the pruning BEFORE + setting DOW GONE. ?; 330 * Subβequently, no antecdentβ will accuaulate. So we i . 331 * can treat DOW GONE aa a no operation. ^ 332 5? 333 334 CHECK_ON_FLUSHCHAIN(x, DOW_AGED FLUSHHEAD); .335 336 if (prune_βearch(x, 0, B TRUE) I- 0) ( 337 /• 338 * the top down pruning of x did not coaplete becauβe it reached 339 * the βet recurβion Halt on prune_βearch. thiβ ahould be a very 340 * rare occurrence, we can afford to be heavy handed In thiβ caae, 341 * and βo we will keep pruning aged dowβ off the aged liat 342 * until we have βucceββfully pruned x. 343 * NOTE that becauβe all anteedentβ of x that could not be pruned 344 * wound up on the aged liβt ahead of x, by pruning the aged liat 345 • in the noraal order repeatedly, we will cover thea efficiently 346 V 347 348 while ((DOW_STATE(x) S DOW_PRUNE) — 0) ( 349 « 350 • TODOl ADD DEBUO CODE TO DETECT INFINITE LOOPINβ RIB. 351 353 z - DOW_FLOSHNEXT(DOW_AGED_FLUSHHEAD); 253 ASSERT(Z I- DOW_AGED_FLOSHHEAD); 354 ASSERT((DOW_STATE(z) « 355 (DOW_PRϋNE|DOW_FLUSHIWTRANS|DOW_IOSETOP)) — 0); 356 if (DOW TIMESTAMP(z) <- (lbolt - DOW AGEJTIX) ) ( 357 If (DOW ANT CNT(z) ~ 0) [ 358 ow_ 1uβh_remove(z); 359 DOW_STATε7z) I- DOW_PRϋNE; dow fluβh_tailinβ(z, DOW_LEAF_FLOSHHEAD); (void) prune_βearch(z, 0, B TRDE) ; h_remove(z) ; h_tallinβ(z, DOW_AGED_FLUSHHEAD) ; CO z * 8 373 en - _r Λ ^ 1 lldent '(d(l)kern : fs/dow ut l . c 1.7' 2 lldent "SHeader: $' 3 * page o counter for each pagβ o that coapletea, where auch page* 51 * would have normally been aaaociated with dow structures but were 53 * not. due to dow resource exhaustion. 101 dow_io_utρp->diu_func - NULL; 102 dow_io_utpp->diu_chain - NULL; 103 If (DOW_IO_UTP_SV_BLKD()) [ 104 DOW_IO_OTP_SV_BROADCAST( ); ΪOS I 106 107 108 109 void 110 dow_arrajrinit(voi ) 111 Initialize all dow atructurea (including haah bucketa and 113 chain anchorβ for fluahchaina and freeliat) . 113 114 Calling/Exit Statai 115 None. Thia ia a ayβtew initialization routine. 116 11? aarkai 118 Muat call dowlink arrayinit before calling dow_arraylnlt. Elae 119 aaaertiona in dow_init (for the dependent and antecdent ιao linkheada) would trip. £ 121 / 8 122 void 123 (T 124 125 dowld_t i; 126 CΛ 127 dowlink_arrayinit()j 128 CHECK_DOWLINK_FREELlST( ); 129 130 DOW_FREE_SV_INlT( ); 30 131 DOW_IO_UTP_SV_I IT{); 132 DOW_MUTEX_INIT(); 133 DOW_FLUSH_EVEWr_INΪT(); IN? 134 3 135 for (i - 0; 1 < DOW_ARRΛTSIZE; i++) I 136 dow_init(i, 0, NULL, DOH_ISFUNC_NBLK)j 137 ] 138 dow_freecount - 0; 139 untracked_pagelo - 0; 140 for (1 - 0; i < DOW_TABLE_SIZE; i++) 141 dow_free(i); 142 J 143 144 for ( 1 - 0; i < MΛX_UNTRΛCI.ED_PAGES; i + + ) ( 145 dow_io_utp_tabl i J .dlu_bp - NULL; 146 dow_io_utp_tab| i J .diu_func - NULL; 147 dow_lo_utp_tab| i ) . lu_chaln - NULL; 148 149 150 ASSERT(dow_f reecount — DOW_TABLE_SIZE) ; 151 .J52 llfdef DEBUG 153 for (i - 0 1 < DOW TABLE SIZE; i++) ( 154 ASSERT(DOW_DEBUG_FLUSHID(i) — DOW FREEHEAD) ; 155 ASS ERT ( EMPTY_DOWLI NK LI ST ( DOWLI NK_ANT_LI NKH EAD ( i ))) ; 156 ASSERT(EMPTY_DOWLINK_LIST(DOWLINK_DEP_LINKHEAD(i) ) ) ; 157 CHECK_DOWLINK_CHAIN(DOWLINK_DEP_LINKHEAD(i) ) ; 158 CHECK_DOWLINK_CHAIN(DOWLINK_ANT_LINKHEAD(1) ) ; 159 ) 160 161 for (i - DOW_TABLE_SIZE; i < (DOW_TABLE_SIZE * DOW HASHWIDTH) ; i++) { > ASSERT(DOW_DEBUG_CHT(i) — 0); 1-3 ASSERT ( EMPTY DOW HASHLIS ( i ) ) ; 164 1 1*5 166 for (1 - (DOW_TABLE_SIZE + DOW HASHWIDTH) ; i < (DOW_TABLE_SIZE + DOW HASHWIDTH + 3); i++) ( %H ASSERT(DOW_DEBUG_CHT(i) — 0); li-9 ASSERT ( EMPTY DOW FLUSHLI S ( i ) ) ; 170 ".* 172 lendif 6 Hi CHECK DOW FREELIST ( ) ; erf. 174 ii:. 176 177 void 179 dow init(dowid_t z, long identl, long ldent2, uchar t type) 179 Initialize a dow atructure. identl and ident2 provide the 180 identity; type apecifiea whether thia ia to be a buffer, 181 page, or function dow. 182 183 Calling/Exit Statei 184 Noraally the dow_autez ahould be held by caller, ezcept when 185 called during a atea initialization. It ia the caller'a 18. reaponaibility to inaert the dow atructure on the correct lβ* haah chain. 188 189 ■eaar at 190 dow_inlt( ) ahould only be uaed aa an internal Interface. It 191 doea not require that a dow_hold be placed on z, nor doea it 193 place the dow_hold. That ia left to the caller(a). The validity 193 of z ia guaranteed by the dow_autez held by caller. 194 / 195 void 19$ do*_i t(aDwia_t *, low Mt tfim &mArWk*£ k&il 197 t 198 DOW FREENEXT(x) - x; 199 DOW FREEPREV(x) - x; 200 DOW_FL0SHNEXT(x) - x; 201 DOW FLUSHPREV(X ) 202 DOW HOLD(x ) - 0 ; 203 DOH LEVEL(x ) - 0 ; 204 DOW_DEP_CNT (x ) - 0 ; 205 DOW_ANT_CNT(x ) - 0 ; 206 DOW_TIMESTAMP(X) - INT MAX; 307 DOW_SV_INIT(x ) ; 208 DOH_STATE(x ) - 0; 209 DOH TYPE(X) - type; 210 if Ttype — DOH_ISBUFFER) ( 211 DOH DEV(x) - (dev_t)identl; 312 DOW BLKNO(x) - (int)ident2; 313 DOH BSIZE(X) - 0; 314 DOH_MOD_LOCK(x) - 0; 215 316 1 else if (type — DOW_ISPAGE) { 317 DOH_VP(x) - (vnode_t *)identl; 318 DOH_OFFSET(x) - (of _t)ident3; Ui 21$ DOH_MOD_LOCK(x) - 0; OO 230 331 ) else ( 332 DOH FtJNC(x) - (void (*)())identl; 333 DOH ARGP(x) - (void *)ident3; 334 DOW HOD_L0CK(x) - 0; ^ SI "2256 D1OH BP(x) - NULL; jri 227 DOW_DEBUG_IODONE_INIT(x); a2 β /• . . 229 * Thia assertion would trip unless we called j5 230 • dowlink_array init before dow_arrayinlt waa called, p= 231 * during initialisation. He expect the aaβertion fTI 232 * to hold subsequently, when dow_t'a are recycled, r 233 •/ ■S3 234 llfdef DEBUG. 235 if (X < DOH_TΛBLE_SIZE) J 236 ASSERT(EMPτ7_DOHLINK_LIST(DOHLINK_ANT_LINKHEAD(x) ) ) ; 237 ASSERT(EMPTY_DOWLINK_LIST(DOHLINK_DEP_LINKHEAD(x) ) ) ; 338 ASSERT(DOHLINK_LINKS~SΛNE(DOHLINK_ANT~LINKHEAD(X) ) ) ; 339 ASSERT(DOWLINK_LINKS_SANE(DOHLINK_DEP~LINKHEΛD(x) ) ) ; 340 J 241 lendlf 343 343 DOH_DEBϋβ_INIT(x); 244 345 246 llfdef DEBUG 350 • dow_free_badinit(dowid_t id) 301 302 Calling/Ezit Statei 303 dow_autez held by caller, and held on return. The function 304 doea not block or drop the lock. 305 306 * PERΠ 307 • Convert to a aacro. Preferrably aaaeabler aacro. 308 * Collect atata on how good a hash function we really have. 309 */ 310 void 311 313 313 ASSERT(DOW_MUTEX_OWNED< ) ); 314 ASSERT(VALID_DOWID(id)); 31S ASSER ( VALID HASH BϋCKE ( hbucket) ) ; 316 DOW HASHNEXT( id) • DOH_HASHNEXT( hbucket) ; 317 DOW HASHPREV( id) - hbucket; £ 318 DOW_HASHPREV(DOW_HASHNEXT( ld) ) - id; s 319 DOW HASHNEXT(hbucket) - id; 330 DOW DEBOG HASHENTER( ld, hbucket) ; 331 333 ) 333 void 324 dow_reahaah(dowid_t id, dowidjt hbucket) CO 325 Reaove dow "id" froa ita haah chain. 326 337 Calling/Ezit Statei 328 dow_autez held by caller, and held on return, The function 30 329 doea not block or drop the lock. 330 331 PERFi ro. Preferrably aaaeabler aacro. 337 ASSERT(DOW_MϋTEX_OWNED( ) ); 338 ASSERT(VALID_DOHID(ld) ); 339 CHECK HASH(ld); 340 DOH_HASHNEXT(DOW_HASHPREV(id)) - DOH RASHNEXT(id) ; 341 DOH_HASHPREV(DOW_HASHNEXT(id)) - DOH_HASHPREV(id); 342 DOH_DEBUG_HASHLEAVE(id) ; 343 DOH HASHINVAL(id); 344 J 345 /• 346 * * dowidjt 347 * * dow_alloc(void) 348 * Allocate a dow atructure froa the freeliat. 349 350 • Calling/Ezit Statei 351. The doa autez is acquired and released within. The function does 352 not block. 353 354 Keaarkei 355 If later we iapleaent dow reaervationβ, then a flag could be 356 uaed to specify reservation. All the real work iβ done by 357 dow_alloc_l. 358 359 PElFi both dowjalloc and dow_alloc_l are good candidates for inlining. 350 361 362 dowid t 263 :.S64 i 355 dowid t id; 366 367 DOW_MUTEX_L0CK ( ) ; id - dow_alloc_l ( ) > DOW_HU TEX JNLOCK ( ) ; return ( id ) ; dowidjt dow_alloc_l( oid) Allocate a dow atructure froa the freelist. Calling/Ezit Statei The doajautez iβ held at entry and exit, and is not reacquired. The function does not block. Reaarkat 384 If later we iapleaent dow reβervationβ, then a flag could be 385 uaed to specify reservation. Once dow βtructureβ are reserved, 386 the caller can expect aucceββful yet non-blocking return. 387 / 388 dowid t 389 SO»_aΣlo_._ϊ(voi<!^ 390 { 3^1 dowid_t freefirst; 393 398 ASSERT ( I EMPTY_DOW_FREELIST (DOW_FREEHEAD) ) ; 399 - - (dow_f reecount) ; 400 freef irst - DOW_FREENEXT (DOW_FREEHEAD) ; 401 DOW_FREENEXT(DOW_FREEHEAD) - DOW FREENEXT( eefirβt); 403 403 llfdef DEBUG 404 /• 405 * in DEBUG aode, we aaintain the freelist doubly linked. 406 ' */ 407 ASSERT(DOH_FREEPREV(DOH_FREENEXT(freefirβt)) -- freefirst); 406 DOW_FREEPREV(DOW_FREENEXT(freefirβt)) - DOW FREEHEAD; 409 lendlf 410 411 DOH_DEBUG_FREELEAVE(freefiret); 413 return(freefirst); 413 ) 414 415 416 void 417 dow_free(dowidjt z) 418 Insert dowid "z" at the head of the dow free liβt. Buap 419 up the dow_freecount. 430 431 Calling Exit Statei 433 dow_autez held by caller, returned held. Nos-blocking function. 433 424 leaarkβt 425 Caller haa the reβponalbility of dequeuing z froa itβ haβh and < A) 426 fluah chaina. \ »37 438 PERFl 439 Convert to a aacro. 430 431 void 433 * > * ■ * ' 433 ( 434 ASSERT(DOW HOLD(X) -- 0); 435 ASSERT(DOH >BP_CWr(x) — 0); 436 ASSERT(DOH_ANT~CNT(x) — » 0); 437 ASSERT(DOH_MOD_L0CK(X) — 0); 438 ASSERT( IDOW_SV~BLKD(X)); 439 440 DOW FREENEXT(X) - DOH_FREENEXT(DOH_FREEHEAD); 441 443 llfdef DEBUG 443 DOW FREEPREV(x) - DOW FREEHEAD; 444 DOW_FREEPREV(DOW_FREENEXT(x)) - x; 445 lendlf 446 447 DOW FREENEXT(DOW FREEHEAD) - X ; 448 ++dow_ reecount; 449 if (DOH_FREE_SV_BLKD( ) ) { 450 DOH FREE SV BROADCAST ( ) ; #45 Calling/Exit Statei Called and returns with dow autex held. FESFi May be converted to a aacro? He ahould put in aeveral debug checks for now, and convert it to a aacro with these checka reaoved, after the code iβ shown to hold up well. dowld t dowid_t haoh_bucketid; dowid_t 1; ASSERT(DOW_MUTEX_OWNED() ); 481 483 haβh_bucketld - DOW_RASHBUC__ET( identl, IdentS); 483 484 ASSERT(DOH_HASHLINKS_SANE(haβh_bucketid) ) ; 485 ASSERT(VALID_HASH_BUCKET(haβh_bucketid) ) ; 486 4,87 1 - DOW_HASHNEXT(haβh_bUCketid); 4%β while (i I- hash_bucketid) ( 439 490 ASSERT { VALI D_DOHI D ( i ) ) ; 491 ΛSSERT(D0H_DEBUG_HASHID(1) — haβh bucketid) ; 492 ASSERT (D0H_HASHL1NKS_SANE( i) ) ; 493 ASSERT((DOW_STATE(i) t DOW GONE) -- 0); .94 If ((DOW_IDENTl(i) — identl) tt (D0H_IDENT2(1) — • identS)) { 495 DOW_CHEAP_HO D( 1 ) ; 496 return(l); 497 J 498 i - DOW HASHNEXT(i); 499 ); goo return(DOW BADID); 501 ) 503 503 504 dowid_t 505 dow_lookup_page(vnode_t *vp, off_t offaet) 506 Search for a page dow correaponding to the apecified 507 identity <vp, offaet>. If one iβ found, return with 508 a hold on the dowld. If none ia found, return an invalid 509 dowid (i.e., DOW_BADID) . 510 511 Calling/Ezit βtatei 512 Called and returna with dow autez held. 515 May be converted to a aacro? He ahould put in aeveral debug 51$ cheeks for now, aad convert it to a aacro with theae cheoka 517 reaoved, af er the code ia ahown to hold up well. 518 519 520 dowid 521 522 523 dowid_t haahjbucketid; 524 dowid t i; en ~-l 525 526 ASSERT(D0W_MUTEX_0WNED( )); 1 527 528 hash_bucketid - D0W_HASHBϋCKET( (long)vp, offβet); 30 529 530 ASSERT(DOW_HASH INKS_SANE(hash_buclcetid)) ; 531 ASSERT(VAI.7D_HASH_BαCKET(haβh_bucketld)); ro 532 546 )< 547 return(D0H_BADID); 548 549 550 • 560 aod f cat on nterlock. 561 562 Reaarkai 563 Swapping ia inhibited aa a deadlock avoidance aeaβure, aince 664 while Modifying the data the lwp ia either holding a buffer, -.65 if the dow corxeaponda to a buf er, or i 'a holding the dow 566 aodification interlock, if the dow corresponds to a page. d)) ) -- DOW_ISPAGE || DOW_TYPE(id) -- DOW ISBUFFER); DOW ISBUFFER) k(id); ro 581 582 void 583 dow_atart__od_rdlock(dowid_t id) 584 Acquire the ■odification interlock on a dow atructure, in read 585 ■ode. Thia ia a pβeudo reader-writer lock, whoae intent ia 586 to enaure that if the dow atructure carriea the DOW_MODIFIED 587 atate, then the real page la aodified aa well. 508 Called only for page dowa. Not needed for buffer dowa, because 589 buffera are uniquely owned, and writea on buffera alwaya coaplete. 690 Read aode lockera are thoae that intend to βet the HOD atate. 591 592 Calling/Exit Statei 593 None. The caller ahould be prepeared to block. 594 / 595 void 596 do*_«tϊt'iaoa_tdi<.o .a »id_C &f 597 ι 598 dowid_t hbucket; 599 long identl, ldent2; 600 601 if ( IVALlD DOWID(ld) || (D0W_STATE(Id) t DOW GONE)) 603 return; . 637 638 Calling/Ezit Statei 639 dow_autez held by caller. The caller ahould be prepeared 640 to block, however. 645 dowid_t hbucket; 646 long identl, IdentJ; 647 648 if (DOH_STATE(id) t DOW GONE) 649 return; 650 (-D); 701 ident2 < DOH_IDENT3(id); 702 hbucket DOW_HASHB0CKET(identl, identS); 703 llfdef DEBUG 704 ΛSSERT(DOW_DEBUG_HASHΪD(id) -- hbucket); 705 lendlf 706 if (DOH_SV_BLKD(hbucket) ) 707 DOH_SV_BROΛDCAST(hbucket) ; 708 return; 709 ) 710 711 /• 713 oid 713 dow_clear_aodlock_l(dowidjt id) 714 Clear the aodification interlock on a page dow and wakeup 715 all waitera. It ia expected that the caller will reaet the 716 DOW__STATE to DOHJSOHE before dropping the dow_autex, which en 717 cz ia held on entry to thia function. cσ 718 en 719 730 Calling Exit Statei 731 dow_autez held by caller. 732 733 void en 734 735 ( 726 dowid_t hbucket; S3 727 long identl, ldent2; 728 729 ASSERT(VALID_DOHID(id)); 730 If (DOH_STATE(id) t DOHjGONE) 731 return; 732 ASSERT(DOW_TTPE(id) — D0H_1SPAGE); 733 identl - DOW IDENTl(ld); '734 ident2 - DOH_IDENT2(id); 735 hbucket - DOW_HASHB0CKET{Identl, ident2); 736 lifdef DEBUG 749 • dow_aetβod(dowid_t id, clock t fluβhdelta) 750 • Set the MODIFY atate in the dow, and releaae the aodification interlock. DOH STATE(id) I- DOW MODIFIED; dow_βtate - DOW_STATE(ld) ; flush stamp - (lbolt - (FLUSHDELTAMAX - fluahdelta)); 795 796 /* 797 * rire the dow ifi 798 * - no antecdenta, and, not already being written/executed, 799 * and, 800 * - type "- function, or 801 - pruned (though how can thiβ be?) 802 803 804 if {(DOW_ANT_CNT(id) — ■ 0) tt ( (dow βtate t DOH FLUSH I NTRANS ) — 0)) ( 805 if (DOH TΪPE(id) t DOH ISFUNC) ( 806 807 do _f luβh_remove( Id) ; 808 DOW STATE(id) I- (DOH_FLUSH|DOH_PRUNE); 809 DOH_TIMESTAMP(id) - INT MAX; 810 dow_proceββ_leaf_func(id, NULL); 811 DOH MUTEX UNLOCK ( ) ; 812 return; 813 -1 I en oO 1 F ro 02 846 * The dowid ataya on whichever fluβh chain it happenβ to be onl 847 •/ 848 if (DOH TYPE(id) — DOH_ISPAGE) I 849 dow_drop_modloc_t_l ( id ) ; 850 ) 851 852 DOH MUTEX UNLOCK( ) i 853 if ((DOW TYPE(id) t DOW ISFUNC) 0) 854 SWAP ENABLEO; 855 return; 856 I 837 838 / 659 void 860 dow_rele(dowidjt id) 861 Release the hold on a dow atructure. lookup or ure and to 899 /• 900 * if the hold ia poaitive, or there are any linka 901 * (antecdent/dependent) , don't free the dow. 902 * 903 * PEIFi Collapse the three testa into one? 904 •/ 905 906 if (DOH_HOLD(id) > 0 || DOW_AN _CNT(id) > 0 || 907 DOW~DEP_CNT(ld) > 0) { 908 return; 909 1 910 /* 911 * hold -- 0, no antecdent/dependent links. Free the dow 913 * if it iβ not being fluβhed/written. Alternatively, if 913 * the dow iβ a function whoβe execution iβ deferred to the 914 * fluβh deaon, we cannot reaove it. 915 •/ 916 if (DOH_STATE( id) t (DOH_FLUSHIWTRANS |DOH_IOSETOP) ) ( 917 return; CSi lβ 1 C 919 /• S5 -920 • function types recieve a slightly different treataentt —4) 931 * for a "■edified" function dow, we auβt either absorb the —j '923 * responsibility of executing the function here itaelf or *_ j 933 * leave it to the fluβh deaon (<■> verify that the dow iβ on <~ r * 924 • the leaf liβt and that it iβ in PRUHB state); the dow, in Λ ._ 935 • thiβ caβe should not be freed without executing the function. j-f_j X 926 * A function dow that doeβ not have the aodified βtate, on rπ 92 • the other hand, auβt be assuaed to have been "olear-aodified" X . 930 * in which eaβe, dow_rβlβ can treat it basically aβ free-able. 30 939 * See dlβcuββion in dow_proceββ_leaf_func(). ^ 930 */ rπ 31 932 if ((DOW YPE(id) t DOW ISFUNC) tt -22 33 ((DOW_STATE(ld) t (DOW MODIFIED | DOW GONE)) — DOW MODIFIED)) ( ,934 CHECK_ON_FLUSHCHAIN(ld, DOW LEΛF FLUSHHEAD); 935 return; 936 ) "937 938 /* 939 * At thiβ point, thiβ dow iβ a gonerI He should be able 940 • to aaaert that if the CORE βtate ia ON, then the dow 941 * cannot be on any haah chainβ. 942 •/ 943 944 dow_f luβh_remove( id) i 945 if ( (DOW_STATE( id) t DOH_GONE) — 0 ) ( 946 dow_remhash( ld) ; 947 if (DOH_TΪPE( id) — DOW ISPAGE) { 948 VN SOFTRELE(DOH_Vp( id) ) ; 949 ) 950 ) elβe ( 951 CHECK_HΛSH_REMOVED(id); 953 953 do _free(id) ; 954 return; 955 956 fc* void 958 dow_intranβ_wait(dowid_t id) 959 Hait for any current 10 sequence to coaplete. Thia aay not necessarily 960 require that an IO auat occur -- juat that dow_iodone proceaaing 961 ia performed on the id. 963 963 Renarks> DOHJGONE caae, assuning that guarantee that do _iodone will | DOH IOSETOP ) ) ( loua dow_handle_aaync 987 Calling/Ezit Statei 988 Caller holdβ the dow autex, and ia prepared to block. 989 990 leaarkβt 991 If dow_handle_aaync could not initiate a pruning operation due 993 to an intranait 10 when it got called, then it will aet the 993 atate to PRUNE'd -- cauaing dow_iodone( ) to reaubnit the id for 994 a quick fluah. In that caae, dow_iowait aay need to wait twicei 995 the firat tine to perait the INTRAMS atate to clear, and the 996 second tiae, for the resubaitted 10 to coaplete. 997 998 No special handling ia needed for the D0HJS0NE caae, aββualng that 999 (a) DOH_FLUSH/DOH_IOSETUP/DOH_INTI_ANS all guarantee that dow_iodone 1000 will be perforaed for the id. 1001 * (b) If the id iβ not in one of theβe βtateβ, then D0HJ40DIFIED auβt 1002 • iaply IDOHJGONE, ao no additional checking iβ needed. 1003 • 1004 V 1005 void 1006 d. _i«-«i ._i.d6#i id) 1007 i 1008 ASSERT(DOH_MUTEX_OHNED()); 1009 ASSERT(DOH_HO D(id) > 0); 1010 if (DOH_STATE(id) t (DOH F USHINTRANS | DOH I0SET0P)) { 1011 if ((DOH_STATE(id) t DOH MODINTRANS) I- DOW MODINTRANS) ( 1012 DOH SV HAIT(id); 1013 return; 1014 I 1015 /• 1016 * elβ t MODIFIED and INTRANS. In thiβ caβe, we may need to 1017 * wait a βecond tiae (depending on whether PRUNE iβ 101Θ * turned ON or not). 1019 V 1020 if ((DOH STATE(id) S DOH_PRUNE) — 0) ( 8 1021 DOH_SV_HAIT(id)ι 1022 return; IO coapletea, we will reteβt the βtate en tiae. 1032 if ( (DOH STATE(id) t (DOH FLOSHI NTRANS | DOH IOSETϋP ) ) | | 1033 ( (DOH STATE( id) « DOH_MODPRUNE) — DOH MODPRONE) ) ( en 1034 DOH_SV_HAIT ( id ) I 1035 return; 1036 ) 1037 /• 1038 • there iβ no IO that the caller ia intereated in waiting for. 1039 •/ 1040 DOH_MtTTE___ϋNI0CK(); 1041 return; 1042 1043 1044 1045 τoid 1046 dow_lowait(dowidjt id) 1047 Hait for any initiated IO on the dow to finiβh, including IO that 1048 aay not be currently underway but would happen aoon, anyway, due 1049 to the βetting of the PRUNE βtate. 1050 1060 ASSERT(KS_HO D0LOCKS()); lq€1 DOH_MUTEX_I_OCI.(); 1062 dow_iowait_l(id); /* dropa the autex */ 1063 return; 1054 1 I CD en en 2_? 30 ro 1 lldent *(d(l)kern:fs/dowllnk_utll.c 1.3* 3 lident 'SHeader: S* 3 4 linclude <fs/dow.h> 5 linclude <fs/fs_hier.h> 6 linclude <lo/conf.h> 7 llnclude < e /k e .h> 8 linclude <mem/pag . h> 9 linclude <βvc/clock . > 10 linclude <util/c n_err.h> 11 linclude <utll/debug.h> 13 linclude <util/jJ_ier./> 13 linclude <utll/βys acros_f.h> 14 linclude <utll/var.h> 15 16 do lin _t dow_link_tablDOHLINK_ARRΛYSIZE. ; 17 18 /* 19 • »oid 30 * dowlink_arrayiι_lt(τoid) 31 * Initialize the array of dow link structures. 33 • 33 * Calling Exit Statei 34 • Nome. 35 »/ I 36 ■ ^ 37 void ~ ^» 33β9 ( i &M M ' 30 do linkid_t i; 31 33 for (i - 0; 1 < (DOHLINK_ARRAYSIZE). i++) ( 33 ,dowlink_init(i, T, D0H_BADID); 34 DOHI_IWE_DEBϋG_INIT(i. i); "35 ) 36 DOHLIHK_rRBB_SV_IMIT(); 31 dowl lnk_f reecount - 0; 38 for (i - DOHLINK_TABLE_BASE; 39 i < (__OHMNK_TAB__E_BASE + DOWLI NK M AX FREE ) ; i++) { 40 DOHLINK_DEBOG_INIT(i, DOWLI NI._BADID) ; 41 dowlink free(i); 4 2 3 A'SSERT(dowlink_ reecount -- UυHLINK_MAXFREE); 44 ) 4 45 6 /* 47 • τoid 48 • dowli_ιk_init(dowlinkid_t link, dowlinkid_t inveraelink, dowidjt id) 49 * Initialise the dow link upon allocation. If link X were to 50 * be uaed to apecify an antecedence/dependence relationship 51 * between two dow_idβ A and B, auch that X ia on the appropriate 53 * link chain for A, then, 53 • inveraelink identifiea the correaponding link on B'a 54 * link chain that identifiea the dowid A, ' ' 64 DOHLINK_NEXT( link) - link; * 65 DOHLINK PREV( link) - link; - ' £6 DOHLIHK INVERSE( llnk) - inversellnk; . - 67 DOHLINK DOHID( link) - id; ■ •.68 ) s ' * _»-• ' »70 llfdef DEBUG : -71 → 73 /• < 73 " * void m I 74 • dowlink_debug_init(dowlinkidJt link, dowllnkid t head) en — '75 • Initialize debugging support fielda in a link that will oO 76 • be inserted on a linkchain headed by "head", m °° .77 • ^ ' 78 • Call-ing/Eilt Statei _30 79 * dow_nutex held by caller. ?≡ TBO V m 91 3 83 void S3 83 doWtink_debug it_lt(dσiliHkid_t link, owlinki^ h*βd) 84 ( 85 DOHLINK_DEB0G_I_HEAD(liπk) - head; • 86 DOHLINI__DEBUβ_CNT( link) - 0 ; 87 I 88 89 /* . . 101 DOHLINK_INVERSE(link) - DOWLINK BADID; 103 DOWLINK_DOHID(link) - DOH BADID; 103 } 104 lendlf 111 Calling/Exit Statei 113 dow__mtex ia held by caller. 113 114 Rewarki 115 The freeliat ia Maintained doubly linked only under DEBUG 116 coapile option. Therefore, the following aaaert ia not valid 117 except in DEBUG coapllei 118 ■ ASSERT(DOHLIMK_LIMKS_SANE(DOm.IH _raEEBEAI>)) CD 119 130 dowlinkid_t 131 133 { 133 dowlinkid_t freefirst; en 134 on 135 ASSERT ( DOH I NR_LI NKS SANE ( DOWLI NK FREEHEAD ) ) ; 136 if (dowlink_f reecount — 0) I I 137 ASSERT ( EMPTΪ_DOWLINK_ IST ( DOHt.1 NK_FREEHEAD ) ) ; 138 return(DOH INK_BADID) ; 3D 139 ) 130 ASSERT ( I EMPTY_DOHLINK_LI ST ( DOHLI NK FREEHEAD) ) ; 131 - - (dowlink_f reecount) ; en 133 freefirst - DOWLI K_NEXT( DOHLI NK FREEHEAD ) ; 133 ASSERT(VALID_DOHLINK_ID( freefirst)); 134 DOWLI NK_NEXT( DOWLI NK FREEHEAD) - DOHLI NK_NEXT(f reef irβt) ; 135 llfdef DEBUG 136 DOWLI NK_PREV( DOWLI NK_NEXT( freefirst)) - DOWLI NK FREEHEAD; 137 lendlf 138 DOWLI K_DEBUG_FREELEAVE(f reef lrβt) ; 139 140 llfdef DEBUG 141 DOWLINK_PREV( freefirst) - (-8877); 143 DOHLINK_NEXT( freefirst) - (-7788); 143 DOHLINK_IHVERSE(freefirst) - (-6655); 144 DOWLINK_DOWID( freefirst) - (-5566); 145 lendlf 146 DOHLINK_DEBUG_INIT(f ree irβt, DOHLI NK BADID) ; 147 148 return (f reef lrβt); 149 ) 150 151 152 dowllnkid_t 153 dowlink_free(void) 154 Free a link atructure. 15!> 156 Calling/Exit Statei 157- dow_autex ia held by caller. l r >8 159 Beaarki lfiO The freeliat ia Maintained doubly linked only under DEBUG 151 eoapile option. Therefore, the following aaaert ia not valid 162 except in DEBUG eoapilei -is* ASSERT(DOHI,I_I _I,IHK9_3AHE(DOW INK_rREEHEAD) ) •16* 16S 166 void 167 ti 168 ( 169 ASSERT(VALID_DOWLINK_ID(llπk) ) ; •170 DOWLINK NEXT ( link) - DOWLI NK_NEXT( DOWLINK FREEHEAD) ; 171 173 ll fdef DEBUG 173 DOWLI K_PREV( link ) - DOWLI K FREEHEAD; 174 DOWLINK_PREV(DOWLINK_NEXT ( link) ) - link ; 175 lendlf en -O 176 O 177 DOWLI K_NEXT(DOWLI K_FREEHEAD) - link; 178 ++dowllnk_freecount; 179 if (DOWLINK_FREE_SV_BLKD()) ( 30 180 DOWLINK_FREE_SV_BROADCAST() ; lβϊ ) 382 DOWLINK_FREE_BADINlT(link); f\_> 183 DOWLINK_DEBUG_FREEENTER(link) ; 184 185 186 187 • void 188 • dowlink_addlink(dowlinkid_t newlink, dowllnkid_t headlink) 189 • Add the link, newlink, to the dow link chain anchored 190 • at headlink. 198 ASSERT(VALID_DOWLINK_ID(newlink) ) ; 199 ASSERT(VALID_DOWLINK HEAD(headlink) ) ; 200 DOWLINK_NEXτ7newlink! - DOWLINK_NEXT{headlIn ) ; 301 DOWLINK_PREV(newlink) - headlink; 203 DOWLINK_NEXT(headlink) - newlink; 303 DOWLINK_PREV(DOWLINK_NEXT(newlink)) - newlink; 304 DOWLINK_DEBUG_ENTER(newlink, headlink); 305 ) 306 307 /• 308 void 309 dowlink_aublink(dowllnkld_t link) 310 Reaove the apecified link froa ita link chain. 245 ASSERT(DOWLINK_AVAIL(2)); 246 ASSERT(VALID_DOWID(dep_id)); 247 ASSERT(VALID_DO«ID(ant_id)); 248 249 if (DOW_DEP_CNT(ant_ld) >- DOW_DEP_MAX) ( 350 return (DθW_MAJ._DEPCNT) ; 351 ) elβe if (DOW_ANT_CNT(dep_id) >- DOW_ANT_MAX) ( 253 return (DOW_MAX_ANTCN ); 253 ) 354 355 dep head - DOWLINK_ANT_LINKHEAD(dep_id) ; 256 ant_head - DOWLINK_DEP_LINKHEAD(ant_id); 357 358 dlink - dowlink_alloc( ); 359 alink - dowlink_alloc( ); JfiO 361 dowllnk_init(alink, dlink, dep_id); 262 dowlink_lnlt(dlink, alink, ant_ld); 263 264 dowlink_addllnk(allnk, ant head); 265 dowlink_addlink(dllnk, dep head); 266 ' 2C7 4+DOW_DEP_CNT(ant_id); 268 ++DOW_AiNT_CNT(dep_id); 269 CO 270 ASSERT(DOWLINK_ILINK_SANE(dllnk)); m 371 ∑ 272 llfdef DEBUG ____ 273 ( ^ . 314 ASSERT( (dep id ~ DOWLINK_DEBUG_MYDOW(dlink) ) tt 375 (ant_id ~ DOWLINK_DEB0G_MYDOW(alink)) tt rπ -o 2 6 (ant_head — DOWLINK_DEBUG_LHEAD(alink)) tt ξ ^ 31 (dep_head — ■ DOWLINK_DEBUG~LBBAD(dllnk)) tt f^ ) 378 (DOWLINK_DEBOG_CNT(an _head) —- DOW_DEP_CNT(ant_ld)) tt rη 279 (DOWLINK_DEBOG_CNT(dep~head) —■ DOW_ANT_CNT(dep_id)) ); ^ 280 1 39 201 lendlf Jie: 282 return(O); m 3^3 ) £ .264 2U5 /« 286 * void 287 * dowlink_breaklink(alink, dependent, antecdent) 313 llfdef DEBUG 314 I 315 dowllnkid t dep head - DOWLINK_ANT_LINKHEAD(dep_id) ; 316 dowlinkid t ant_head - DOWLINK DEP LINKHEAD(ant id); 317 318 ASSERT ( (dep ^ ld -- DOWLINK DEBUG MYDOW(dlink) ) tt (tntj — DOWLINK_DEBUG_MYDOW(allnk)) tt (ant head — DOWLINK_DEB0G_LHEAD(allnk)) tt (dep head « DOWLINK_DEBUG_LHEAD(dlink) ) tt (DOWLINK_DEB«JG_CWT(ant_head) — DOW_DEP_CNT(ant_id) ) tt ( DOWLI K_DEBOG_CNT( ep head) — DOW ANT_CNT ( ep_i ) ) ); 1 dowlink βubl in (alink); dowlink sublink(dlink); - - ( DOW ANT CNT ( dep i ) ) ; - - ( DOW_DEP_CN ( ant_ld ) ) ; dowlink_free(alink); dowlink_free(dllnk); 351 ( 352 dowlinkid_t link, dep_ant_lhead, dep_dep_lhead; 353 354 /• 355 • firβt, we βearch the antecdent liβt of the dependent to aeβ 356 * whether the deaired link exiata already (if ao, return 0). 357 */ 158 359 link - dep_ant_lhead - DOWLINK_ANT_LINKHEAD(dep_id); 350 361 ASSERT((DOW_ANT_CNT(dep_id) — 0) || 363 IEMPTY_DOWLINK_LIST(dep_ant_lhead)); '363 ASSERT((DOW_ANT_CNT(dep_id) > 0) | | 364 EMPTY_DOWLINK_LIST(dep_ant_lhead)); 365 CHECK_DOWLINR_CHAIN{dep_ant_l__ead); 366 367 while (.(lin - DOWLINK_NEXT(link)) I- dep_ant_lhead) ( ^2 368 §5 369 if (DOWLINK_DOWID(link) — ant id) ( <J\ 370 CHECK_DOW_LINKAGE(link); —j "371 return 0; cΞ 3/3 1 ^ 373 ) en ' * zz - 375 /• rπ 376 * the deaired link does not yet exiat. check whether it can be → -C 377 • created. l 379 V C l 379 if (DOW_DEP_CNT(dep_id) — 0 || DOW_ANT_CNT(ant_ld) — 0) ( Wr ? 39 80 1 /* * there ia no poaaibility of a cycle. O? 333 V 383 return (DOW_CREATE_0K)i 384 ) 395 link - dep_dep_lhead - DOWLINK_DEP_LINKHEAD(deρ_ld) ; 396 ASSERT( l EMPTY_DOWLINK_LIST(dep_dep_lhead ) ) ; 3S7 CHECK DOWLINK CHAIN(dep dep lhead) ; 398 399 while ( ( link - DOWLINK_NEXT( link) ) I - dep dep l head ) ( 400 401 if (DOWLINK_DOWID(link) -- ant_ld) [ 403 CHECK_DOW_LINKAGE(link); 403 return DOW_DEF_CYCLE; 404 ) 405 ) 406 407 , return DOW_POS_CYCLE; 408 ) ro

Claims: CLAIMS 1. An ordering subsystem for controlling the order of operations in a computer system, the computer system having a first unit and a second unit for files, having a file management subsystem for controlling operations for files, said file management subsystem specifying operations for files in response to new requests where a sequence of requests for said operations is represented by the requests Rl, R2, ..., Rr and where the requests for said operations in said sequence have order dependencies Dl, D2, ..., Dd where r and d are integers, said order dependencies constraining the order for carrying out said operations, said ordering subsystem including, an ordering store for storing a plurality of entries, each of said entries containing an operation type identifying one of said operations for files, at least one of said entries at some time also containing a link which links said entry to another of said entries, said link specifying an order for carrying out said operations in said linked entries, said entries and said links defining a partially ordered acyclic graph, add means for adding entries to the ordering store by processing said new requests to identify one or more common operations COO, CO1, ... , COco, each of said common operations identifying an operation requested by one or more of the requests Rl, R2, ..., Rr, where said common operations have common order dependencies CDO, CD1, ..., CDcd that preserve the order dependencies Dl, D2, ..., Dd between the operations in the requests, and where co and cd are integers, execution means for executing said one or more common operations COO, CO1, .... COco responsive to the entries in the ordering store, and delete means for deleting entries from the ordering store. 2. The ordering subsystem of Claim 1 wherein said add means includes, dow create means for providing one or more of said entries as operation entries for identifying common operations, and dow_order means for providing one or more of said entries as order entries for identifying said common order dependencies. 3. The ordering subsystem of Claim 2 wherein said delete means includes operation delete means for deleting operation entries from said ordering store and includes order delete means for deleting order entries from said ordering store. 4. The ordering subsystem of Claim 3 wherein said delete means includes dow abort means for deleting entries from said ordering store. 5. The ordering subsystem of Claim 4 wherein said dow ώort means operates asynchronously with respect to said execution means. 6. The ordering subsystem of Claim 1 wherein said operations include writes from said first unit to said second unit. 7. The ordering subsystem of Claim 1 wherein said operations include function calls. 8. The ordering subsystem of Claim 1 wherein said first unit is primary storage and said second unit is secondary storage and wherein said requests are update requests and said operations include writes from said primary storage to said secondary storage. 9. The ordering subsystem of Claims 1 wherein said first unit is primary storage and said second unit is secondary storage and wherein said requests are update requests and said operations include writes from said primary storage to said secondary storage and may include function calls. 10. The ordering subsystem of Claim 9 wherein said writes from said primary storage to said secondary storage may include common writes combining one or more separate writes and may include associated function calls, and wherein said add means includes, -197- SUeSTITUTE SHEET (PULE 26) dow_create means for providing one or more of said entries as common-write entries for identifying common writes or as function-call entries for identifying function calls, and dow order means for providing one or more of said entries as order entries for identifying said order dependencies as common-write order dependencies or as function-call order dependencies. 11. The ordering subsystem of Claim 10 wherein said entries in the ordering store are organized in one or more sets with each set having an order from high order for predecessor operations to low order for dependent operations and wherein each of said function-call entries, if present in a set, is the lowest order so that function calls are the last performed operation in a set. 12. The ordering subsystem of Claim 9 wherein a write for one or more of said update requests is delayed so as to be part of one of said common writes. 13. The ordering subsystem of Claim 9 wherein said update requests Rl, R2, ..., Rr are presented in time order with Rl before R2, R2 before R3, ..., R(r-l) before Rr and wherein a write for one or more of said update requests is delayed so as to be part of one of said common writes whereby writes for one or more of said update request are not necessarily in the time order of the update requests Rl, R2 Rr. 14. The ordering subsystem of Claim 9 wherein said add means operates asynchronously with respect to said execution means. 15. The ordering subsystem of Claim 9 wherein said delete means operates asynchronously with respect to said execution means. 16. The ordering subsystem of Claim 1 wherein said system includes a local unit and a remote unit connected by a network. 17. The ordering subsystem of Claim 16 wherein said first unit is primary storage in said local unit and said second unit is secondary storage in said local unit, wherein said requests are update requests and said operations include writes from said primary storage to said secondary storage and may include function calls, and wherein said remote unit initiates said requests for writes from said primary storage to said secondary storage over said network. 18. The ordering subsystem of Claim 1 wherein the computer system includes call means for issuing a call to said ordering subsystem and said ordering subsystem includes, dow lush_chain means for queuing operation entries for operations to be executed, dow_strategy means for searching the ordering store to identify operation entries for operations to be executed and for placing said operation entries for operations to be executed on the dσwjlush_chain means, dowjlush means for removing operation entries from the dowJlush_chain and for initiating the operations to be executed. 19. An ordered write subsystem for controlling the order of operations in connection with writes from primary storage to secondary storage in a computer system, the computer system having data organized in files, having primary storage for storing files, having a secondary storage for storing files, having a file management subsystem for controlling transfers of files between primary storage and secondary storage, said file management subsystem specifying operations in connection with writes from primary storage to secondary storage in response to new update requests for said operations, where a sequence of update requests is represented by the update requests Rl, R2, ..., R(r-l), Rr, where the update requests in said sequence have order dependencies Dl, D2, ..., Dd and where r and d are integers, said order dependencies constraining the order for carrying out said operations, said ordered write subsystem including, an ordering store for storing a plurality of entries, each of said entries containing an operation type identifying one of said operations, at least one of said entries at some time also containing a link which links said entry to another of said entries, said link specifying an order -199- SU8STITUTE SHEET (RULE 26) for carrying out said operations in said linked entries, said entries and said links defining a partially ordered acyclic graph, add means for adding entries to said ordering store by processing said new update requests to identify common operations, said common operations including, one or more common writes C 1, CW2, ..., CWcw for a combined operation requested by one or more of the update requests Rl, R2, ..., Rr where cw is an integer less than r, and one or more function calls FC1, FC2, ..., FCfc where fc is an integer, and wherein said common writes and said function calls have common order dependencies CD1, CD2, ..., CDcd that preserve the update order dependencies D 1 , D2 , ... , Dd between the operations , where cd is an integer, execution means for executing common operations including, write means responsive to the entries in the ordering store for writing from primary storage to secondary storage with said common writes CW1, CW2, ..., CWcw constrained by the common-write order dependencies CD1 , CD2, ..., CDcd, function means for executing said function calls, and delete means for deleting entries from the ordering store. 20. The ordering subsystem of Claim 19 wherein said add means includes, dowjcreate means for providing one or more of said entries as operation entries for identifying said common operations, and dow_order means for providing one or more of said entries as order entries for identifying said common order dependencies. 21. The ordering subsystem of Claim 20 wherein said dowjcreate means provides said operation as common-write entries for identifying common writes. 22. The ordering subsystem of Claim 20 wherein said dowjcreate means provides said operation entries as function-call entries for identifying function calls. 23. The ordering subsystem of Claim 19 wherein said ordering store includes ordered locations with higher-order locations and lower-order locations and for each common- write entry, zero or more higher-order locations for an order entry pointing to zero or more high-order common writes and zero or more lower-order locations for an order entry pointing to zero or more lower-order common writes. 24. The ordering subsystem of Claim 19 wherein a write for one or more of said update requests is delayed so as to be part of one of said common writes. 25. The ordering subsystem of Claim 19 wherein said update requests Rl, R2, ..., Rr are presented in time order with Rl and before R2, R2 before R3, ..., R(r-l) before Rr and wherein a write for one or more of said update requests is delayed so as to be part of one of said common writes whereby writes for one or more of said update requests are not in the time order of the update requests Rl, R2, ..., R(r-1), Rr. 26. The ordering subsystem of Claim 19 wherein said add means operates asynchronously with respect to said execution means. 27. The ordering subsystem of Claim 19 wherein said delete means includes operation delete means for deleting operation entries from said ordering store and includes order delete means for deleting order entries from said ordering store. 28. The ordering subsystem of Claim 27 wherein said operation delete means includes dowjώort means for deleting entries from said ordering store. 29. The ordering subsystem of Claim 28 wherein said dowjώort means operates asynchronously with respect to said, execution means. -201- SU8STITUTE SHEET RULE 26) 30. The ordering subsystem of Claim 19 wherein said primary storage includes a cache and wherein said ordered write subsystem causes said file management subsystem to initiate writes from said cache. 31. The ordering subsystem of Claim 29 further including device drivers connected to write from said cache to said secondary storage. 32. The ordering subsystem of Claim 19 wherein said ordering subsystem includes, dow startmod means for indicating that a set-up for a common operation is to be initiated, dow setmod means for indicating that said set-up is complete, dow create means for providing one of said entries as an operation entry for identifying said common operation, and dow order means for providing one of said entries as an order entry for identifying said common order dependency. 33. The ordering subsystem of Claim 32 wherein said ordering subsystem is operative for a first one and for a second one of said common operations and wherein, said dow startmod means is called for indicating that a first set-up for said first one of said common operations is to be initiated and dow_startmod means is again called for indicating that a second set-up for said second one of said common operations is to be initiated, said dow setmod means is called for indicating that said first set-up is complete for said first one of said common operations, said dow reate means is called for providing a first one of said entries as a first operation entry for identifying said first common operation, said dow_order means is called for providing a first one of said entries as an order entry for identifying said first common order dependency; said dowjorder means employed to provide said order entry after said dow_setmod means are employed to indicate that said first set-up is complete for said first one of said common operations and before said dow_startmod means are employed to indicate that said second set-up for said second one of said common operations is to be initiated. 34. A method in a computer system having a first unit and a second unit for files, having a file management subsystem for controlling operations for files, said file management subsystem specifying operations for files in response to new requests where a sequence of requests for the operations is represented by the requests Rl, R2, ..., Rr and where the requests for the operations in said sequence have order dependencies Dl, D2, ..., Dd where r and d are integers, said order dependencies constraining the order for carrying out the operations, said computer system including an ordering subsystem for controlling the order of operations including, said method comprising: storing a plurality of entries in an ordering store, each of said entries containing an operation type identifying one of said operations for files, at least one of said entries at some time also containing a link which links said entry to another of said entries, said link specifying an order for carrying out said operations in said linked entries, said entries and said links defining a partially ordered acyclic graph, adding entries to the ordering store by processing said new requests to identify one or more common operations CO1, CO2, ..., COco, each of the common operations identifying an operation requested by one or more of the requests Rl, R2, ..., Rr, where said common operations have common order dependencies CD1, CD2, ..., CDcd that preserve the order dependencies Dl, D2, ..., Dd between the operations in the requests, and where co and cd are integers, and executing said one or more common operations CO1, CO2, ..., COco responsive to the entries in the ordering store. 35. The computer method of Claim 34 wherein said adding step includes, dow reate step for providing one or more of said entries as operation entries for identifying common operations, and dow j order step for providing one or more of said entries as order entries for identifying said common order dependencies. 36. The computer method of Claim 35 further comprising a delete step which includes an operation delete step for deleting operation entries from said ordering store and includes an order delete step for deleting order entries from said ordering store. 37. The computer method of Claim 36 wherein said delete step includes a dow abort step for deleting entries from said ordering store. 38. The computer method of Claim 37 wherein said dowjώort step operates asynchronously with respect to said execution step. 39. The computer method of Claim 34 wherein said operations include writes from said first unit to said second unit. 40. The computer method of Claim 34 wherein said operations include function calls. 41. The computer method of Claim 34 wherein said first unit is primary storage and said second unit is secondary storage and wherein said requests are update requests and said operations include writes from said primary storage to said secondary storage. 42. The computer method of Claim 34 wherein said first unit is primary storage and said second unit is secondary storage and wherein said requests are update requests and said operations include writes from said primary storage to said secondary storage and may include function calls. 43. The computer method of Claim 42 wherein said writes from said primary storage to said secondary storage may include common writes combining one or more separate writes and may include associated function calls, and said add step includes, dow reate step for providing one or more of said entries as common-write entries for identifying common writes or as function-call entries for identifying function calls, and dowj>rder step for providing one or more of said entries as order entries for identifying said order dependencies as common-write order dependencies or as function-call order dependencies. 44. The computer method of Claim 43 wherein said entries in the ordering store are organized in one or more sets with each set having an order from high order for preceding operations to low order for succeeding operations and wherein said function-call entries, if present in a set, are the lowest order so that function calls are the last performed operation in a set. 45. The computer method of Claim 42 wherein a write for one or more of said update requests is delayed so as to be part of one of said common writes. 46. The computer method of Claim 42 wherein said update requests Rl, R2, ..., Rr are presented in time order with Rl before R2, R2 before R3, ..., R(r-l) before Rr and wherein a write for one or more of said update requests is delayed so as to be part of one of said common writes whereby writes for one or more of said update requests are not necessarily in the time order of the update requests Rl, R2, ..., Rr. 47. The computer method of Claim 42 wherein said add step operates asynchronously with respect to said execution step. 48. The computer method of Claim 42 further comprising a delete step which operates asynchronously with respect to said execution step. 49. The computer method of Claim 34 wherein said system includes a local unit and a remote unit connected by a network. 50. The computer method of Claim 49 wherein said first unit is primary storage in said local unit and said second unit is secondary storage in said local unit, wherein said requests are update requests and said operations include writes from said primary storage to said secondary storage and may include function calls, wherein said remote unit communicates over said network with said local unit to move data between said first unit and said second unit. 51. A computer method in a computer system having data organized in files, having primary storage for storing files, having a secondary storage for storing files, having a file management subsystem for controlling transfers of files between primary storage and secondary storage, said file management subsystem specifying operations in connection with writes from primary storage to secondary storage in response to new update requests where a sequence of update requests for the operations is represented by the update requests Rl, R2, ..., R(r-l), Rr, where the update requests in said sequence have order dependencies Dl, D2, ..., Dd and where r and d are integers, the order dependencies constraining the order for carrying out the operations, said computer method including an ordered write subsystem for controlling the order of operations in connection with writes from primary storage to secondary storage, said method including, storing a plurality of entries in an ordering store, each of said entries containing an operation type identifying one of said operations for files, at least one of said entries at some time also containing a link which links said entry to another of said entries, said link specifying an order for carrying out said operations in said linked entries, said entries and said links defining a partially ordered acyclic graph, add steps for adding entries to said ordering store by processing said new update requests to identify common operations, said common operations including, one or more common writes CVVl, CW2, ..., CWcw for a combined operation identifying an operation requested by one or more of the update requests Rl, R2, ..., Rr where cw is an integer less than r, and one or more function calls FC1, FC2, ..., FCfc where fc is an integer, and where said common writes and said function calls have common order dependencies CD1, CD2, ..., CDcd that preserve the update order dependencies Dl, D2, ..., Dd between the operations in the requests, where cd is an integer, executing common operations including, write steps responsive to the entries in the ordering store for writing from primary storage to secondary storage with said common writes CW1, CW2, ..., CWcw constrained by the common- write order dependencies CD1, CD2, ..., CDcd, function steps for executing said function calls, and deleting entries from the ordering store. 52. The computer method of Claim 51 wherein said add steps include, dow create steps for providing one or more of said entries as operation entries for identifying said common operations, and dowjorder steps for providing one or more of said entries as order entries for identifying said common order dependencies. 53. The computer method of Claim 51 wherein said dow reate steps provide said operation entries as common- write entries for identifying common writes. 54. The computer method of Claim 51 wherein said dowjcreate steps provide said operation entries as function-call entries for identifying function calls. 55. The computer method of Claim 51 wherein said ordering store includes ordered locations with higher-order locations and lower-order locations and wherein said ordering store includes for each common-write entry, zero or more higher-order locations for an order entry pointing to zero or more higher-order common writes and zero or more lower-order locations for an order entry pointing to zero or more lower-order common writes. 56. The computer method of Claim 51 wherein a write for one or more of said update requests is delayed so as to be part of one of said common writes. 57. The computer method of Claim 51 wherein said update requests Rl, R2, ..., Rr are presented in time order with Rl, R2 before R3, ..., R(r-l) before Rr and wherein a write for one or more of said update requests is delayed so as to be part of one of said common writes whereby writes for one or more of said update requests are not in the time order of the update requests Rl, R2, ..., R(r-l), Rr. 58. The computer method of Claim 51 wherein said add steps operate asynchronously with respect to said execution steps. 59. The computer method of Claim 51 wherein said deleting step includes an operation delete step for deleting operation entries from said ordering store and includes an order delete step for deleting order entries from said ordering store. 60. The computer method of Claim 60 wherein said operation delete step includes a dowjώort step for deleting entries from said ordering store. 61. The computer method of Claim 60 wherein said dow abort step operates asynchronously with respect to said execution steps. 62. The computer method of Claim 51 wherein said ordering subsystem performs, dow startmod steps for indicating that a set-up for a common operation is to be initiated, dow etmod steps for indicating that said set-up is complete, dow reate steps for providing one of said entries as an operation entry for identifying said common operation, and dow rder steps for providing one of said entries as an order entry for identifying said common order dependency. 63. The computer method of Claim 62 wherein said ordering subsystem is operative for a first one and for a second one of said common operations and wherein, said dow_startmod steps are called for indicating that a first set-up for said first one of said common operations are to be initiated and dow_startmod steps are again called for indicating that a second set-up for said second one of said common operations is to be initiated, said dow_setmod steps are called for indicating that said first set-up are complete for said first one of said common operations, said dow-create steps are called for providing a first one of said entries as a first operation entry for identifying said first common operation, said dowjtrder steps are called for providing a first one of said entries as an order entry for identifying said first common order dependency; said dowjrder steps employed to provide said order entry after said dow setmod steps are employed to indicate that said first set-up is complete for said first one of said common operations and before said dow_startmod steps are employed to indicate that said second set-up for said second one of said common operations is to be initiated. 64. A computer system having a first unit and a second unit for files, having an operating system including a file system with a plurality of file system implementations, said operating system having a kernel formed of a plurality of subsystems including a file management subsystem for controlling operations for files, said file management subsystem specifying operations for files in response to new requests where a sequence of requests for -209- SUeSTITUTE SHEET (RULE 26) said operations is represented by the requests Rl, R2, ..., Rr and where the requests for said operations in said sequence have order dependencies Dl, D2, ..., Dd, said order dependencies constraining the order for carrying out said operations, said kernel including an ordering subsystem for controlling the order of operations, said ordering subsystem organized independently of other subsystems of said kernel and having a common interface for communicating with said other subsystems, said ordering subsystem including, an ordering store for storing a plurality of entries, each of said entries containing an operation type identifying one of said operations for files, at least one of said entries at some time also containing a link which links said entry to another of said entries, said link specifying an order for carrying out said operations in said linked entries, said entries and said links defining a partially ordered acyclic graph, add means for adding entries to the ordering store by processing said new requests to identify one or more common operations CO1, CO2, ..., COco, each of said common operations identifying an operation requested by one or more of the requests Rl, R2, ..., Rr, where said common operations have common order dependencies CD1 , CD2, ... , CDcd that preserve the order dependencies Dl, D2, ..., Dd between the operations in the requests, execution means for executing said one or more common operations CO1, CO2, ..., COco responsive to the entries in the ordering store, and delete means for deleting entries from the ordering store. 65. The computer system of Claim 64 wherein said ordering subsystem includes in said common interface, dow startmod means for indicating that a set-up for a common operation is to be initiated, dow_setmod means for indicating that said set-up is complete, dow reate means for providing one of said entries as an operation entry for identifying said common operation, and dow rder means for providing one of said entries as an order entry for identifying said common order dependency. 66. The computer system of Claim 65 wherein said ordering subsystem is operative for a first one and for a second one of said common operations and wherein, said dow_startmod means is called for indicating that a first set-up for said first one of said common operations is to be initiated and dow_startmod means is again called for indicating that a second set-up for said second one of said common operations is to be initiated, said dow_setmod means is called for indicating that said first set-up is complete for said first one of said common operations, said dow reate means is called for providing a first one of said entries as a first operation entry for identifying said first common operation, said dowjrder means is called for providing a first one of said entries as an order entry for identifying said first common order dependency; said dowjyrder means is employed to provide said order entry after said dow_setmod means is employed to indicate that said first set-up is complete for said first one of said common operations and before said dow tartmod means is employed to indicate that said second set-up for said second one of said common operations is to be initiated. 67. A method in a computer system having a first unit and a second unit for files, having an operating system including a file system with a plurality of file system -211- SUBST1TUTE SHEET (RULE 26) implementations, said operating system having a kernel formed of a plurality of subsystems including a file management subsystem for controlling operations for files, said file management subsystem specifying operations for files in response to new requests where a sequence of requests for the operations is represented by the requests Rl, R2, ..., Rr and where the requests in said sequence have order dependencies Dl, D2, ..., Dd, the order dependencies constraining the order for carrying out the operations, said kernel including an ordering subsystem for controlling the order of operations, said ordering subsystem organized independently of other subsystems of said kernel and having a common interface for communicating with said other subsystems, said method comprising, storing a plurality of entries in an ordering store, each of said entries containing an operation type identifying one of said operations for files, at least one of said entries at some time also containing a link which links said entry to another of said entries, said link specifying an order for carrying out said operations in said linked entries, said entries and said links defining a partially ordered acyclic graph, adding entries to the ordering store by processing said new requests to identify one or more common operations CO1, CO2, ..., COco, each of said common operations identifying an operation requested by one or more of the requests Rl, R2, ..., Rr, where said common operations have common order dependencies CD1, CD2, ..., CDcd that preserve the order dependencies Dl, D2, ..., Dd between the operations in the requests, executing said one or more common operations CO1, CO2, ..., COco responsive to the entries in the ordering store, and deleting entries from the ordering store. -212- SϋeSTITUTE SHEET (RULE 26)

Inventors: DOSHI KSHITIJ ARUN, SAKS JONATHAN HAIM, DOSHI, KSHITIJ, ARUN, SAKS, JONATHAN, HAIM
Applicants: NOVELL INC, NOVELL, INC.
Application year: 1995
Main classification: G06F17
IPC codes: G06F3, G06F12, G06F17