NVRAM Module
Logo Image
Phase 1 Rewrite

3 NVRAM Module

All of NVRAM is partitioned into three contiguous memory spaces, referred to here as the memory map. Each partition is called a file and each file is subdivided into 2K blocks.

Since all of NVRAM is actually a single system file, data is read from it and written to it in a serial manner. Each file is accessed by first doing a file seek to one of the mapped partition boundaries. It is assumed that the boundary is aligned to a 2K block, and that all subsequent accesses are performed in 2K block increments.

There are seven basic file operations supported; open, seek, read, write, delete, ioctl and close.

A seek operation sets both the file address pointer and the file block pointer, and calls the low level seek operation of the nvram media type.

A read operation may be preceded by a seek operation to find the 2K block with the specified address. Otherwise the default block is the one with the current address pointed to by the file-address pointer. Thus a read begins at the end of the previous write or delete, and successive reads begin at the end of the last read.

A write operation assumes some buffered data will be inserted at the current file pointer location, and that the subsequent file data will be shifted over to make room. The one exception is following a read, in which case the data that was previously read is overwritten, and the subsequent file data is shifted accordingly. In legacy code the file data is contiguous and so all the file data will be shifted.

The nvram module also supports non-contiguous file data whereby if the data is shifted left, the data length of the current block is shortened. If the data is shifted right and the new length exceeds the block length then the following block data is shifted, too, and so on until either enough unused block space is used to store the data or all the file data is shifted.

If a write operation is preceded by a seek operation then the write begins at the current file address. Otherwise the default write address is either the current file-address if preceded by a write, or the previous file-address if preceded by a read. In this way a series of api read and write operations, i.e. read, read, write, read, etc. do not appear to require any intervening api seek operations. In fact, the underlying write algorithm automatically determines the correct file-address.

A delete operation will remove a specified amount of data beginning at a specified start location by shifting the subsequent file data over it. In legacy code the file data is contiguous, which means that all the subsequent file data is read and written in a series of 2K block increments. The nvram module also supports non-contiguous file data where a delete operation would shift the data within the current block only, shortening the block data length.

There are four basic i/o control (ioctl) operations supported: permissions, compression, memap, and file stats. These ioctl operations are executed through API function calls. The permissions option is primarily for private config access, but it is configurable for all mapped files, as is true for data compression. The memap option is used to readjust the memory mapped file partitions, and file stats returns info about a specified mapped file.

3.1 Memory Map Descriptor Block

The NVRAM module begins with the memory map descriptor block. The descriptor is a global structure that defines the memory map. It's declared static and is accessible only within the NVRAM module.
 
The memory map control block contains the magic number field followed by the total mem_size of NVRAM. The smallest increment of memory allocated is the block_size, and the map_type specifies which map is currently in use, i.e. the legacy memory map or a new style memory map.

The memory map has three partitions and thus three map[] partition descriptor blocks, one for each of the following files: startup config, private config and persistent data. The descriptor block stores info specific to each partition. Adding another file to NVRAM requires another descriptor block and a new map.
 
Memory Map Descriptor Block
The node_list is a pointer to a linked list of "active nodes", or current users of NVRAM, and each node structure keeps track of the current file offset and the buffered data from the last read. The node structure is created and freed by API calls to open and close an NVRAM file, except for the leagcy API which uses a static node structure and thus has limited functionality, i.e. one legacy calling process at a time, etc. 

3.2 Partition Descriptor Block

With respect to the NVRAM memory map, a partition refers to the boundaries of each mapped memory space. It's called a partition because all memory reads and writes are checked and are prevented from accessing memory outside the boundaries. These checks can be used to generate messages about insufficient memory, and the descriptor blocks can be scanned by ioctl api functions to determine the memory usage of each partition. It would then be possible to distribute memory more efficiently by copying out the files and repartitioning NVRAM to create a new memory map.

*** The number of partitions is hard coded but the boundaries are dynamic.
 
The file_name field is the name of the mapped memory and the file_offset field is the number of bytes up to it's partition boundary starting from the beginning of NVRAM.

The file_length is the total number of bytes from the start of the file to the partition boundary of the next file. Assume that the boundaries are 2K block aligned.

The bytes_used field is the current byte count of the data stored in the file. The byte count between the bytes_used and the file_length is the available space left in the file.

Memory Descriptor Block
The permissions field is a bit-mapped control register that sets three levels of access control for each file: private, group and public. The default setting is public access, except for the private config file which defaults to private access. There is also a permissions field in the node structure (section 3.3) of an opened file which defaults to public. The file permissions are compared to the node permissions just before an access is performed, instead of when the file is opened. So, to access the private config file a calling process must take the extra step of setting it's node permissions to private after opening the file.

The reserved field is reserved.

The compression field indicates whether or not the data is stored compressed.

The access_que watched semaphore allows a process to suspend and wait for access if a read or write operation returns with a "busy" error. This can happen if another process got suspended during an access operation. Note that the nvram module will open nvram, retrieve the requested file data, and close nvram before returning the data to the calling process. This allows the calling process to suspend itself for any length of time without locking access to nvram.

3.3 Node Descriptor Block

The node descriptor block is used by a process to gain access to NVRAM. It is allocated and initialized by the call to open an NVRAM file and is stored on a linked list of node descriptors. The node is referenced by a file descriptor value that was returned to the calling process when the file was opened, and the node is freed when the calling process closes the file.

Note that the file name does not have to be one of the partitioned files in NVRAM but could be any file on any media that is supported by a path/file string. However, the file can only be accessed through the NVRAM api, which has specialized functionality. The reason for accepting non-nvram file names is to support access to remote NVRAM memory on a secondary router.

The name is the requested file name passed by the calling process. It is the full ifs file name.
 
The fid is the file descriptor value returned by an open() command. It is passed to all read, write, close and ioctl calls. The value is unique to all opened files but may be reused after the file is closed.

The offset field is the file offset of the node, which is kept current since the file was opened.

The allocated buffer holds bufsize bytes of data from the last read.

The update field indicates that the buffered data hasn't been written yet. It is only used at init time to postpone the update.

The map field points to the array of partition structures that describe the NVRAM memory map. 

Node Structure
The permissions field is a bit-mapped control register that sets three levels of access control for the node: private, group and public. The default setting is public access. There is also a permissions field in the file structure (section 3.2). The node permissions are compared to the file permissions just before an access is performed.
 
[ Prev Section : 2
[ Contents ]
[ Next Section : 4 ]