NVRAM Module
Logo Image
Phase 1 Rewrite

4 NVRAM API

A description of the NVRAM api is, in fact, a description of the modules programming environment. To put it another way, everything a developer needs in order to use this module is defined and declared in a single api header file. The following is a description of that file, and since definitions are at the top, the first topic is about the access control bits. 

4.1 Access Control

File access control is implemented using file permission bits. The permissions field exists on a stored file and it exists on each instance where that file is opened, called a node. There are three levels of access permissions, and each file is hard coded with a specific level of access in mind. Thus the private config file has only it's private read and write bits set and nothing else.

When an attempt is made to either a read or a write a file, the node permissions are checked against the file permissions. To gain access to private files the default node permissions must first be modified to match the file permissions. This affords a certain amount of control by requiring an explicit api function call to gain access to files other than public ones. The api function could implement any method of access control, though in this case it simply sets the specified bits if appropriate.
 
The permissions field for each level of both the file structure and the node structure support just two types of access: read and write.  These permission bits are defined for all three levels of access, public, group and private. The default node permissions are set when the file is opened.

To change the node permissions for private access, for example, the P_PRI_RDWR bits would be passed to the access control api function.

Note that the permissions bit map is similar to unix file permissions and indeed all the bits can be modified, but the undefined bits are reserved and should not be set.
Permissions Definitions

When a file is opened the complete ifs file name is passed, along with one of five possible access types. Each type is in fact a bit mask that specifies which node permissions can be modified. Thus a file that is opened as read-only can't be configured writable simply by changing permissions.

The mask pattern is used to mask out all but the selected access type or types from the node's permissions. For example, a file opened as read-only would mask out the "write" permissions in all the levels of the node, i.e. private, group and public.
Open Flags

During a read or write api call the masked node permissions are compared to the file permissions and if the access type (rd, wr) is set in both then access is granted. Otherwise an error is returned indicating "permission denied."

For example, if a file is hard coded for private read and write, group read, and public write, and it is opened for reading and writing, then by default the node would have only public write access, i.e. a drop box. If the permissions are then set to group, the node would have only read access. If the permissions were then set to private the node would have read and write access.

If the same file is opened read-only, the default would be no public access, and group and private would both be read-only.

4.2 IOCTL Commands


  [ details ]
ioctl Structure



 
  [ details ]
getstats structure

4.3 Error Handling

**** A read and a write operation will actually _lock, _open, _seek, _access, _close, and _unlock all of NVRAM before returning with the results. This approach appears to allow concurrent file accesses by multiple processes. Ideally this procedure would not be allowed to suspend, though in practice a platform with a lot of memory could result in data transfers that take too long. This means that a read or write function call has the potential to return a "busy" error because some other process was suspended during a long read or write operation.

**** Every api function has the potential to return a negative value that specifies an error, and it's up to the calling process to handle all errors. In case of a "busy" error (E_BUSY), for example, the simplest response is to call the api suspend function that waits on the file's watched semaphore. 

There is a set number of errors defined for this module and no other error codes will be returned.

The module has it's own debug logging facility so the calling process is not obligated to decode all the return codes, and can choose to simply exit on any negative return value.
Error Code Definitions

4.4 API Function Declarations

/*
 *
 */

typedef int nvfid_t;
typedef int nvopen_t;
typedef int nvfrom_t;

enum {
    NO_SUSPEND,
   SUSPEND_OK,
};

#define NV_FILESIZE   -2
#define NV_MAXSIZE  -1



/*
 * Function: nvfid_t  nvram_open()
 *
 *         Initializes a file node structure that is used for file access. If the file is valid and
 *         the open is successful a reference to the node structure is returned.
 *
 * Parameter: char  *fname
 *
 *        The ifs file name for nvram and a sub-file name from the nvram file space
 *        separated by a colon.
 *
 *            Example: "nvram:startup-config"
 *
* Parameter: nvopen_t  otype
 *
 *        Specifies one of the following opened-file modes:
 *
 *            F_READ, F_WRITE, F_RDWR, F_APPEND, F_ERASE.
 *
 * Parameter: boolean  suspend_ok
 *
 *        When set to TRUE allows a read or write operation to suspend and wait for access
 *        if nvram returns an E_BUSY error. When set to FALSE the read or write function
 *        call will return the busy error code.
 *         
 * Returns: nvfid_t fid
 *
 *        On success function returns a positive value file identifier. On error function 
 *        returns one of the following negative error values:
 * 
 *            E_NOENT, E_NODEV, E_NOMEM, E_INVAL
 */

extern nvfid_t nvram_open(char  *fname, nvopen_t  otype, boolean  suspend_ok);
 
 
/*
 * Function: int nvram_read()
 *
 *        Locks and opens nvram, seeks the file offset that was saved after the last access,
 *        reads a buffer size of data into the provided buffer and then closes and unlocks nvram.
 *
 * Parameter: nvfid_t  fid
 *
 *        Reference to the opened file node structure.
 *
 * Parameter: char *buffer
 *
 *        Pointer to a data buffer provided by the process.
 *
 * Parameter: int  bufsize
 *
 *        The amount of requested data in bytes. The bufsize value can be any amount up
 *        to the maximum file size. Larger values are truncated.
 *
 * Returns: int bytes
 *
 *        On success function returns a positive value that is the number of bytes read.
 *        On error the function returns one of the following negative error values:
 * 
 *            E_BADF, E_NOMEM, E_BUSY, E_INVAL, E_ACCESS, F_EOF
 */

extern int nvram_read(nvfid_t fid, char *buffer, int bufsize);
 
 
/*
 * Function: nvfid_t nvram_write()
 *
 *         Locks and opens nvram, seeks the file offset that was saved after the last
 *         access, writes a buffer size of data from the provided buffer and then closes
 *         and unlocks nvram. The write algorithm determines where data is overwritten
 *         and where data is inserted.
 *
 * Parameter: nvfid_t  fid
 *
 *        Reference to the opened file node structure.
 *
 * Parameter: char *buffer
 *
 *        Pointer to the data buffer provided by the process.
 *
 * Parameter: int  bufsize
 *
 *        The amount of buffered data to write in bytes. The write can be for any amount
 *         of data up to the size of the buffer.
 *
 * Returns: int bytes
 *
 *        On success function returns a positive value that is the number of bytes written.
 *        On error the function returns one of the following negative error values:
 * 
 *            E_BADF, E_NOSPC, E_BUSY, E_INVAL, E_ACCESS
 */

extern int nvram_write(nvfid_t fid, char *buffer, int bufsize);
 
 
/*
 * Function: nvfid_t nvram_seek()
 *
 *        Sets the offset from the beginning of the file for reading or writing. In fact nvram is
 *        never actually opened.
 *
 * Parameter: nvfid_t  fid
 *
 *        Reference to the opened file node structure.
 *
 * Parameter: int  offset
 *
 *        The offset from the beginning of the file, stored after each read or write.
 *
 * Parameter:  nvfrom_t  from
 *
 *        Specifies whether the offset parameter value is relative the the beginning of the file,
 *        or relative to the current location, or relative to the end of the file. In all cases the
 *        calculated value that is stored is the offset from the beginning of the file. The from
 *        parameter can be any value, plus or minus, within the bounds of the file. If the
 *        value is greater that EOF, but not greater that the boundary, the end-of-file is moved
 *        to the new location. Here are the flag settings:
 *
 *            NVSEEK_SET, NVSEEK_CUR, NVSEEK_END
 *
 * Returns: int error
 *
 *        
On success function returns zero, else it returns one of the following
 *        negative error values:
 *
 *           
E_BADF, E_NOSPC, E_INVAL, E_ACCESS
 */

extern int nvram_seek(nvfid_t fid, int offset, nvfrom_t from);
 
 
/*
 * Function: nvfid_t nvram_ioctl()
 *
 *        Issues commands to review or modify certain file statistics. Two commands
 *        modify the file and two commands modify the node structure.
 *
 * Parameter: nvfid_t  fid
 *
 *        Reference to the opened file node structure.
 *
 * Parameter:  nvioctl_t  cmd
 *
 *        One of the five control  commands:
 *
 *            NVIO_GETSTATS, NVIO_SETMAP, NVIO_SETPERM,
 *            NVIO_TIMEOUT, NVIO_COMPRESS
 *
 * Parameter: nviostats_t   *parms
 *
 *       The api data structure used to pass info between the nvram module and
 *        the calling process.
 *
 * Returns: int return_code
 *
 *        
On success function returns zero, else it returns one of the following
 *        negative error values:
 *
 *            E_BADF, E_INVAL, E_ACCESS, E_NOENT, E_NOMEM
 */

extern int  nvram_ioctl(nvfid_t fid, nvioctl_t cmd, void *arg);
 
 
/*
 * Function: nvfid_t nvram_close()
 *
 *        Frees the file node structure that is used for file access, and marks the
 *        file identifier as unused.
 *
 * Parameter: nvfid_t  fid
 *
 *        Reference to the opened file node structure.
 *
 * Returns: int return_code
 *
 *        
On success function returns zero, else it returns one of the following
 *        negative error values:
 *
 *            
E_BADF, E_INVAL
 */

extern int nvram_close(nvfid_t fid);

 
[ Prev Section : 3
[ Contents ]
[ Next Section : 5 ]