13.4 Direct File System Overview

NetWare Direct File System (DFS) functions provide a method of bypassing the NetWare disk caching subsystem. The NetWare cache provides the best possible throughput and should not normally be bypassed. However, several applications exist where this bypass might be desirable:

The DFS functions provide a standardized solution by bypassing the NetWare disk caching, while providing more direct control of file allocation. The DFS functions fall into two groups: basic direct mode file I/O, and file allocation primitives.

The following figure illustrates the DFS as it interfaces with the file system, applications, and other portions of the NetWare OS.

Figure 13-1 DFS Interface Flow Chart

This section describes the following features of DFS:

13.4.1 File Allocation

The DFS allocation functions allow a great deal of control in determining where and how file space is allocated. The application NLM might allow the OS to allocate required space for a file using OS default allocation, or might request allocation to be on a specific volume segment and/or specify the actual volume blocks to be allocated. File allocation can be used to fill holes in sparse files or to extend existing files. Writing to a nonexistent area in a file (either to a hole or beyond the allocated file space) is not allowed with the DFS functions.

Setting the File Size and Zero-Filling with DFS

The size of a file can be specified independent of the actual file space allocated by calling dfs_seteof. Reads attempted beyond the current end-of-file (indicated by the file size) are always rejected as an attempted operation beyond the current file size.

If the file size is expanded beyond its previous value, the additional file area incorporated in the new file size is zero-filled, provided that the file space is actually allocated. If the file size specified is smaller than the previously indicated file size and the trunctatedBlockFlag parameter is nonzero, blocks previously allocated beyond the newly defined file size are truncated, that is, returned to the OS for future use.

The file size is also modified by calling dfs_write, indicating a write to a file sector address beyond the current file size (the file size is updated accordingly) but within the range of blocks allocated for the file. If the write does not start immediately following the current file size, the intervening blocks are zero-filled.

When a file has additional space allocated at the end of the file by calling dfs_extend, the additional file space is not zero-filled immediately. Subsequent writes to the file set a new file size and eliminate the requirement to zero-fill the additional file space. Calling dfs_seteof also sets a new file size, and zero-fills any sectors in the new file size that are beyond the previous file size.

When a file has additional space allocated to fill a hole in a sparse file, the dfs_extend function also zero-fills the additional space if the space is not beyond the current file size.

See the following related tasks as well:

Impact of Striping

Causing a file to be allocated with striping has different effects on different configurations. A drive array normally provides optimum throughput using internal striping, so specifying striping by the OS in this case would defeat optimum throughput, while specifying striping on files on a SCSI host adapter providing disconnect with multiple drives normally provides more optimal performance. Striping does not necessarily provide significant performance benefits for extremely large files accessed in true random fashion, but provides performance benefits when accessed sequentially.

13.4.2 File Locks

All DFS application file, record, and field locks must be provided and managed by the DFS application. OS utilities that are designed to perform reorganization or relocation of DFS files use an exclusive lock on the file, so that the lock fails if the file is currently in use by an application. An application need only lock the file with a shared or nonexclusive lock to ensure that an OS utility NLM has not exclusively locked the file for operations such as reorganization.

OS audtiting, if enabled, is performed at the file level. The database application must perform its own auditing of access to database records and fields, since DFS is not aware of the actual record and field definitions.

Input and Output

An open file is in one of two possible modes: normal mode or direct mode. In a normal open mode, any of the valid opens are used. For direct open mode, the dfs_sopen function is used. If a file is already open in normal mode and dfs_sopen is called, the file changes from the normal mode to the direct mode.

In this condition, any files in the normal open mode can continue to be read, but attempts to write to the file fail. Programs using the direct mode can read and write to the file successfully. The only way to write to files in the normal open mode again is by closing all direct mode opens, and closing and re-opening the normal mode open.

When a file is successfully opened for direct file I/O by calling dfs_sopen, the server opens the file, flushes all cache entries for the file, and flags the file so that future I/Os do not use caching functions. Subsequent file I/O must be done using the I/O functions dfs_read, dfs_readnowait, dfs_write, or dfs_writenowait. The "no wait" versions of these functions do not block execution of the thread until completion, thus allowing a single thread to have multiple outstanding DFS I/O functions.

When direct file I/O operations are completed, the file must be closed by calling dfs_close. The file must not be used for normal I/O writes until all handles are relinquished for the file by calling dfs_close, followed by a normal open. If a normal open exists, it must be closed and reopened for writes.

When a file is in Direct mode, writes must not be made to areas of the file where a hole exists (sparse files) or beyond the file’s currently allocated last block address. Read operations to these areas are successful, and the data area is zeroed.

A file cannot be extended while in direct mode by writing beyond its current extents. A separate call to dfs_extend must be made to extend a file or to fill in holes in a file area.

13.4.3 File Structures

Files in direct file mode can be viewed as an array of sectors numbered from zero to n, where n is the last sector in the last block currently allocated for the file. All direct file I/O must be done in multiples of sectors (one or more). The sectors allocated in the file are actually allocated on an allocation block size, which is either 4 KB, 8 KB, 16 KB, 32 KB, or 64 KB on NetWare. The allocation size must be specified for a volume when the volume is created.

It is possible to create files that have blocks allocated for high addresses, but do not have blocks allocated for intermediate addresses. (Such files are called sparse files, and have holes in their actual allocation space). Normal (non-direct) I/O allows writes to be made into these holes or beyond the current end of allocated space for a file, in which case space is automatically allocated to fill the hole or extend the file. However, the Direct File System does not allow such writes when the file is in direct mode. Files must be extended before writes can be issued to holes or beyond the end of the allocated space for a file.

The logical block address of the blocks in the above array are referred to as File Block Addresses, and the associated logical sector addresses are referred to as File Sector Addresses. These addresses exist even for holes in the file, though actual storage space might not have been allocated for the corresponding locations on the file.

No space is allocated when a file is initially created by dfs_creat or dfs_sopen. All space must be allocated by the application process for files in direct mode, and the space must be allocated on the same volume.

When a file not currently opened by another process is opened in direct mode, the OS creates a turbo FAT for the file if one does not currently exist, flushes the cache of entries for the file, and marks the file as open in direct mode (only direct mode operations are allowed).

The following figures shows a file with 4 KB allocation block size and only one block allocated:

Figure 13-2 One Allocated Block (4 KB)

The following figure shows a file with 4 KB allocation block size and four blocks allocated (no holes):

Figure 13-3 Four Allocated Blocks (4 KB each with no holes)

The following figure shows a file with 4 KB allocation block size and three blocks allocated (with hole):

Figure 13-4 Three Allocated Blocks (4 KB each with hole)

The following figure shows a file with 64 KB allocation and three blocks allocated (with hole):

Figure 13-5 Three Allocated Blocks (64 KB each with hole)

The following figure shows a file with 8 KB allocation block size and three blocks allocated (no holes):

Figure 13-6 Three Allocated Blocks (8 KB each with no holes)

13.4.4 Volume Structures

NetWare® volumes can be viewed as an array of allocation blocks numbered from zero to n, where n is the total number of allocation blocks in all segments of the volume (volume segments), minus one. Volumes can be extended by adding additional segments, which are logically added at the end of the list of current volume segments. Each logical block number in the logical array of volume blocks is referred to by a Volume Block Number. There are no holes in the volume block numbers. (Using this organization, a specific volume block number also indirectly indicates the segment upon which it occurs in the list of volume segments.)

NetWare supports a maximum of 255 volumes, with a NetWare volume consisting of from 1 to 64 segments.

Multiple volume segments can exist on a single logical NetWare partition on a drive. It is also possible that a drive has a single volume segment on it. A Logical partition has blocks numbered logically from zero through the last block available in the partition, and does not include the physical partition blocks which are allocated for Hot Fix™ and Mirroring tables at the time the NetWare partition is created.

The following figure shows a volume with a single volume segment (9444 volume blocks):

Figure 13-7 Single Volume Segment

The following figure shows a volume with four volume segments (25288 volume blocks):

Figure 13-8 Four Volume Segments

13.4.5 DFS Return Values

The following table lists and defines the DFS return values:

Decimal

Constant

Description

-1

DFS_FAILURE

The requested operation was not completed.

0

DFS_SUCCESS

The operation was completed as specified.

1

DFS_ERR_INSUFFICIENT_SPACE

The volume does not have the required space to expand the file as requested.

4

DFS_ERR_VOLUME_SEGMENT_ DEACTIVATED

The volume segments on which the file is located have been deactivated by the operating system.

16

DFS_ERR_TRUNCATION_FAILURE

dfs_seteof detected that the caller requested excess blocks to be truncated, but the file was open for other connections, causing the request to be rejected.

17

DFS_ERR_HOLE_IN_FILE

An operation (read or write) was requested for one or more file sectors where file space has not been allocated (a sparse file). The buffer is also zeroed for read functions.

18

DFS_ERR_PARAMETER

The function caller supplied an invalid parameter.

19

DFS_ERR_OVERLAP

An attempt was made to allocate additional file space where file blocks already exist.

20

DFS_ERR_SEGMENT

The volume does not have a segment that matches the request.

21

DFS_ERR_BOUNDARY

One or more blocks in the range requested are not currently available, or are not in the volume or volume segment specified.

22

DFS_ERR_INSUFFICIENT_LIMBO_ FILE_SPACE

The request could not be completed because there were not enough contiguous limbo blocks to complete the request successfully.

23

DFS_ERR_NOT_IN_DIRECT_FILE_MODE

A function requiring a file to be opened in direct mode (using dfs_sopen or dfs_creat) was requested, but the file is not currently opened in direct mode.

24

DFS_ERR_OPERATION_BEYOND_ EOF

A read operation was requested beyond the end-of-file (current file size).

129

DFS_ERR_OUT_OF_FILDES

All available handles for the file are already in use.

131

DFS_ERR_HARD_IO

Problem decompressing or insufficient allocatable space.

136

DFS_ERR_EBADF

A DFS function was called using a file handle that is not valid—typically an open was omitted or the user inadvertently closed the file before attempting this access.

147

DFS_ERR_CANT_READ

The current connection does not have read privileges for the file.

148

DFS_ERR_CANT_WRITE

The current connection does not have write privileges for the file.

149

DFS_ERR_FILE_DETACHED

The file system will not allow further processing on this handle.

150

DFS_ERR_ENOMEM

The Direct File System could not obtain sufficient memory to complete the requested function.

152

DFS_ERR_INVALID_VOLUME

The volume number specified does not exist ,or the volume is not mounted.

13.4.6 Overview of the DFS Functions

These functions allow you to directly manage file system objects:

dfs_close

Closes a file that is open in direct file mode.

dfs_creat

Creates and opens a file in direct file mode, and returns a file handle.

dfs_extend

Expands a file with a range of contiguous blocks.

dfs_freelimbospace

Frees a number of limbo blocks on a volume.

dfs_read

Reads sectors from a file in direct file mode, sleeping until completion.

dfs_readnowait

Reads sectors from a file in direct file mode, returning immediately after initiation.

dfs_getfilemapinfo

Returns file extents, each with number of blocks and starting file and volume block numbers.

dfs_getvolblockinfo

Returns volume block usage bitmap.

dfs_getvolmapinfo

Returns information about a volume required for file allocation.

dfs_seteof

Sets the file size of a file.

dfs_sopen

Opens a file in direct file mode.

dfs_write

Writes sectors into a file in the direct file mode, sleeping until completion.

dfs_writenowait

Writes sectors into a file in direct file mode, returning immediately after initiation.