nvfile.c revision fcf3ce441efd61da9bb2884968af01cb7c1452cc
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "iscsi.h"
#include "nvfile.h"
#define NVF_GETF 16
static kmutex_t nvf_getf_lock;
/*
* file names
*/
#define NVF_FILENAME "/etc/iscsi/iscsi"
#define NVF_CURR_FILE_SUFFIX "dbc"
#define NVF_PREV_FILE_SUFFIX "dbp"
#define NVF_TMP_FILENAME "/etc/iscsi/iscsi.dbt"
#define NVF_MAX_FILENAME_LEN 40
/*
* file header definitions
*/
#define NVF_HDR_VERSION 1
#define NVF_HDR_SIZE 128
/*
* file flag definitions
*
* These flags describe the current state of reading or writing
*
*/
/*
* file flush time constants
*/
/*
* file access operations
*/
static void nvf_releasef(int fdes);
static int nvf_remove(char *filename);
int nvf_errno;
/*
* file header data structure definition
*
* This data structure definition was derived from a like data structure
*
* This header is larger than need in order to support extensability in the
* future
*
*/
typedef struct nvf_hdr {
union {
struct hdr {
} h_info;
} h_u;
} nvf_hdr_t;
/*
* Local Global Variables
*/
static char nvf_curr_filename[NVF_MAX_FILENAME_LEN];
static char nvf_prev_filename[NVF_MAX_FILENAME_LEN];
/*
* Local Function Prototypes
*/
static void nvf_thread(void *arg);
/*
*/
void
nvf_init(void)
{
nvf_flags = 0;
nvf_thread_id = 0;
nvf_thread_ticks = 0;
}
void
nvf_fini(void)
{
if (NVF_IS_SCHED(nvf_flags)) {
nvf_thread_ticks = 0;
(void) untimeout(nvf_thread_id);
}
if (nvf_list) {
}
}
/*
*/
nvf_load(void)
{
/*
* try to load current file
*/
return (rval);
} else {
/*
* Rename current file to add corrupted suffix
*/
"%s.corrupt", nvf_curr_filename);
}
/*
* try to load previous file
*/
return (rval);
} else {
/*
* Rename previous file to add corrupted suffix
*/
"%s.corrupt", nvf_prev_filename);
}
/*
* non-existent or corrupted files are OK. We just create
* an empty root nvlist and then write to file when
* something added. However, ensure that any current root nvlist
* is deallocated before allocating a new one.
*/
}
if (rval != 0) {
"allocate root list (%d)", rval);
}
}
/*
*
*
*/
void
nvf_update(void)
{
/*
* set dirty flag to indicate data flush is needed
*/
/*
* If thread is already started just update number of
* ticks before flush, otherwise start thread and set
* number of ticks. The thread will is responsible
* for starting the actual store to file.
*
* If update error occured previously, reschedule flush to
* occur almost immediately. If error still exists, the
* update thread will be backed off again
*/
if (!NVF_IS_SCHED(nvf_flags)) {
} else {
/*
* If update error occured previously, reschedule flush
* attempt to occur quickly. If an error still exists
* after a flush attempt, the update thread will be backed
* off again
*/
(void) untimeout(nvf_thread_id);
} else {
}
}
}
/*
* nvf_data_check -- check if specified list exists
*/
nvf_list_check(char *id)
{
int rval;
/*
* find the specified list
*/
}
/*
* nvf_node_value_set - store value associated with node
*/
{
int rval;
return (B_FALSE);
}
/*
* update value. If value already exists, it will be replaced
* by this update.
*/
if (rval == 0) {
/*
* value was set, so update associated file
*/
nvf_update();
} else {
}
}
/*
* nvf_node_value_get - obtain value associated with node
*/
{
return (B_FALSE);
}
}
/*
* nvf_node_name_set - store a specific type of name
*/
{
return (B_FALSE);
}
if (rval == 0) {
nvf_update();
} else {
}
}
/*
* nvf_node_name_get - return a specific type of name
*/
{
char *tmpname;
return (B_FALSE);
}
if (rval == 0) {
/*
* ensure name is able to fit into given buffer
*/
} else {
"unable to fit %s node name into buffer %d %s",
}
} else {
}
return (rval);
}
/*
* nvf_node_data_set -- store data element associated with node
*/
{
int rval;
return (B_FALSE);
}
/*
* update the address configuration element in the specific
* list. If this element already exists, it will be
* replaced by this update.
*/
if (rval == 0) {
/*
* data was set, so update associated file
*/
nvf_update();
} else {
}
}
/*
* nvf_node_data_get -- obtain a data element associated with node
*/
{
int rval = 0;
return (ISCSI_NVFILE_NVF_LIST_NOT_FOUND);
}
if (rval == 0) {
/*
* ensure data is able to fit into given buffer
*/
} else {
}
} else {
}
return (status);
}
/*
* nvf_node_data_clear -- remove a data element associated with node
*/
nvf_node_data_clear(char *name)
{
int rval;
return (B_FALSE);
}
/*
* remove the specified data element
*/
if (rval == 0) {
/*
* data was set, so update associated file
*/
nvf_update();
}
}
/*
* nvf_data_set -- store a data element in the specified list
*/
{
int rval;
return (B_FALSE);
}
/*
* find the specified list
*/
if (rval != 0) {
if (rval != 0) {
return (B_FALSE);
}
list_alloc = B_TRUE;
}
/*
* update the data element in the specified list. If this element
* already exists, it will be replaced by this update.
*/
if (rval == 0) {
if (rval != 0) {
return (B_FALSE);
}
/*
* data was set, so update file
*/
nvf_update();
} else {
}
if (list_alloc) {
}
}
/*
* nvf_data_get -- get a data element from the specified list
*/
{
int rval;
return (B_FALSE);
}
/*
* find the specified list
*/
if (rval != 0) {
return (B_FALSE);
}
/* obtain data element from list */
if (rval == 0) {
/*
* ensure data is able to fit into given buffer
*/
} else {
}
}
}
/*
* nvf_data_next -- get the next data element in the specified list
*/
{
int rval;
return (B_FALSE);
}
/*
* find the specified list
*/
if (rval != 0) {
return (B_FALSE);
}
/*
* get the next nvpair data item in the list
*/
*v = (void *)pair;
return (B_FALSE);
}
/*
* get the data bytes
*/
if (rval != 0) {
return (B_FALSE);
}
/*
* ensure data is able to fit into given buffer
*/
} else {
}
return (B_TRUE);
}
/*
* nvf_data_clear -- remove a data element from the specified list
*/
{
return (B_FALSE);
}
/*
* find the specified list
*/
if (rval != 0) {
return (B_FALSE);
}
/*
* remove the specified data element
*/
if (rval == 0) {
/*
* data was set, so update associated file
*/
nvf_update();
}
}
/*
* +--------------------------------------------------------------------+
* | Internal Helper Functions |
* +--------------------------------------------------------------------+
*/
/*
* nvf_cksum - calculate checksum of given buffer.
*
* This function was derived from like function (nvp_cksum) in
*/
static uint16_t
{
int64_t n;
if ((buflen & 0x01) != 0) {
buflen--;
}
n = buflen / 2;
while (n-- > 0)
cksum ^= *p++;
return (cksum);
}
/*
* should occur.
*/
/* ARGSUSED */
static void
nvf_thread(void *arg)
{
/*
* check whether its time to write to file. If not, reschedule self
*/
if (nticks > NVF_RESCHED_MIN_TICKS) {
if (NVF_IS_ACTIVE(nvf_flags)) {
}
return;
}
/*
*/
nvf_flags &= ~NVF_FLUSHING;
if (nvf_written_once) {
"!iscsi persistent store update "
"failed file:%s", nvf_curr_filename);
}
}
"filename:%s", nvf_curr_filename);
}
/*
* re-check whether data is dirty and reschedule if necessary
*/
if (nticks > NVF_FLUSH_DELAY) {
} else {
}
} else {
}
}
/*
*
*/
static boolean_t
nvf_flush(void)
{
int rval;
char *nvfbuf;
char *nvlbuf;
int file;
int bytes_written;
/*
* duplicate data so access isn't blocked while writing to disk
*/
if (rval != 0) {
"duplicate nvf_list (%d)", rval);
return (B_FALSE);
}
/*
* pack duplicated list to get ready for file write
*/
if (rval != 0) {
"nvf_list (%d)", rval);
return (B_FALSE);
}
/*
* allocate buffer to store both the header and the data.
*/
/*
* fill buffer with contents of file header
*/
nvllen);
sizeof (nvf_hdr_t));
/*
* copy packed nvlist into buffer
*/
/*
* free memory used for packed nvlist
*/
/*
* To make it unlikely we suffer data loss, write
* data to the new temporary file. Once successful
* complete the transaction by renaming the new file
* to replace the previous.
*/
/*
* remove temporary file to ensure data content is written correctly
*/
if (rval == -1) {
return (B_FALSE);
}
/*
* create tempororary file
*/
if (file == -1) {
if (nvf_written_once) {
"!iscsi persistent store failed to create "
}
return (B_FALSE);
}
/*
* write data to tempororary file
*/
if (bytes_written == -1) {
return (B_FALSE);
}
if (bytes_written != nvflen) {
"%s (errno:%d)\n\tpartial write %d of %ld bytes\n",
return (B_FALSE);
}
/*
* close tempororary file
*/
if (rval == -1) {
return (B_FALSE);
}
/*
* File has been written. Set flag to allow the create and update
* messages to be displayed in case of create or update failures.
*/
/*
* rename current original file to previous original file
*/
if (rval == -1) {
return (B_FALSE);
}
/*
* rename temporary file to current original file
*/
if (rval == -1) {
return (B_FALSE);
}
return (B_TRUE);
}
/*
*
*/
static boolean_t
{
int file;
int bytes_read;
int rval;
char *buf;
char overfill;
/*
* open current file
*/
if (file == -1) {
return (B_FALSE);
}
/*
* read file header
*/
if (bytes_read != sizeof (hdr)) {
return (B_FALSE);
}
/*
* calculate checksum over file header bytes
*/
hdr.nvfh_hdrsum = 0;
/*
* validate file header is as expected
*/
"checksum error %s actual:0x%x expected:0x%x",
}
"incorrect header", filename);
return (B_FALSE);
}
/*
* read expected remaining content of file
*/
if (bytes_read < 0) {
} else {
"read %s bytes:%d/%lld", filename,
}
return (B_FALSE);
}
/*
* check whether file has anymore data. If so this is an error
*/
if (bytes_read > 0) {
"than expected %s bytes:%lld",
return (B_FALSE);
}
/*
* validate file data is as expected
*/
"actual:0x%x expected:0x%x", filename,
return (B_FALSE);
}
if (rval != 0) {
return (B_FALSE);
}
/*
* activate nvlist
*/
/*
* free up old nvlist
*/
if (old_nvl) {
}
return (B_TRUE);
}
/*
* iscsid_getf -- given a file descriptor returns a file pointer
*/
static file_t *
{
}
return (fp);
}
/*
* nvf_releasef -- release lock on file pointer
*/
static void
nvf_releasef(int fdes)
{
}
}
/*
* nvf_setf -- stores the file pointer in an empty slot returning index
*/
static int
{
int i = -1;
for (i = 0; i < NVF_GETF; i++) {
if (nvf_fd[i] == 0) {
break;
}
}
return (i);
}
/*
* nvf_freef -- gets the file pointer based on index and releases memory.
*/
static void
{
}
}
/*
* nvf_open -- acts like syscall open, but works for kernel
*
* Note: This works for regular files only. No umask is provided to
* vn_open which means whatever mode is passed in will be used to
* create a file.
*/
static int
{
int fdes = -1;
int fflags;
/*
* Need to convert from user mode flags to file system flags.
* It's unfortunate that the kernel doesn't define a mask for
* counterparts. If one was provided something like
* fflags = ((flags & mask) + 1) | (flags & ~mask)
* would work. But, that would only be true if the relationship
* be O_XXX and FXXX was defined and it's not. So we have the
* following.
*/
else
/*
* look at the other flags and OR them in.
*/
return (-1);
}
return (-1);
}
/* ---- falloc returns with f_tlock held on success ---- */
}
return (fdes);
}
/*
* nvf_close -- closes down the file by releasing locks and memory.
*/
static int
{
return (-1);
/*
* unfalloc which is called from here will do a mutex_exit
* on t_lock in the fp. So don't call nvf_releasef() here.
*/
return (0);
}
/*
* nvf_remove -- remove file from filesystem
*/
static int
nvf_remove(char *filename)
{
}
/*
* nvf_rename -- rename file from one name to another
*/
static int
{
}
/*
*/
static ssize_t
{
return (-1);
return (-1);
}
}
/*
* nvf_write -- kernel write function
*/
static ssize_t
{
}
/*
* nvf_read -- kernel read function
*/
static ssize_t
{
}