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.
|
|
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.