Method of sharing memory between an operating system and an application program5673394Abstract An improved method for the sharing of data among a file server, a file system, and a network driver executing on a computer is provided. The file system allocates cache buffers to be used in reading from or writing to a file. When reading a file, the file system starts loading the cache buffers with the file data. When a buffer is loaded, the file system signals the file server that a buffer at a certain address is loaded. The file server provides the network driver with the buffer address of the data that is ready to be transported onto a computer network. The transport system then reads the data from the cache buffers and sends the data onto the computer network. When writing a file, the file system allocates cache buffers to receive the file. The file system notifies the file server of the cache buffer addresses. The file server then notifies the network driver of the cache buffer addresses. When the network driver receives the data it loads the data directly into the cache buffers. The file system can then write the data from the cache buffers to the disk. Claims We claim: Description TECHNICAL FIELD
TABLE 1
______________________________________
Data Structures
Description
______________________________________
Data Descriptor
dd.sub.-- addr points to first byte to transfer in
the cache buffer
dd.sub.-- length
number of bytes to transfer in the
cache buffer
dd.sub.-- offset
byte offset where the data begins
dd.sub.-- sector
SNUM disk sector address of data
SHINT pointer to cache buffer header
Buffer Descriptor
bf.sub.-- DataPtr
pointer to the first byte in cache
buffer to transfer
bf.sub.-- DataLen
number of bytes to transfer
PNB
pnb.sub.-- list
pointer to link the PNBs
pnb.sub.-- flag
holds internal state
pnb.sub.-- ncb
ncb.sub.-- command
network control command
ncb.sub.-- buffer
pointer to the Buffer Descriptors
ncb.sub.-- length
count of bytes to transfer
ncb.sub.-- flags
indicates position of NCB group of
NCBs
ncb.sub.-- cmd.sub.-- cplt
indicates that the network has
completed the network request
associated with this NCB
Read Work Area
rwk.sub.-- cbData
number of bytes in file to read
rwk.sub.-- pDDesc
pointer to next Data Descriptor to
send
rwk.sub.-- cDDesc
number of Data Descriptors left to
send
rwk.sub.-- ncbs
pointer to list of NCBs
rwk.sub.-- cNcbs
number of NCBs
rwk.sub.-- bufDesc
Buffer Descriptors
Cache Header
b.sub.-- sec sector address of data in cache buffer
b.sub.-- addr pointer to cache buffer
b.sub.-- lcnt lock count
b.sub.-- hcnt hold count
b.sub.-- dirt flag indicating whether the cache
needs to be written to disk
OFT
oft.sub.-- hcnt
hold count for an open file
Write Work Area
wwk.sub.-- cImm
number of bytes of immediate data
wwk.sub.-- pImm
pointer to immediate data
wwk.sub.-- cRaw
count of bytes of raw data that will
fit into the last cache buffer of
immediate data
wwk.sub.-- cbytes
number of bytes to write to the file
wwk.sub.-- pDDesc
pointer to Data Descriptors
wwk.sub.-- cDDesc
count of Data Descriptors
wwk.sub.-- bufDesc
Buffer Descriptors
______________________________________
READ REQUEST In a preferred embodiment of the present invention, the file server receives a read request from the network driver. If the read is a "raw mode" read, then the file server calls subroutine ReadRaw. A raw mode read request indicates that the requesting computer expects the file data to be transported on the network without accompanying header information and without packaging the data. Basically, the file server computer transports only the file data. When the file server calls the ReadRaw subroutine, it passes the file handle Fid, the seek position seek.sub.-- position, and byte count byte.sub.-- count. The file handle identifies the open file to read from, the seek position is the byte offset in the file from which the read is to begin, and the byte count indicates the number of bytes to be read. The ReadRaw subroutine and several of the subroutines that it calls are described below. ReadRaw Subroutine The subroutine ReadRaw controls the reading of a file from a disk and transporting the data read onto the network. The subroutine input parameters are file handle Fid, seek position seek.sub.-- position, and number of bytes to read rwk.sub.-- cbData. Subroutine ReadRaw uses certain file system APIs to read the file from disk. Once the file system stores data in a cache buffer, the subroutine formats a network control block (NCB). The subroutine ReadRaw then invokes the network driver to transport the data. FIGS. 6A, 6B, 6C, and 6d show a flow diagram of a preferred embodiment of the present invention. Referring to FIG. 6A in block 601, the system calls the File System routine ReadInit passing the parameters Fid, seek.sub.-- position, and rwk.sub.-- cbData. The subroutine ReadInit initializes a list of Data Descriptors for the read and returns a pointer to Data Descriptors rwk.sub.-- pDDesc, the count of the Data Descriptors rwk.sub.-- pDDesc initialized, and the number of bytes read rwk.sub.-- cbData. Subroutine ReadInit also allocates cache buffer headers for the reads and sets the headers to hold. Setting the headers to hold indicates that the associated cache buffer will not be removed from memory until the hold is removed. The hold is removed after the data is transported on the network. In blocks 602 through 606, the system executes a loop initializing the PNBs. The PNBs 501 are a circular-linked list, as shown in FIG. 5. The PNBs contain information relating to the transport, including the NCBs needed to issue a transport request to the network driver. In a preferred embodiment, there are six PNBs in the linked list. However, the number of PNBs can be varied based upon available memory and other considerations. The variable rwk.sub.-- cNcbs contains the number of PNBs in the linked list, and the variable rwk.sub.-- ncbs contain a pointer to the first PNB in the list. In block 602, the system sets count equal to rwk.sub.-- cNcbs. The variable count controls the number of times the loop at blocks 604 through 606 is executed. In block 603, the system selects the first PNB, which is pointed to by rwk.sub.-- ncbs. In block 604, the system initializes the selected PNB. The system initializes a couple of the NCB fields: ncb.sub.-- command, to indicate a transport request and ncb.sub.-- cmd.sub.-- cplt to indicate the command is not complete. In block 605, the system selects the next PNB, which is pointed to by pnb.sub.-- list of the currently selected PNB. In block 606, the system decrements count, and if count is not equal to 0, then the system loops to block 604 to initialize the newly selected PNB, else all the PNBs are initialized and the system continues at block 607. When the loop at blocks 604 through 606 completes (i.e., count=0), the currently selected PNB is the first PNB, that is, the PNB pointed to by rwk.sub.-- ncbs. Blocks 607 through 629 in FIGS. 6A, 6B, and 6C compose a loop which initializes an NCB and associated Buffer Descriptor and then submits the NCB to the network driver. In a preferred embodiment, the use of a circular-linked list for the PNBs simplifies the processing. However, other data organization techniques may be used. Referring to FIG. 6A, the first time through the loop, the system executes block 607. On subsequent executions of the loop, the system executes block 608. In block 607, the system sets pnb.sub.-- ncb.ncb.sub.-- flags equal to the constant FIRST.sub.-- NCB.sub.-- FLAG. This setting indicates to the network driver that the NCB is the first of a group of NCEs. In block 608, the system sets pnb.sub.-- ncb.ncb.sub.-- flags equal to 0, which indicates to the network driver that the NCB is in the middle of a group of NCBs. In block 609, the system sets pnb.sub.-- ncb.ncb.sub.-- buffer to point to the Buffer Descriptor pointed to by rwk.sub.-- pBufDesc. In block 610, the system sets pnb.sub.-- ncb.ncb.sub.-- length equal to 0. The variable pnb.sub.-- ncb.ncb.sub.-- length holds the total number of bytes a data to be transferred with a PNB. The system then continues at block 611 in FIG. 6B. In blocks 611 through 619 of FIG. 6B, the system prepares an NCB and associated Buffer Descriptors for sending to the network driver. In a preferred embodiment, the system associates no less than 8,192 bytes of data with an NCB unless the last NCB for the read request is being prepared. In blocks 611 through 619, the system loops processing the Data Descriptors. The system waits until each Data Descriptor has its associated cache buffer filled by the file system. The file system indicates that a cache buffer has been filled by setting dd.sub.-- addr to 0. When the system selects a cache buffer that has been filled, the system initializes a Buffer Descriptor to point to the cache buffer and increases the length of the data associated with the NCB being prepared. In a preferred embodiment, the Buffer Descriptors are stored as an array-like data structure. However, other data storage techniques such as a heap or a linked list may be used. The Buffer Descriptors associated with an NCB are contiguous elements of the array-like structure. When the system selects a cache buffer that has not yet been filled, the system either sends the prepared NCB to the network driver or waits until the cache buffer is filled. The system sends the NCB to the network driver when the number of associated data bytes is greater than or equal to 8,192. The variable rwk.sub.-- cDDesc contains the count of Data Descriptors whose associated cache buffers have not yet been submitted to the network driver. In block 611, if rwk.sub.-- cDDesc is equal to 0 then all the Data Descriptors have been processed and the system prepares to send the last NCB by continuing at block 620, else the system continues at block 612. In block 612, the system selects the next unprocessed Data Descriptor. In block 613, the system selects the next unused buffer descriptor. In blocks 614 through 619, the system processes the Data Descriptors until one is encountered whose associated cache buffer has not yet been filled or until all the Data Descriptors have been processed. In block 14, if dd.sub.-- addr for the selected Data Descriptor equals 0, then the associated cache buffer has not yet been filled and the system continues at block 621, else the system continues at block 615. In block 615, the system sets bf.sub.-- DataPtr of the selected Buffer Descriptor to point to the filled cache buffer associated with the selected Data Descriptor. In block 616, the system increases pnb.sub.-- ncb.ncb.sub.-- length for the selected NCB by the number of bytes of data in the cache buffer, which is stored in dd.sub.-- length. In block 617, the system selects the next Data Descriptor. In block 618, the system selects the next Buffer Descriptor. In block 619, the system decrements rwk.sub.-- cDDesc. If rwk.sub.-- cDDesc is equal to 0, then all the Data Descriptors have been processed and the system continues at block 620 to submit the selected NCB to the network driver, else the system loops to block 614 to process the next Data Descriptor. In block 621, if pnb.sub.-- ncb.ncb.sub.-- length is greater than or equal to 8,192, then the system submits the selected NCB to the network driver by continuing at block 623 of FIG. 6C, else the system continues at block 622. In block 622, the system calls subroutine ReadWait, which returns when the selected cache buffer has been filled and the system continues at block 611. In block 620, pnb.sub.-- ncb.ncb.sub.-- flags is set to LAST.sub.-- NCB.sub.-- FLAG to indicate that the selected NCB is the last NCB to be submitted to the network driver for the read request. The system then continues at block 623 of FIG. 6C. Referring to FIG. 6C in block 623, the system selects the next Buffer Descriptor as a list terminator. In block 624, the system sets bf.sub.-- DataLen equal to zero to indicate that the selected Buffer Descriptor terminates the list. In block 625, the system calls subroutine NCBSubmit to send the selected NCB to the network driver. In block 627, if rwk.sub.-- cDDesc equals 0, then all the cache buffers represented by the Data Descriptors have been submitted to the network driver and the system continues at block 630 of FIG. 6D, else more cache buffers need to be submitted to the network driver and the system continues at block 627. In block 627, the system selects the next PNB, which is pointed to by pnb.sub.-- list of the currently selected PNB. In block 628, if pnb.sub.-- ncb.ncb.sub.-- cmd.sub.-- cplt of the selected PNB equals 0, then the network driver has transmitted the data that was previously pointed to by the selected NCB and the system loops to block 608 of FIG. 6A to reuse the NCB, else the network driver has not completed transmitting the data and the system waits for the completion by continuing at block 629. In block 629, the system calls subroutine NCBWait to wait for the completion of the NCB request represented by the currently selected PNB. The system then loops to block 608 of FIG. 6A. In blocks 630 through 635, the system ensures that all the NCB requests are complete and that all the cache buffers are not held. In block 630, the system selects the next PNB, which is pointed to by pnb.sub.-- list of the currently selected PNB. In block 631, if pnb.sub.-- ncb.ncb.sub.-- flags of the selected PNB equals the constant PNBF.sub.-- DONE, then all the NCB requests have been completed and the system continues at block 635, else the system continues at block 632. In block 632, the system sets pnb.sub.-- ncb.ncb.sub.-- flags of the selected PNB equal to PNBF.sub.-- DONE to indicate that the NCB request represented by the selected PNB has completed. In block 633, if pnb.sub.-- ncb.ncb.sub.-- cmd.sub.-- cplt of the selected PNB equals 0, than the network driver has transmitted the data that was previously pointed to by the selected PNB and the system loops to block 630 to check the next PNB, else the network driver has not completed transmitting the data and the system waits for the completion by continuing at block 634. In block 634, the system calls subroutine NCBWait to wait for the completion of the NCB request represented by the currently selected PNB. In block 635, the system calls subroutine ReadFinish to remove the hold on the file and the cache buffers. The subroutine ReadRaw is then complete and returns. ReadInit Subroutine The subroutine ReadInit initializes the Data Descriptor List for the file and issues an asynchronous read request. The ReadInit subroutine processes the file extent by extent. The subroutine takes the data for each extent and initializes the appropriate Data Descriptor. The input parameters are the file handle Fid, seek position seek.sub.-- position, and number of bytes to read rwk.sub.-- cbData. This routine returns a pointer to the first Data Descriptor in rwk.sub.-- pDDesc, the number of Data Descriptors in rwk.sub.-- cDDesc, and the number of bytes read in rwk.sub.-- cbData. FIGS. 7A, 7B, and 7C are a flow diagram of the ReadInit subroutine. Referring to FIG. 7A, in block 700A, the system selects the File Handle Table entry (FHT) for the file, which is pointed to by Fid. FIG. 16 shows the data structures that hold information relating to each open file. In block 700B, the system selects the Open File Table entry OFT, pointed to by the selected FHT. In block 700C, the system increments oft.sub.-- hcnt of the selected OFT, which is the hold count for the file. In block 701, the system selects the first extent to be read in the file. This extent is based on the seek position, which is the offset in bytes in the file at which the read is to start. In block 702, the system sets the local variable left.sub.-- to.sub.-- read.sub.-- file equal to the minimum of rwk.sub.-- cbData and file.sub.-- size minus seek.sub.-- position. The variable left.sub.-- to.sub.-- read.sub.-- file contains the number of bytes left to process in the read request. The variable file.sub.-- size equals the total number of bytes in the file. The file.sub.-- size minus seek.sub.-- position term ensures that the requested number of bytes does not extend past the end of file. In block 703, the system sets the local variable left.sub.-- to.sub.-- read.sub.-- extent equal to extent.sub.-- length. The variable left.sub.-- to.sub.-- read.sub.-- extent contains the number of bytes left to process in the selected extent. The variable extent.sub.-- length equals the number of bytes in the selected extent. In block 704, the system selects the next Data Descriptor. In blocks 705 through 709, the system initializes the Data Descriptor fields for the first cache buffer allocated to an extent. In block 705, the system sets dd.sub.-- offset of the selected Data Descriptor equal to the offset in the cache buffer at which the first sector of the selected extent will be stored, that is, 512 times the remainder of extent.sub.-- sector divided by 4. The variable extent.sub.-- sector contains the starting sector address of the selected extent. If the first extent in the read is being accessed, then dd.sub.-- offset of the selected Data Descriptor is adjusted to reflect that the application may not be requesting the read to start on a sector boundary. Referring to FIG. 7B, in block 706, if the first extent to read is selected, then in block 707 the system adds the remainder of seek.sub.-- position divided by 512 to dd.sub.-- offset of the selected Data Descriptor and continues at block 708. In block 708, the system sets dd.sub.-- length of the selected Data Descriptor equal to the minimum of 2K minus dd.sub.-- offset of the selected Data Descriptor, left.sub.-- to.sub.-- read.sub.-- extent, and left.sub.-- to.sub.-- read.sub.-- file. This setting accounts for reads that do not end on a 2K boundary. In block 709, the system sets dd.sub.-- sector.SNUM equal to the sector address of the first sector to be stored in the associated cache buffer for the selected extent. The first sector is next lower four-sector boundary of the extent sector, that is, 4 times the integer portion of extent.sub.-- sector divided by 4. In block 711, the system sets the local variable next.sub.-- sector equal to dd.sub.-- sector.SNUM plus 4. the next sector in the extent starts on a four-sector boundary. In block 712, the system decrements left.sub.-- to.sub.-- read.sub.-- file by dd.sub.-- length of the selected Data Descriptor. In block 713, the system decrements left.sub.-- to.sub.-- read.sub.-- extent by dd.sub.-- length of the selected Data Descriptor. In block 714, if left.sub.-- to.sub.-- read.sub.-- file equals 0, then all the Data Descriptors for the read request have been initialized and the ReadInit subroutine returns, else the system continues at block 715. In block 715, if left.sub.-- to.sub.-- read.sub.-- extent equals 0, then all the Data Descriptors for the selected extent have been initialized and the system continues at block 722 in FIG. 7A to process the next extent, else the system continues at block 716 in FIG. 7C. Referring to FIG. 7C, in block 716, the system selects the next Data Descriptor to be initialized. In blocks 717 through 720, the system initializes the selected Data Descriptor. In block 717, the system sets dd.sub.-- offset of the selected Data Descriptor to 0. In block 718, the system sets dd.sub.-- length of the selected Data Descriptor equal to the minimum of 2K minus dd.sub.-- offset, left.sub.-- to.sub.-- read.sub.-- extent, and left.sub.-- to.sub.-- read.sub.-- file. In block 719, the system sets dd.sub.-- sector.SNUM of the selected Data Descriptor equal to next.sub.-- sector. In block 720, the system sets dd.sub.-- addr of the selected Data Descriptor equal to 0. In block 721, the system sets next.sub.-- sector equal to next.sub.-- sector plus 4 and the system loops to block 712 to process the rest of the extent. Referring to FIG. 7A, in block 722, the system issues an asynchronous read request to initiate a read from the selected extent into the cache memory by calling subroutine RdAsync. In block 723, the routine selects the next extent to be processed and continues with the loop at block 704. ReadAsync Subroutine The RdAsync subroutine determines whether the specified sectors are in a cache buffer. If they are, then subroutine RdAsync sets the passed Data Descriptor to point to the cache buffer, else the subroutine issues an asychronous read request to load a cache buffer with the data from the sectors. The input parameter is a pointer to the selected Data Descriptor which contains the sector number. FIG. 8 is a flow diagram of subroutine RdAsync. Referring to FIG. 8, in block 801, the system selects the passed Data Descriptor. In block 802 the system calls subroutine CCH. Subroutine CCH determines whether the sector specified by dd.sub.-- sector.SNUM of the selected Data Descriptor currently in a cache buffer and returns its address in pcache.sub.-- buffer. In block 803, if pcache.sub.-- buffer equals 0, then the sector is not in a cache buffer and the system continues at block 808, else the system continues at block 804. In block 804, the system selects the cache buffer pointed to by pcache.sub.-- buffer. In block 805, the system places a hold on the cache buffer by incrementing b.sub.-- hcnt. In block 806, the system sets dd.sub.-- sector.SHINT equal to pcache.sub.-- buffer. In block 807, the system sets dd.sub.-- addr equal to b.sub.-- addr plus dd.sub.-- offset. The variable dd.sub.-- addr contains the address in the cache buffer of the data. Subroutine RdAsync then returns. In block 808, the system calls subroutine GFB, which returns the address of an available cache buffer in pcache.sub.-- buffer. In block 809, the system selects the cache header for the cache buffer pointed to by pcache.sub.-- buffer. In block 810, the system places a hold on the cache buffer by incrementing b.sub.-- hcnt. In block 811, the system sets dd.sub.-- sector.SHINT equal to pcache.sub.-- buffer. In block 812, the system sets dd.sub.-- addr to 0 to indicate that the cache buffer has not yet been loaded with the data from the file. In block 813, the system sets b.sub.-- sec equal to dd.sub.-- sector.SNUM. In block 814, the system issues an asynchronous read request and then returns. The asynchronous read request instructs the file system to read the specified sectors into the held cache buffer. The file system sets dd.sub.-- addr to the address in the cache buffer of where the file data begins. ReadFinish Subroutine The subroutine ReadFinish decrements the hold count of the file and removes the hold from the cache buffers. The input parameters are the file handle, a pointer to the first Data Descriptor, and the count of Data Descriptors. FIG. 10 shows a flow diagram of the ReadFinish subroutine. In block 1001, the system selects the FHT, that is, the entry in the File Handle Table pointed to by the file handle. In block 1002, the system selects the OFT, that is, Open File Table entry, pointed to by fht.sub.-- oft. In block 1003, the system decrements oft.sub.-- hcnt, the hold count of the file. In block 1004, the system selects the first Data Descriptor in the group. In blocks 1005 through 1009, the system executes a loop once for each Data Descriptor in the group. In block 1005, the system sets count equal to the number of Data Descriptors; the variable count controls the number of times the loop is executed. In block 1006, the system selects the cache header pointed to by dd.sub.-- sector.SHINT of the selected Data Descriptor. In block 1007, the system decrements b.sub.-- hcnt, which is the hold count for the selected cache header. In block 1008, the system selects the system Data Descriptor. In block 1009, the system decrements count and if count equals 0, then the hold count for each of the cache buffers has been decremented and subroutine ReadFinish returns, else the system loops to block 1006 to process the recently selected Data Descriptor. WRITE REQUEST In a preferred embodiment of the present invention, the file server receives a write request from the network driver. If the write is a "raw mode" write then the file server calls the WriteRaw subroutine. A raw mode write request indicates that the sending computer will send the file data onto the network without accompanying header information and without packaging the data. Basically, the file server computer receives only the file data. The sending computer when it sends the write request may include with that transmission a portion of the data to be written to the file. This data is called the immediate data. The data that is transmitted later in the raw mode is called the raw data. When the file server calls the WriteRaw subroutine it passes the file handle, the seek position, and the byte count along with a pointer to the immediate data and the number of bytes in the immediate data. In a preferred embodiment of the present invention, the file system initializes a list of Data Descriptors and holds the associated cache buffers. The network driver when it receives the raw mode data stores the data directly into the cache buffers. The file system then writes the cache buffer to the file and removes the hold. WriteRaw Subroutine The WriteRaw subroutine processes a request to write data to a file by allocating cache buffers, issuing a request to receive the data, and then writing the cache buffers to the file on disk. This routine is invoked when a WriteRaw request is received by the network server. The input parameters are the file handle, the seek position, the byte count to write, a pointer to the immediate data, and the byte count of the immediate data. FIGS. 11A and 11B show a flow diagram of the WriteRaw subroutine. In block 1101, the system initializes the PNB data structure. The system initializes a couple of the NCB fields. The system sets ncb.sub.-- command to indicate a write raw request. The system also sets ncb.sub.-- buffer to point to the first Buffer Descriptor at wwk.sub.-- bufDesc. In block 1102, the system calls subroutine WriteInit. The subroutine WriteInit locks the file for the duration of the write, extends the file size if the write request is beyond the current end of file, and initializes the Data Descriptors for the write request. This subroutine returns wwk.sub.-- cDDesc, the count of Data Descriptors, and wwk.sub.-- pDDesc, which is a pointer to the Data Descriptors. Since immediate data has been included in the write request, the system must transfer the immediate data to the cache buffers. In a preferred embodiment, the system does not transfer the data until after the system issues a receive request to the network driver for the rest of the data, that is, the non-immediate or raw data. The system sets aside a group of Data Descriptors for the immediate data. In blocks 1103 through 1110, the system loops through the Data Descriptors. When this loop is completed, the Data Descriptor for the cache buffer at which the first raw data will be stored is selected. In block 1103, the system sets count equal to wwk.sub.-- cDDesc, which is the number of Data Descriptors. In block 1104, the system sets wwk.sub.-- cImm equal to wb.sub.-- dsize, which is the number of bytes of immediate data. The variable wwk.sub.-- cImm controls the termination of the loop at block 1108. When there is no raw data, then the variable count controls the termination of the loop at block 1110. In block 1105, the system selects the first Data Descriptor, which is pointed to by wwk.sub.-- pDDesc. In block 1106, the system sets pCache.sub.-- buffer equal to dd.sub.-- addr of the selected Data Descriptor plus wwk.sub.-- cImm. At the termination of the loop, the variable pCache.sub.-- buffer will contain the offset into the selected cache buffer at which the first byte of raw data is to be stored. In block 1107, the system decrements wwk.sub.-- cImm by dd.sub.-- length of the selected Data Descriptor to account for the immediate data that will be moved to the selected cache buffer. In block 1108, if wwk.sub.-- cImm is less than or equal to 0, then the system has selected the Data Descriptor for the first byte of raw data and continues at block 1111, else the system continues at block 1109. In block 1109, the system selects the next Data Descriptor. In block 1110, the system decrements count and if count is not equal to 0, then not all the Data Descriptors for the immediate data have been set aside and the system loops to block 1106, else the system continues at block 1111. In block 1111, the system sets wwk.sub.-- cRaw equal to the negative of wwk.sub.-- cImm, which is the number of bytes of raw data that will fit into the last cache buffer of immediate data. In block 1112, the system sets pnb.sub.-- ncb.ncb.sub.-- cDesc equal to count, which is the number of Data Descriptors for the raw data. Referring to FIG. 11B, in blocks 1113 through 1118, the system initializes the Buffer Descriptors for the call to the network driver to receive the raw data. Before block 1113 is executed, the system has selected the first Data Descriptor for the raw data. In block 1113, the system selects the first Buffer Descriptor, which is at wwk.sub.-- bufDesc. In block 1114, the system sets bf.sub.-- DataPtr of the selected Buffer Descriptor equal to dd.sub.-- addr of the selected Buffer Descriptor, which points to the cache buffer for the selected Data Descriptor. In block 1115, the system sets bf.sub.-- DataLen of the selected Buffer Descriptor equal to dd.sub.-- length of the selected Data Descriptor. At block 1116, the system selects the next Data Descriptor. In block 1117, the system selects the next Buffer Descriptor. In block 1118, the system decrements count and if count is not equal to 0, then the system has not yet initialized all the Buffer Descriptors and loops to block 1114, else the system continues at block 1119. Before block 1119 is executed, the system has initialized the PNB and the Buffer Descriptors. The system is ready to issue the receive raw data request to the network driver. In block 1119, the system calls subroutine RawWrtWorker to issue this request. In blocks 1120 through 1126, the system moves the immediate data to the cache buffers. In block 1120, the system selects the first Data Descriptor. In block 1120A, the system sets wwk.sub.-- cImm equal to wb.sub.-- dsize; the variable wwk.sub.-- cImm controls the termination of the loop in block 1121. In block 1121, if wwk.sub.-- cImm equals 0, then the system has moved all the immediate data to the cache and continues at block 1127, else the system continues at block 1122. In block 1122, the system sets wwk.sub.-- cbytes equal to the minimum of wwk.sub.-- cImm and dd.sub.-- length of the selected Data Descriptor; the variable wwk.sub.-- cbytes equals the number of bytes to be written to the selected cache buffer. In block 1123, the system decrements wwk.sub.-- cImm by wwk.sub.-- cbytes to reflect the number of immediate bytes left to move. In block 1124, the system moves a group of immediate bytes to the selected buffer. In block 1125, the system advances a wwk.sub.-- pImm to point to the next group of immediate bytes to move. In block 1126, the system selects the next Data Descriptor and loops to block 1121. In block 1127A, the system calls subroutine NCBWait to wait until the network I/O is complete. In block 1127, the system calls subroutine WriteFree to write each of the cache buffers pointed to by the Data Descriptors to the file and removes the hold from the cache buffers. In block 1128, the system calls subroutine WriteFinish to update the directory for the file and remove the lock from the file and then the subroutine WriteRaw returns. WriteInit Subroutine The subroutine WriteInit locks the file, extends the file size if the data to be written extends beyond the current end of file, and calls subroutine SetupWD to initialize the Data Descriptor. The input parameters are the file handle, seek position, and number of bytes to write to the file. FIG. 12 shows a flow diagram of the subroutine WriteInit. In block 1201, the system selects the File Handle Table entry for the file. In block 1202, the system selects the Open File Table entry for the file, which is pointed to by the FHT. In block 1203, the system locks the file. In block 1204, the system extends the file size as appropriate. In block 1205, the system calls the subroutine SetupWD, which initializes the Data Descriptors and then returns from subroutine WriteInit. SetupWD Subroutine The subroutine SetupWD initializes the Data Descriptors with information for the receiving of data from the network. The subroutine is passed the file handle Fid, a pointer to the Data Descriptors wwk.sub.-- pDDesc, the seek position in the file seek.sub.-- position, and the number of bytes to write, wwk.sub.-- cbytes. FIGS. 13A and 13B are flow diagrams of the SetupWD subroutine. In block 1301, the system sets the local variable left.sub.-- to.sub.-- write.sub.-- file equal to wwk.sub.-- cbytes; the variable left.sub.-- to.sub.-- write.sub.-- file contains the number of bytes in the write request for which the system has not initialized a Data Descriptor. The system loops through blocks 1304 through 1322, selecting each extent in the file and initializing the Data Descriptors for the cache buffer in which the data for the selected extent is to be written. In block 1302, the system selects the first Data Descriptor. In block 1303, the system selects the first extent in the file and stores the sector address for the extent in local variable extent.sub.-- sector. In block 1304, the system computes the number of bytes in the extent and stores the result in local variable extent.sub.-- length. In block 1305, the system sets the local variable next.sub.-- sector equal to 4 times the integer portion of extent.sub.-- sector divided by 4; the variable next.sub.-- sector contains the sector number of the first sector associated with the Data Descriptor. In block 1306, the system sets the local variable left.sub.-- to.sub.-- write.sub.-- extent equal to extent.sub.-- length; the variable left.sub.-- to.sub.-- write.sub.-- extent contains the number of bytes that are to be written to the selected extent for which the system has not initialized a Data Descriptor. In block 1307, the system sets dd.sub.-- offset of the selected Data Descriptor equal to 512 (sector size) times the remainder of next.sub.-- sector divided by 4. The variable dd.sub.-- offset contains the offset in the cache buffer at which the write data will be stored. In block 1308, if the first Data Descriptor is selected, then the offset into the cache buffer may not be on a sector boundary and the system continues at block 1309, else the system continues at block 1310. In block 1309, the system increments dd.sub.-- offset by the remainder of seek.sub.-- position divided by 512 to account for seek positions that do not start on a sector boundary. In block 1310, the system sets dd.sub.-- length of the selected Data Descriptor equal to the minimum of 2K minus dd.sub.-- offset, left.sub.-- to.sub.-- write.sub.-- file, and left.sub.-- to.sub.-- write.sub.-- extent. In block 1311, the system sets dd.sub.-- sector.SNUM equal to next.sub.-- sector. In block 1312, the system selects a cache buffer in which to store the data for the selected extent. In a preferred embodiment, this selection is accomplished by a cache manager subroutine, which returns the address of the cache header for the selected buffer in pCache.sub.-- header. In block 1313, the system sets dd.sub.-- sector.SHINT equal to pCache.sub.-- header. In block 1314, the system increments the hold count, b.sub.-- hcnt for the selected cache buffer. In block 1315, the system sets dd.sub.-- addr equal to b.sub.-- addr, which is the address of the cache buffer. Referring to FIG. 13B, in blocks 1316 and 1318, the system updates certain variables for the next execution of the loop. In block 1316, the system decrements left.sub.-- to.sub.-- write.sub.-- extent by dd.sub.-- length of the selected Data Descriptor. In block 1317, the system decrements left.sub.-- to.sub.-- write.sub.-- file by dd.sub.-- length. In block 1318, the system increment next.sub.-- sector by 4 to give the sector number of the next sector in the extent. In block 1319, the system selects the next Data Descriptor. In block 1320, if left.sub.-- to.sub.-- write.sub.-- file equals 0, then the system has initialized all the Data Descriptors and the subroutine SetupWD returns, else the system continues at block 1321. In block 1321, if left.sub.-- to.sub.-- write.sub.-- extent equals 0, then the system has initialized the Data Descriptors for the recently selected extent and the system selects the next extent in block 1322 and loops to block 1304 in FIG. 13A to initialize the Data Descriptors for the selected extent, else the system loops to block 1307 in FIG. 13A to initialize the next Data Descriptor for the selected extent. WriteFree Subroutine The subroutine WriteFree writes each of the cache buffers that contains the received data to the disk and decrements the hold count of the cache buffers. The input parameters are wwk.sub.-- pDDesc, the pointer to the Data Descriptors, and wwk.sub.-- cDDesc, the number of Data Descriptors. FIG. 14 shows a flow diagram of the subroutine WriteFree. In block 1401, the system selects the first Data Descriptor. In block 1402, the system sets count equal to wwk.sub.-- cDDesc; the variable count controls the number of times the loop comprising blocks 1403 through 1408 is executed. In block 1403, the system selects the cache header pointed to by dd.sub.-- sector.SHINT of the selected Data Descriptor. In block 1404, the system sets the number of bytes from the selected cache buffer that are to be written to disk. In block 1405, the system decrements the hold count, b.sub.-- hcnt, for the cache buffer. In block 1406, the system calls subroutine WriteBuffer to write the data in the selected cache buffer to disk. In block 1407, the system selects the next Data Descriptor. In block 1408, the system decrements count and if count equals 0, then the subroutine WriteFree returns, else the system loops to block 1403 to write the next cache buffer. WriteFinish Subroutine The subroutine WriteFinish updates the directory for the file and removes the lock on the file. The input parameter is file handle. FIG. 15 is a flow diagram of the WriteFinish subroutine. In block 1501, the system selects the File Handle Table entry for the file. In block 1502, the system selects the Open File Table entry for the file, which is pointed to by the FHT. In block 1503, the system calls subroutine UpdateDirectory, which updates the directory information for the file. In block 1504, the system removes the lock from the file and the subroutine returns. Although the present invention has been described in terms of a preferred embodiment, it is not intended that the invention be limited to these embodiments. Modifications within the spirit of the invention will be apparent to those skilled in the art. For example, the different data structures may be used and a different internal organization of the subroutines may be used with acceptable results. The scope of the present invention is defined by the claims that follow.
|
Same subclass Same class Consider this |
||||||||||
