xref: /onnv-gate/usr/src/uts/common/io/scsi/adapters/iscsi/nvfile.c (revision 10774:72b99c06d75b)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*10774SZhang.Yi@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM #include "iscsi.h"
277836SJohn.Forte@Sun.COM #include "nvfile.h"
287836SJohn.Forte@Sun.COM #include <sys/file.h>	    /* defines:	FKIOCTL */
298194SJack.Meng@Sun.COM #include <sys/kobj.h>
307836SJohn.Forte@Sun.COM 
317836SJohn.Forte@Sun.COM #define	NVF_GETF	16
327836SJohn.Forte@Sun.COM static kmutex_t		nvf_getf_lock;
337836SJohn.Forte@Sun.COM static file_t		*nvf_fd[NVF_GETF];
348194SJack.Meng@Sun.COM extern int modrootloaded;
357836SJohn.Forte@Sun.COM 
367836SJohn.Forte@Sun.COM /*
377836SJohn.Forte@Sun.COM  * file names
387836SJohn.Forte@Sun.COM  */
397836SJohn.Forte@Sun.COM #define	NVF_FILENAME		"/etc/iscsi/iscsi"
407836SJohn.Forte@Sun.COM #define	NVF_CURR_FILE_SUFFIX	"dbc"
417836SJohn.Forte@Sun.COM #define	NVF_PREV_FILE_SUFFIX	"dbp"
427836SJohn.Forte@Sun.COM #define	NVF_TMP_FILENAME	"/etc/iscsi/iscsi.dbt"
437836SJohn.Forte@Sun.COM #define	NVF_MAX_FILENAME_LEN	40
447836SJohn.Forte@Sun.COM 
457836SJohn.Forte@Sun.COM /*
467836SJohn.Forte@Sun.COM  * file header definitions
477836SJohn.Forte@Sun.COM  */
487836SJohn.Forte@Sun.COM #define	NVF_HDR_MAGIC		0x15C510DB		/* iSCSI DB */
497836SJohn.Forte@Sun.COM #define	NVF_HDR_VERSION		1
507836SJohn.Forte@Sun.COM #define	NVF_HDR_SIZE		128
517836SJohn.Forte@Sun.COM 
527836SJohn.Forte@Sun.COM 
537836SJohn.Forte@Sun.COM /*
547836SJohn.Forte@Sun.COM  * file flag definitions
557836SJohn.Forte@Sun.COM  *
567836SJohn.Forte@Sun.COM  * These flags describe the current state of reading or writing
577836SJohn.Forte@Sun.COM  * the NVFILE/NVPAIR or the backing file.
587836SJohn.Forte@Sun.COM  *
597836SJohn.Forte@Sun.COM  * These flags are derived from a like NVPAIR/NVFILE implementation
607836SJohn.Forte@Sun.COM  * in usr/src/uts/common/sys/devctl_impl.h
617836SJohn.Forte@Sun.COM  */
627836SJohn.Forte@Sun.COM #define	NVF_ACTIVE	0x01	/* nvlist/nvpair file is active */
637836SJohn.Forte@Sun.COM #define	NVF_DIRTY	0x02	/* needs to be flushed */
647836SJohn.Forte@Sun.COM #define	NVF_SCHED	0x04	/* flush thread is currently scheduled */
657836SJohn.Forte@Sun.COM #define	NVF_FLUSHING	0x08	/* in process of being flushed */
667836SJohn.Forte@Sun.COM #define	NVF_ERROR	0x10	/* most recent flush failed */
677836SJohn.Forte@Sun.COM 
687836SJohn.Forte@Sun.COM #define	NVF_IS_ACTIVE(flag)	(flag & NVF_ACTIVE)
697836SJohn.Forte@Sun.COM #define	NVF_MARK_ACTIVE(flag)	(flag |= NVF_ACTIVE)
707836SJohn.Forte@Sun.COM #define	NVF_CLEAR_ACTIVE(flag)	(flag &= ~NVF_ACTIVE)
717836SJohn.Forte@Sun.COM 
727836SJohn.Forte@Sun.COM #define	NVF_IS_DIRTY(flag)	(flag & NVF_DIRTY)
737836SJohn.Forte@Sun.COM #define	NVF_MARK_DIRTY(flag)	(flag |= NVF_DIRTY)
747836SJohn.Forte@Sun.COM #define	NVF_CLEAR_DIRTY(flag)	(flag &= ~NVF_DIRTY)
757836SJohn.Forte@Sun.COM 
767836SJohn.Forte@Sun.COM #define	NVF_IS_SCHED(flag)	(flag & NVF_SCHED)
777836SJohn.Forte@Sun.COM #define	NVF_MARK_SCHED(flag)	(flag |= NVF_SCHED)
787836SJohn.Forte@Sun.COM #define	NVF_CLEAR_SCHED(flag)	(flag &= ~NVF_SCHED)
797836SJohn.Forte@Sun.COM 
807836SJohn.Forte@Sun.COM /*
817836SJohn.Forte@Sun.COM  * file flush time constants
827836SJohn.Forte@Sun.COM  */
837836SJohn.Forte@Sun.COM #define	NVF_FLUSH_DELAY		10	/* number of ticks before flush */
847836SJohn.Forte@Sun.COM #define	NVF_RESCHED_MIN_TICKS	5	/* min # of ticks to resched thread */
857836SJohn.Forte@Sun.COM #define	NVF_FLUSH_BACKOFF_DELAY	(SEC_TO_TICK(300))   /* re-try flush in 5 min */
867836SJohn.Forte@Sun.COM 
877836SJohn.Forte@Sun.COM /*
887836SJohn.Forte@Sun.COM  * file access operations
897836SJohn.Forte@Sun.COM  */
907836SJohn.Forte@Sun.COM static file_t		*nvf_getf(int fdes);
917836SJohn.Forte@Sun.COM static void		nvf_releasef(int fdes);
927836SJohn.Forte@Sun.COM static int		nvf_setf(file_t *fp);
937836SJohn.Forte@Sun.COM 
947836SJohn.Forte@Sun.COM static int		nvf_open(char *path, int flags, int mode);
957836SJohn.Forte@Sun.COM static int		nvf_close(int fdes);
967836SJohn.Forte@Sun.COM static int		nvf_remove(char *filename);
977836SJohn.Forte@Sun.COM static int		nvf_rename(char *oldname, char *newname);
987836SJohn.Forte@Sun.COM static ssize_t		nvf_read(int fdes, void *cbuf, ssize_t count);
997836SJohn.Forte@Sun.COM static ssize_t		nvf_write(int fdes, void *cbuf, ssize_t count);
1007836SJohn.Forte@Sun.COM 
1017836SJohn.Forte@Sun.COM int			nvf_errno;
1027836SJohn.Forte@Sun.COM 
1037836SJohn.Forte@Sun.COM /*
1047836SJohn.Forte@Sun.COM  * file header data structure definition
1057836SJohn.Forte@Sun.COM  *
1067836SJohn.Forte@Sun.COM  * This data structure definition was derived from a like data structure
1077836SJohn.Forte@Sun.COM  * (nvpf_hdr_t) in usr/src/uts/common/sys/devctl_impl.h
1087836SJohn.Forte@Sun.COM  *
1097836SJohn.Forte@Sun.COM  * This header is larger than need in order to support extensability in the
1107836SJohn.Forte@Sun.COM  * future
1117836SJohn.Forte@Sun.COM  *
1127836SJohn.Forte@Sun.COM  */
1137836SJohn.Forte@Sun.COM typedef struct nvf_hdr {
1147836SJohn.Forte@Sun.COM 	union {
1157836SJohn.Forte@Sun.COM 		struct hdr {
1167836SJohn.Forte@Sun.COM 			uint32_t	h_magic;
1177836SJohn.Forte@Sun.COM 			int32_t		h_ver;
1187836SJohn.Forte@Sun.COM 			int64_t		h_size;
1197836SJohn.Forte@Sun.COM 			uint16_t	h_hdrsum;
1207836SJohn.Forte@Sun.COM 			uint16_t	h_datasum;
1217836SJohn.Forte@Sun.COM 		} h_info;
1227836SJohn.Forte@Sun.COM 		uchar_t h_pad[NVF_HDR_SIZE];
1237836SJohn.Forte@Sun.COM 	} h_u;
1247836SJohn.Forte@Sun.COM } nvf_hdr_t;
1257836SJohn.Forte@Sun.COM 
1267836SJohn.Forte@Sun.COM #define	nvfh_magic	h_u.h_info.h_magic
1277836SJohn.Forte@Sun.COM #define	nvfh_ver	h_u.h_info.h_ver
1287836SJohn.Forte@Sun.COM #define	nvfh_size	h_u.h_info.h_size
1297836SJohn.Forte@Sun.COM #define	nvfh_hdrsum	h_u.h_info.h_hdrsum
1307836SJohn.Forte@Sun.COM #define	nvfh_datasum	h_u.h_info.h_datasum
1317836SJohn.Forte@Sun.COM 
1327836SJohn.Forte@Sun.COM 
1337836SJohn.Forte@Sun.COM /*
1347836SJohn.Forte@Sun.COM  *  Local Global Variables
1357836SJohn.Forte@Sun.COM  */
1367836SJohn.Forte@Sun.COM static nvlist_t		*nvf_list;		/* pointer to root nvlist */
1377836SJohn.Forte@Sun.COM static uint32_t		nvf_flags;		/* nvfile state flags */
1387836SJohn.Forte@Sun.COM static kmutex_t		nvf_lock;		/* lock	for file */
1397836SJohn.Forte@Sun.COM static krwlock_t	nvf_list_lock;		/* lock for nvlist access */
1407836SJohn.Forte@Sun.COM static timeout_id_t	nvf_thread_id;		/* thread identifier */
1417836SJohn.Forte@Sun.COM static clock_t		nvf_thread_ticks;	/* timeout tick value */
1427836SJohn.Forte@Sun.COM static char		nvf_curr_filename[NVF_MAX_FILENAME_LEN];
1437836SJohn.Forte@Sun.COM static char		nvf_prev_filename[NVF_MAX_FILENAME_LEN];
1447836SJohn.Forte@Sun.COM static boolean_t	nvf_written_once; 	/* File has been written once */
1457836SJohn.Forte@Sun.COM /*
1467836SJohn.Forte@Sun.COM  *  Local Function Prototypes
1477836SJohn.Forte@Sun.COM  */
1487836SJohn.Forte@Sun.COM static uint16_t		nvf_chksum(char *buf, int64_t buflen);
1497836SJohn.Forte@Sun.COM static void		nvf_thread(void *arg);
1507836SJohn.Forte@Sun.COM static boolean_t	nvf_flush(void);
1517836SJohn.Forte@Sun.COM static boolean_t	nvf_parse(char *filename);
1527836SJohn.Forte@Sun.COM 
1537836SJohn.Forte@Sun.COM /*
1547836SJohn.Forte@Sun.COM  *  NVLIST/NVPAIR FILE External Interfaces
1557836SJohn.Forte@Sun.COM  */
1567836SJohn.Forte@Sun.COM 
1577836SJohn.Forte@Sun.COM void
nvf_init(void)1587836SJohn.Forte@Sun.COM nvf_init(void)
1597836SJohn.Forte@Sun.COM {
1607836SJohn.Forte@Sun.COM 	mutex_init(&nvf_getf_lock, NULL, MUTEX_DRIVER, NULL);
1617836SJohn.Forte@Sun.COM 	nvf_list = NULL;
1627836SJohn.Forte@Sun.COM 	nvf_flags = 0;
1637836SJohn.Forte@Sun.COM 	NVF_MARK_ACTIVE(nvf_flags);
1647836SJohn.Forte@Sun.COM 	nvf_thread_id = 0;
1657836SJohn.Forte@Sun.COM 	nvf_thread_ticks = 0;
1667836SJohn.Forte@Sun.COM 	nvf_written_once = B_FALSE;
1677836SJohn.Forte@Sun.COM 	(void) snprintf(nvf_curr_filename, NVF_MAX_FILENAME_LEN, "%s_v%d.%s",
1687836SJohn.Forte@Sun.COM 	    NVF_FILENAME, NVF_HDR_VERSION, NVF_CURR_FILE_SUFFIX);
1697836SJohn.Forte@Sun.COM 	(void) snprintf(nvf_prev_filename, NVF_MAX_FILENAME_LEN, "%s_v%d.%s",
1707836SJohn.Forte@Sun.COM 	    NVF_FILENAME, NVF_HDR_VERSION, NVF_PREV_FILE_SUFFIX);
1717836SJohn.Forte@Sun.COM 	mutex_init(&nvf_lock, NULL, MUTEX_DRIVER, NULL);
1727836SJohn.Forte@Sun.COM 	rw_init(&nvf_list_lock, NULL, RW_DRIVER, NULL);
1737836SJohn.Forte@Sun.COM }
1747836SJohn.Forte@Sun.COM 
1757836SJohn.Forte@Sun.COM void
nvf_fini(void)1767836SJohn.Forte@Sun.COM nvf_fini(void)
1777836SJohn.Forte@Sun.COM {
1787836SJohn.Forte@Sun.COM 	mutex_enter(&nvf_lock);
1797836SJohn.Forte@Sun.COM 	NVF_CLEAR_ACTIVE(nvf_flags);
1807836SJohn.Forte@Sun.COM 	if (NVF_IS_SCHED(nvf_flags)) {
1817836SJohn.Forte@Sun.COM 		nvf_thread_ticks = 0;
1827836SJohn.Forte@Sun.COM 		mutex_exit(&nvf_lock);
1837836SJohn.Forte@Sun.COM 		(void) untimeout(nvf_thread_id);
1847836SJohn.Forte@Sun.COM 		mutex_enter(&nvf_lock);
1857836SJohn.Forte@Sun.COM 	}
1867836SJohn.Forte@Sun.COM 
1877836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_WRITER);
1887836SJohn.Forte@Sun.COM 	if (nvf_list) {
1897836SJohn.Forte@Sun.COM 		nvlist_free(nvf_list);
1907836SJohn.Forte@Sun.COM 	}
1917836SJohn.Forte@Sun.COM 	nvf_list = NULL;
1927836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
1937836SJohn.Forte@Sun.COM 	mutex_exit(&nvf_lock);
1947836SJohn.Forte@Sun.COM 
1957836SJohn.Forte@Sun.COM 	rw_destroy(&nvf_list_lock);
1967836SJohn.Forte@Sun.COM 	mutex_destroy(&nvf_lock);
1977836SJohn.Forte@Sun.COM }
1987836SJohn.Forte@Sun.COM 
1997836SJohn.Forte@Sun.COM /*
2007836SJohn.Forte@Sun.COM  * nvf_load - load contents of NVLIST/NVPAIR file into memory.
2017836SJohn.Forte@Sun.COM  */
2027836SJohn.Forte@Sun.COM boolean_t
nvf_load(void)2037836SJohn.Forte@Sun.COM nvf_load(void)
2047836SJohn.Forte@Sun.COM {
2057836SJohn.Forte@Sun.COM 	char		corrupt_filename[NVF_MAX_FILENAME_LEN];
2067836SJohn.Forte@Sun.COM 	boolean_t	rval;
2077836SJohn.Forte@Sun.COM 
2087836SJohn.Forte@Sun.COM 	mutex_enter(&nvf_lock);
2097836SJohn.Forte@Sun.COM 
2107836SJohn.Forte@Sun.COM 	/*
2117836SJohn.Forte@Sun.COM 	 * try to load current file
2127836SJohn.Forte@Sun.COM 	 */
2138194SJack.Meng@Sun.COM 	if (!modrootloaded) {
2148194SJack.Meng@Sun.COM 		mutex_exit(&nvf_lock);
2158194SJack.Meng@Sun.COM 		return (B_TRUE);
2168194SJack.Meng@Sun.COM 	} else {
2178194SJack.Meng@Sun.COM 		rval = nvf_parse(nvf_curr_filename);
2188194SJack.Meng@Sun.COM 	}
2197836SJohn.Forte@Sun.COM 	if (rval == B_TRUE) {
2207836SJohn.Forte@Sun.COM 		mutex_exit(&nvf_lock);
2217836SJohn.Forte@Sun.COM 		return (rval);
2227836SJohn.Forte@Sun.COM 	} else {
2237836SJohn.Forte@Sun.COM 		/*
2247836SJohn.Forte@Sun.COM 		 * Rename current file to add corrupted suffix
2257836SJohn.Forte@Sun.COM 		 */
2267836SJohn.Forte@Sun.COM 		(void) snprintf(corrupt_filename, NVF_MAX_FILENAME_LEN,
2277836SJohn.Forte@Sun.COM 		    "%s.corrupt", nvf_curr_filename);
2287836SJohn.Forte@Sun.COM 		(void) nvf_rename(nvf_curr_filename, corrupt_filename);
2297836SJohn.Forte@Sun.COM 	}
2307836SJohn.Forte@Sun.COM 
2317836SJohn.Forte@Sun.COM 	/*
2327836SJohn.Forte@Sun.COM 	 * try to load previous file
2337836SJohn.Forte@Sun.COM 	 */
2348194SJack.Meng@Sun.COM 	if (!modrootloaded) {
2358194SJack.Meng@Sun.COM 		mutex_exit(&nvf_lock);
2368194SJack.Meng@Sun.COM 		return (B_TRUE);
2378194SJack.Meng@Sun.COM 	} else {
238*10774SZhang.Yi@Sun.COM 		rval = nvf_parse(nvf_prev_filename);
2398194SJack.Meng@Sun.COM 	}
2408194SJack.Meng@Sun.COM 
2417836SJohn.Forte@Sun.COM 	if (rval == B_TRUE) {
2427836SJohn.Forte@Sun.COM 		mutex_exit(&nvf_lock);
2437836SJohn.Forte@Sun.COM 		return (rval);
2447836SJohn.Forte@Sun.COM 	} else {
2457836SJohn.Forte@Sun.COM 		/*
2467836SJohn.Forte@Sun.COM 		 * Rename previous file to add corrupted suffix
2477836SJohn.Forte@Sun.COM 		 */
2487836SJohn.Forte@Sun.COM 		(void) snprintf(corrupt_filename, NVF_MAX_FILENAME_LEN,
2497836SJohn.Forte@Sun.COM 		    "%s.corrupt", nvf_prev_filename);
2507836SJohn.Forte@Sun.COM 		(void) nvf_rename(nvf_prev_filename, corrupt_filename);
2517836SJohn.Forte@Sun.COM 	}
2527836SJohn.Forte@Sun.COM 
2537836SJohn.Forte@Sun.COM 	/*
2547836SJohn.Forte@Sun.COM 	 * non-existent or corrupted files are OK.  We just create
2557836SJohn.Forte@Sun.COM 	 * an empty root nvlist and then write to file when
2567836SJohn.Forte@Sun.COM 	 * something added.  However, ensure that any current root nvlist
2577836SJohn.Forte@Sun.COM 	 * is deallocated before allocating a new one.
2587836SJohn.Forte@Sun.COM 	 */
2597836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_WRITER);
2607836SJohn.Forte@Sun.COM 	if (nvf_list != NULL) {
2617836SJohn.Forte@Sun.COM 		nvlist_free(nvf_list);
2627836SJohn.Forte@Sun.COM 		nvf_list = NULL;
2637836SJohn.Forte@Sun.COM 	}
2647836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
2657836SJohn.Forte@Sun.COM 
2667836SJohn.Forte@Sun.COM 	rval = nvlist_alloc(&nvf_list, NV_UNIQUE_NAME, KM_SLEEP);
2677836SJohn.Forte@Sun.COM 	if (rval != 0) {
2687836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed to "
2697836SJohn.Forte@Sun.COM 		    "allocate root list (%d)", rval);
2707836SJohn.Forte@Sun.COM 	}
2717836SJohn.Forte@Sun.COM 
2727836SJohn.Forte@Sun.COM 	mutex_exit(&nvf_lock);
2737836SJohn.Forte@Sun.COM 	return (rval == 0 ? B_TRUE : B_FALSE);
2747836SJohn.Forte@Sun.COM }
2757836SJohn.Forte@Sun.COM 
2767836SJohn.Forte@Sun.COM /*
2777836SJohn.Forte@Sun.COM  * nvf_update - start process of updating the NVPAIR/NVLIST file.
2787836SJohn.Forte@Sun.COM  *
2797836SJohn.Forte@Sun.COM  * This function is derived from a like NVPAIR/NVFILE implementation
2807836SJohn.Forte@Sun.COM  * in usr/src/uts/common/os/devctl.c
2817836SJohn.Forte@Sun.COM  *
2827836SJohn.Forte@Sun.COM  */
2837836SJohn.Forte@Sun.COM void
nvf_update(void)2847836SJohn.Forte@Sun.COM nvf_update(void)
2857836SJohn.Forte@Sun.COM {
2867836SJohn.Forte@Sun.COM 	mutex_enter(&nvf_lock);
2877836SJohn.Forte@Sun.COM 
2887836SJohn.Forte@Sun.COM 	/*
2897836SJohn.Forte@Sun.COM 	 * set dirty flag to indicate data flush is needed
2907836SJohn.Forte@Sun.COM 	 */
2917836SJohn.Forte@Sun.COM 	NVF_MARK_DIRTY(nvf_flags);
2927836SJohn.Forte@Sun.COM 
2937836SJohn.Forte@Sun.COM 	/*
2947836SJohn.Forte@Sun.COM 	 * If thread is already started just update number of
2957836SJohn.Forte@Sun.COM 	 * ticks before flush, otherwise start thread and set
2967836SJohn.Forte@Sun.COM 	 * number of ticks.  The thread will is responsible
2977836SJohn.Forte@Sun.COM 	 * for starting the actual store to file.
2987836SJohn.Forte@Sun.COM 	 *
2997836SJohn.Forte@Sun.COM 	 * If update error occured previously, reschedule flush to
3007836SJohn.Forte@Sun.COM 	 * occur almost immediately.  If error still exists, the
3017836SJohn.Forte@Sun.COM 	 * update thread will be backed off again
3027836SJohn.Forte@Sun.COM 	 */
3037836SJohn.Forte@Sun.COM 	if (!NVF_IS_SCHED(nvf_flags)) {
3047836SJohn.Forte@Sun.COM 		NVF_MARK_SCHED(nvf_flags);
3057836SJohn.Forte@Sun.COM 		mutex_exit(&nvf_lock);
3067836SJohn.Forte@Sun.COM 		nvf_thread_id = timeout(nvf_thread, NULL, NVF_FLUSH_DELAY);
3077836SJohn.Forte@Sun.COM 	} else {
3087836SJohn.Forte@Sun.COM 		nvf_thread_ticks = ddi_get_lbolt() + NVF_FLUSH_DELAY;
3097836SJohn.Forte@Sun.COM 		/*
3107836SJohn.Forte@Sun.COM 		 * If update error occured previously, reschedule flush
3117836SJohn.Forte@Sun.COM 		 * attempt to occur quickly.  If an error still exists
3127836SJohn.Forte@Sun.COM 		 * after a flush attempt, the update thread will be backed
3137836SJohn.Forte@Sun.COM 		 * off again
3147836SJohn.Forte@Sun.COM 		 */
3157836SJohn.Forte@Sun.COM 		if (nvf_flags & NVF_ERROR) {
3167836SJohn.Forte@Sun.COM 			mutex_exit(&nvf_lock);
3177836SJohn.Forte@Sun.COM 			(void) untimeout(nvf_thread_id);
3187836SJohn.Forte@Sun.COM 			nvf_thread_id = timeout(nvf_thread, NULL,
3197836SJohn.Forte@Sun.COM 			    NVF_FLUSH_DELAY);
3207836SJohn.Forte@Sun.COM 		} else {
3217836SJohn.Forte@Sun.COM 			mutex_exit(&nvf_lock);
3227836SJohn.Forte@Sun.COM 		}
3237836SJohn.Forte@Sun.COM 	}
3247836SJohn.Forte@Sun.COM }
3257836SJohn.Forte@Sun.COM 
3267836SJohn.Forte@Sun.COM /*
3277836SJohn.Forte@Sun.COM  * nvf_data_check -- check if specified list exists
3287836SJohn.Forte@Sun.COM  */
3297836SJohn.Forte@Sun.COM boolean_t
nvf_list_check(char * id)3307836SJohn.Forte@Sun.COM nvf_list_check(char *id)
3317836SJohn.Forte@Sun.COM {
3327836SJohn.Forte@Sun.COM 	nvlist_t	*list = NULL;
3337836SJohn.Forte@Sun.COM 	int		rval;
3347836SJohn.Forte@Sun.COM 
3357836SJohn.Forte@Sun.COM 	/*
3367836SJohn.Forte@Sun.COM 	 * find the specified list
3377836SJohn.Forte@Sun.COM 	 */
3387836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_READER);
3397836SJohn.Forte@Sun.COM 	rval = nvlist_lookup_nvlist(nvf_list, id, &list);
3407836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
3417836SJohn.Forte@Sun.COM 
3427836SJohn.Forte@Sun.COM 	return (rval == 0 ? B_TRUE : B_FALSE);
3437836SJohn.Forte@Sun.COM }
3447836SJohn.Forte@Sun.COM 
3457836SJohn.Forte@Sun.COM /*
3467836SJohn.Forte@Sun.COM  * nvf_node_value_set - store value associated with node
3477836SJohn.Forte@Sun.COM  */
3487836SJohn.Forte@Sun.COM boolean_t
nvf_node_value_set(char * id,uint32_t value)3497836SJohn.Forte@Sun.COM nvf_node_value_set(char *id, uint32_t value)
3507836SJohn.Forte@Sun.COM {
3517836SJohn.Forte@Sun.COM 	int	rval;
3527836SJohn.Forte@Sun.COM 
3537836SJohn.Forte@Sun.COM 	ASSERT(id != NULL);
3547836SJohn.Forte@Sun.COM 
3557836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_WRITER);
3567836SJohn.Forte@Sun.COM 
3577836SJohn.Forte@Sun.COM 	if (nvf_list == NULL) {
3587836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
3597836SJohn.Forte@Sun.COM 		return (B_FALSE);
3607836SJohn.Forte@Sun.COM 	}
3617836SJohn.Forte@Sun.COM 
3627836SJohn.Forte@Sun.COM 	/*
3637836SJohn.Forte@Sun.COM 	 * update value.  If value already exists, it will be replaced
3647836SJohn.Forte@Sun.COM 	 * by this update.
3657836SJohn.Forte@Sun.COM 	 */
3667836SJohn.Forte@Sun.COM 	rval =  nvlist_add_uint32(nvf_list, id, value);
3677836SJohn.Forte@Sun.COM 	if (rval == 0) {
3687836SJohn.Forte@Sun.COM 		/*
3697836SJohn.Forte@Sun.COM 		 * value was set, so update associated file
3707836SJohn.Forte@Sun.COM 		 */
3717836SJohn.Forte@Sun.COM 		nvf_update();
3727836SJohn.Forte@Sun.COM 	} else {
3737836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed to "
3747836SJohn.Forte@Sun.COM 		    "store %s value (%d)", id, rval);
3757836SJohn.Forte@Sun.COM 	}
3767836SJohn.Forte@Sun.COM 
3777836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
3787836SJohn.Forte@Sun.COM 	return (rval == 0 ? B_TRUE : B_FALSE);
3797836SJohn.Forte@Sun.COM }
3807836SJohn.Forte@Sun.COM 
3817836SJohn.Forte@Sun.COM /*
3827836SJohn.Forte@Sun.COM  * nvf_node_value_get - obtain value associated with node
3837836SJohn.Forte@Sun.COM  */
3847836SJohn.Forte@Sun.COM boolean_t
nvf_node_value_get(char * id,uint32_t * value)3857836SJohn.Forte@Sun.COM nvf_node_value_get(char *id, uint32_t *value)
3867836SJohn.Forte@Sun.COM {
3877836SJohn.Forte@Sun.COM 	boolean_t	rval;
3887836SJohn.Forte@Sun.COM 
3897836SJohn.Forte@Sun.COM 	ASSERT(id != NULL);
3907836SJohn.Forte@Sun.COM 	ASSERT(value != NULL);
3917836SJohn.Forte@Sun.COM 
3927836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_READER);
3937836SJohn.Forte@Sun.COM 
3947836SJohn.Forte@Sun.COM 	if (nvf_list == NULL) {
3957836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
3967836SJohn.Forte@Sun.COM 		return (B_FALSE);
3977836SJohn.Forte@Sun.COM 	}
3987836SJohn.Forte@Sun.COM 
3997836SJohn.Forte@Sun.COM 	rval = nvlist_lookup_uint32(nvf_list, id, value);
4007836SJohn.Forte@Sun.COM 
4017836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
4027836SJohn.Forte@Sun.COM 	return (rval == 0 ? B_TRUE : B_FALSE);
4037836SJohn.Forte@Sun.COM }
4047836SJohn.Forte@Sun.COM 
4057836SJohn.Forte@Sun.COM /*
4067836SJohn.Forte@Sun.COM  * nvf_node_name_set - store a specific type of name
4077836SJohn.Forte@Sun.COM  */
4087836SJohn.Forte@Sun.COM boolean_t
nvf_node_name_set(char * id,char * name)4097836SJohn.Forte@Sun.COM nvf_node_name_set(char *id, char *name)
4107836SJohn.Forte@Sun.COM {
4117836SJohn.Forte@Sun.COM 	boolean_t	rval = B_TRUE;
4127836SJohn.Forte@Sun.COM 
4137836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_WRITER);
4147836SJohn.Forte@Sun.COM 
4157836SJohn.Forte@Sun.COM 	if (nvf_list == NULL) {
4167836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
4177836SJohn.Forte@Sun.COM 		return (B_FALSE);
4187836SJohn.Forte@Sun.COM 	}
4197836SJohn.Forte@Sun.COM 
4207836SJohn.Forte@Sun.COM 	rval =  nvlist_add_string(nvf_list, id, name);
4217836SJohn.Forte@Sun.COM 	if (rval == 0) {
4227836SJohn.Forte@Sun.COM 		nvf_update();
4237836SJohn.Forte@Sun.COM 	} else {
4247836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed to "
4257836SJohn.Forte@Sun.COM 		    "store %s name (%d)", id, rval);
4267836SJohn.Forte@Sun.COM 	}
4277836SJohn.Forte@Sun.COM 
4287836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
4297836SJohn.Forte@Sun.COM 	return (rval == 0 ? B_TRUE : B_FALSE);
4307836SJohn.Forte@Sun.COM }
4317836SJohn.Forte@Sun.COM 
4327836SJohn.Forte@Sun.COM /*
4337836SJohn.Forte@Sun.COM  * nvf_node_name_get - return a specific type of name
4347836SJohn.Forte@Sun.COM  */
4357836SJohn.Forte@Sun.COM boolean_t
nvf_node_name_get(char * id,char * name,uint_t nsize)4367836SJohn.Forte@Sun.COM nvf_node_name_get(char *id, char *name, uint_t nsize)
4377836SJohn.Forte@Sun.COM {
4387836SJohn.Forte@Sun.COM 	boolean_t	rval = B_FALSE;
4397836SJohn.Forte@Sun.COM 	char		*tmpname;
4407836SJohn.Forte@Sun.COM 
4417836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_READER);
4427836SJohn.Forte@Sun.COM 
4437836SJohn.Forte@Sun.COM 	if (nvf_list == NULL) {
4447836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
4457836SJohn.Forte@Sun.COM 		return (B_FALSE);
4467836SJohn.Forte@Sun.COM 	}
4477836SJohn.Forte@Sun.COM 
4487836SJohn.Forte@Sun.COM 	rval = nvlist_lookup_string(nvf_list, id, &tmpname);
4497836SJohn.Forte@Sun.COM 	if (rval == 0) {
4507836SJohn.Forte@Sun.COM 		/*
4517836SJohn.Forte@Sun.COM 		 *  ensure name is able to fit into given buffer
4527836SJohn.Forte@Sun.COM 		 */
4537836SJohn.Forte@Sun.COM 		if (strlen(tmpname) < nsize) {
4547836SJohn.Forte@Sun.COM 			(void) strcpy(name, tmpname);
4557836SJohn.Forte@Sun.COM 			rval = B_TRUE;
4567836SJohn.Forte@Sun.COM 		} else {
4577836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, "!iscsi persistent store "
4587836SJohn.Forte@Sun.COM 			    "unable to fit %s node name into buffer %d %s",
4597836SJohn.Forte@Sun.COM 			    tmpname, nsize, id);
4607836SJohn.Forte@Sun.COM 			rval = B_FALSE;
4617836SJohn.Forte@Sun.COM 		}
4627836SJohn.Forte@Sun.COM 	} else {
4637836SJohn.Forte@Sun.COM 		rval = B_FALSE;
4647836SJohn.Forte@Sun.COM 	}
4657836SJohn.Forte@Sun.COM 
4667836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
4677836SJohn.Forte@Sun.COM 	return (rval);
4687836SJohn.Forte@Sun.COM }
4697836SJohn.Forte@Sun.COM 
4707836SJohn.Forte@Sun.COM /*
4717836SJohn.Forte@Sun.COM  * nvf_node_data_set -- store data element associated with node
4727836SJohn.Forte@Sun.COM  */
4737836SJohn.Forte@Sun.COM boolean_t
nvf_node_data_set(char * name,void * data,uint_t dsize)4747836SJohn.Forte@Sun.COM nvf_node_data_set(char *name, void *data, uint_t dsize)
4757836SJohn.Forte@Sun.COM {
4767836SJohn.Forte@Sun.COM 	int		rval;
4777836SJohn.Forte@Sun.COM 
4787836SJohn.Forte@Sun.COM 	ASSERT(name != NULL);
4797836SJohn.Forte@Sun.COM 	ASSERT(data != NULL);
4807836SJohn.Forte@Sun.COM 
4817836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_WRITER);
4827836SJohn.Forte@Sun.COM 
4837836SJohn.Forte@Sun.COM 	if (nvf_list == NULL) {
4847836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
4857836SJohn.Forte@Sun.COM 		return (B_FALSE);
4867836SJohn.Forte@Sun.COM 	}
4877836SJohn.Forte@Sun.COM 
4887836SJohn.Forte@Sun.COM 	/*
4897836SJohn.Forte@Sun.COM 	 * update the address configuration element in the specific
4907836SJohn.Forte@Sun.COM 	 * list.  If this element already exists, it will be
4917836SJohn.Forte@Sun.COM 	 * replaced by this update.
4927836SJohn.Forte@Sun.COM 	 */
4937836SJohn.Forte@Sun.COM 	rval = nvlist_add_byte_array(nvf_list, name, (uchar_t *)data, dsize);
4947836SJohn.Forte@Sun.COM 	if (rval == 0) {
4957836SJohn.Forte@Sun.COM 		/*
4967836SJohn.Forte@Sun.COM 		 * data was set, so update associated file
4977836SJohn.Forte@Sun.COM 		 */
4987836SJohn.Forte@Sun.COM 		nvf_update();
4997836SJohn.Forte@Sun.COM 	} else {
5007836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed "
5017836SJohn.Forte@Sun.COM 		    "to store %s name (%d)", name, rval);
5027836SJohn.Forte@Sun.COM 	}
5037836SJohn.Forte@Sun.COM 
5047836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
5057836SJohn.Forte@Sun.COM 	return (rval == 0 ? B_TRUE : B_FALSE);
5067836SJohn.Forte@Sun.COM }
5077836SJohn.Forte@Sun.COM 
5087836SJohn.Forte@Sun.COM /*
5097836SJohn.Forte@Sun.COM  * nvf_node_data_get -- obtain a data element associated with node
5107836SJohn.Forte@Sun.COM  */
5117836SJohn.Forte@Sun.COM iscsi_nvfile_status_t
nvf_node_data_get(char * name,void * data,uint_t dsize)5127836SJohn.Forte@Sun.COM nvf_node_data_get(char *name, void *data, uint_t dsize)
5137836SJohn.Forte@Sun.COM {
5147836SJohn.Forte@Sun.COM 	uchar_t			*value = NULL;
5157836SJohn.Forte@Sun.COM 	uint_t			vsize;
5167836SJohn.Forte@Sun.COM 	int			rval = 0;
5177836SJohn.Forte@Sun.COM 	iscsi_nvfile_status_t	status = ISCSI_NVFILE_SUCCESS;
5187836SJohn.Forte@Sun.COM 
5197836SJohn.Forte@Sun.COM 	ASSERT(name != NULL);
5207836SJohn.Forte@Sun.COM 	ASSERT(data != NULL);
5217836SJohn.Forte@Sun.COM 
5227836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_READER);
5237836SJohn.Forte@Sun.COM 
5247836SJohn.Forte@Sun.COM 	if (nvf_list == NULL) {
5257836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
5267836SJohn.Forte@Sun.COM 		return (ISCSI_NVFILE_NVF_LIST_NOT_FOUND);
5277836SJohn.Forte@Sun.COM 	}
5287836SJohn.Forte@Sun.COM 
5297836SJohn.Forte@Sun.COM 	rval = nvlist_lookup_byte_array(nvf_list, name, &value, &vsize);
5307836SJohn.Forte@Sun.COM 	if (rval == 0) {
5317836SJohn.Forte@Sun.COM 		/*
5327836SJohn.Forte@Sun.COM 		 *  ensure data is able to fit into given buffer
5337836SJohn.Forte@Sun.COM 		 */
5347836SJohn.Forte@Sun.COM 		if (vsize <= dsize) {
5357836SJohn.Forte@Sun.COM 			bcopy(value, data, vsize);
5367836SJohn.Forte@Sun.COM 		} else {
5377836SJohn.Forte@Sun.COM 			bcopy(value, data, dsize);
5387836SJohn.Forte@Sun.COM 		}
5397836SJohn.Forte@Sun.COM 		status = ISCSI_NVFILE_SUCCESS;
5407836SJohn.Forte@Sun.COM 	} else if (rval == ENOENT) {
5417836SJohn.Forte@Sun.COM 		status = ISCSI_NVFILE_NAMEVAL_NOT_FOUND;
5427836SJohn.Forte@Sun.COM 	} else {
5437836SJohn.Forte@Sun.COM 		status = ISCSI_NVFILE_FAILURE;
5447836SJohn.Forte@Sun.COM 	}
5457836SJohn.Forte@Sun.COM 
5467836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
5477836SJohn.Forte@Sun.COM 	return (status);
5487836SJohn.Forte@Sun.COM }
5497836SJohn.Forte@Sun.COM 
5507836SJohn.Forte@Sun.COM /*
5517836SJohn.Forte@Sun.COM  * nvf_node_data_clear -- remove a data element associated with node
5527836SJohn.Forte@Sun.COM  */
5537836SJohn.Forte@Sun.COM boolean_t
nvf_node_data_clear(char * name)5547836SJohn.Forte@Sun.COM nvf_node_data_clear(char *name)
5557836SJohn.Forte@Sun.COM {
5567836SJohn.Forte@Sun.COM 	int	rval;
5577836SJohn.Forte@Sun.COM 
5587836SJohn.Forte@Sun.COM 	ASSERT(name != NULL);
5597836SJohn.Forte@Sun.COM 
5607836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_WRITER);
5617836SJohn.Forte@Sun.COM 
5627836SJohn.Forte@Sun.COM 	if (nvf_list == NULL) {
5637836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
5647836SJohn.Forte@Sun.COM 		return (B_FALSE);
5657836SJohn.Forte@Sun.COM 	}
5667836SJohn.Forte@Sun.COM 
5677836SJohn.Forte@Sun.COM 	/*
5687836SJohn.Forte@Sun.COM 	 * remove the specified data element
5697836SJohn.Forte@Sun.COM 	 */
5707836SJohn.Forte@Sun.COM 	rval = nvlist_remove(nvf_list, name, DATA_TYPE_BYTE_ARRAY);
5717836SJohn.Forte@Sun.COM 	if (rval == 0) {
5727836SJohn.Forte@Sun.COM 		/*
5737836SJohn.Forte@Sun.COM 		 * data was set, so update associated file
5747836SJohn.Forte@Sun.COM 		 */
5757836SJohn.Forte@Sun.COM 		nvf_update();
5767836SJohn.Forte@Sun.COM 	}
5777836SJohn.Forte@Sun.COM 
5787836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
5797836SJohn.Forte@Sun.COM 	return (rval == 0 ? B_TRUE : B_FALSE);
5807836SJohn.Forte@Sun.COM }
5817836SJohn.Forte@Sun.COM 
5827836SJohn.Forte@Sun.COM /*
5837836SJohn.Forte@Sun.COM  * nvf_data_set -- store a data element in the specified list
5847836SJohn.Forte@Sun.COM  */
5857836SJohn.Forte@Sun.COM boolean_t
nvf_data_set(char * id,char * name,void * data,uint_t dsize)5867836SJohn.Forte@Sun.COM nvf_data_set(char *id, char *name, void *data, uint_t dsize)
5877836SJohn.Forte@Sun.COM {
5887836SJohn.Forte@Sun.COM 	nvlist_t	*list = NULL;
5897836SJohn.Forte@Sun.COM 	int		rval;
5907836SJohn.Forte@Sun.COM 	boolean_t	list_alloc = B_FALSE;
5917836SJohn.Forte@Sun.COM 
5927836SJohn.Forte@Sun.COM 	ASSERT(id != NULL);
5937836SJohn.Forte@Sun.COM 	ASSERT(name != NULL);
5947836SJohn.Forte@Sun.COM 	ASSERT(data != NULL);
5957836SJohn.Forte@Sun.COM 
5967836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_WRITER);
5977836SJohn.Forte@Sun.COM 
5987836SJohn.Forte@Sun.COM 	if (nvf_list == NULL) {
5997836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
6007836SJohn.Forte@Sun.COM 		return (B_FALSE);
6017836SJohn.Forte@Sun.COM 	}
6027836SJohn.Forte@Sun.COM 
6037836SJohn.Forte@Sun.COM 	/*
6047836SJohn.Forte@Sun.COM 	 * find the specified list
6057836SJohn.Forte@Sun.COM 	 */
6067836SJohn.Forte@Sun.COM 	rval = nvlist_lookup_nvlist(nvf_list, id, &list);
6077836SJohn.Forte@Sun.COM 	if (rval != 0) {
6087836SJohn.Forte@Sun.COM 		rval = nvlist_alloc(&list, NV_UNIQUE_NAME, KM_SLEEP);
6097836SJohn.Forte@Sun.COM 		if (rval != 0) {
6107836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, "!iscsi persistent store failed to "
6117836SJohn.Forte@Sun.COM 			    "allocate %s list (%d)", id, rval);
6127836SJohn.Forte@Sun.COM 			rw_exit(&nvf_list_lock);
6137836SJohn.Forte@Sun.COM 			return (B_FALSE);
6147836SJohn.Forte@Sun.COM 		}
6157836SJohn.Forte@Sun.COM 		list_alloc = B_TRUE;
6167836SJohn.Forte@Sun.COM 	}
6177836SJohn.Forte@Sun.COM 
6187836SJohn.Forte@Sun.COM 	/*
6197836SJohn.Forte@Sun.COM 	 * update the data element in the specified list.  If this element
6207836SJohn.Forte@Sun.COM 	 * already exists, it will be replaced by this update.
6217836SJohn.Forte@Sun.COM 	 */
6227836SJohn.Forte@Sun.COM 	rval = nvlist_add_byte_array(list, name, (uchar_t *)data, dsize);
6237836SJohn.Forte@Sun.COM 	if (rval == 0) {
6247836SJohn.Forte@Sun.COM 		rval = nvlist_add_nvlist(nvf_list, id, list);
6257836SJohn.Forte@Sun.COM 		if (rval != 0) {
6267836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, "!iscsi persistent store failed "
6277836SJohn.Forte@Sun.COM 			    "to add %s list to root (%d)", id, rval);
6287836SJohn.Forte@Sun.COM 			rw_exit(&nvf_list_lock);
6297836SJohn.Forte@Sun.COM 			return (B_FALSE);
6307836SJohn.Forte@Sun.COM 		}
6317836SJohn.Forte@Sun.COM 		/*
6327836SJohn.Forte@Sun.COM 		 * data was set, so update file
6337836SJohn.Forte@Sun.COM 		 */
6347836SJohn.Forte@Sun.COM 		nvf_update();
6357836SJohn.Forte@Sun.COM 	} else {
6367836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed to "
6377836SJohn.Forte@Sun.COM 		    "store %s in %s list (%d)", name, id, rval);
6387836SJohn.Forte@Sun.COM 	}
6397836SJohn.Forte@Sun.COM 
6407836SJohn.Forte@Sun.COM 	if (list_alloc) {
6417836SJohn.Forte@Sun.COM 		nvlist_free(list);
6427836SJohn.Forte@Sun.COM 	}
6437836SJohn.Forte@Sun.COM 
6447836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
6457836SJohn.Forte@Sun.COM 	return (rval == 0 ? B_TRUE : B_FALSE);
6467836SJohn.Forte@Sun.COM }
6477836SJohn.Forte@Sun.COM 
6487836SJohn.Forte@Sun.COM /*
6497836SJohn.Forte@Sun.COM  * nvf_data_get -- get a data element from the specified list
6507836SJohn.Forte@Sun.COM  */
6517836SJohn.Forte@Sun.COM boolean_t
nvf_data_get(char * id,char * name,void * data,uint_t dsize)6527836SJohn.Forte@Sun.COM nvf_data_get(char *id, char *name, void *data, uint_t dsize)
6537836SJohn.Forte@Sun.COM {
6547836SJohn.Forte@Sun.COM 	nvlist_t	*list = NULL;
6557836SJohn.Forte@Sun.COM 	uchar_t		*value = NULL;
6567836SJohn.Forte@Sun.COM 	uint_t		vsize;
6577836SJohn.Forte@Sun.COM 	int		rval;
6587836SJohn.Forte@Sun.COM 
6597836SJohn.Forte@Sun.COM 	ASSERT(id != NULL);
6607836SJohn.Forte@Sun.COM 	ASSERT(name != NULL);
6617836SJohn.Forte@Sun.COM 	ASSERT(data != NULL);
6627836SJohn.Forte@Sun.COM 
6637836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_READER);
6647836SJohn.Forte@Sun.COM 
6657836SJohn.Forte@Sun.COM 	if (nvf_list == NULL) {
6667836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
6677836SJohn.Forte@Sun.COM 		return (B_FALSE);
6687836SJohn.Forte@Sun.COM 	}
6697836SJohn.Forte@Sun.COM 
6707836SJohn.Forte@Sun.COM 	/*
6717836SJohn.Forte@Sun.COM 	 * find the specified list
6727836SJohn.Forte@Sun.COM 	 */
6737836SJohn.Forte@Sun.COM 	rval = nvlist_lookup_nvlist(nvf_list, id, &list);
6747836SJohn.Forte@Sun.COM 	if (rval != 0) {
6757836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
6767836SJohn.Forte@Sun.COM 		return (B_FALSE);
6777836SJohn.Forte@Sun.COM 	}
6787836SJohn.Forte@Sun.COM 
6797836SJohn.Forte@Sun.COM 	/* obtain data element from list */
6807836SJohn.Forte@Sun.COM 	ASSERT(list != NULL);
6817836SJohn.Forte@Sun.COM 	rval = nvlist_lookup_byte_array(list, name, &value, &vsize);
6827836SJohn.Forte@Sun.COM 	if (rval == 0) {
6837836SJohn.Forte@Sun.COM 		/*
6847836SJohn.Forte@Sun.COM 		 *  ensure data is able to fit into given buffer
6857836SJohn.Forte@Sun.COM 		 */
6867836SJohn.Forte@Sun.COM 		if (vsize <= dsize) {
6877836SJohn.Forte@Sun.COM 			bcopy(value, data, vsize);
6887836SJohn.Forte@Sun.COM 		} else {
6897836SJohn.Forte@Sun.COM 			bcopy(value, data, dsize);
6907836SJohn.Forte@Sun.COM 		}
6917836SJohn.Forte@Sun.COM 	}
6927836SJohn.Forte@Sun.COM 
6937836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
6947836SJohn.Forte@Sun.COM 	return (rval == 0 ? B_TRUE : B_FALSE);
6957836SJohn.Forte@Sun.COM }
6967836SJohn.Forte@Sun.COM 
6977836SJohn.Forte@Sun.COM 
6987836SJohn.Forte@Sun.COM /*
6997836SJohn.Forte@Sun.COM  * nvf_data_next -- get the next data element in the specified list
7007836SJohn.Forte@Sun.COM  */
7017836SJohn.Forte@Sun.COM boolean_t
nvf_data_next(char * id,void ** v,char * name,void * data,uint_t dsize)7027836SJohn.Forte@Sun.COM nvf_data_next(char *id, void **v, char *name, void *data, uint_t dsize)
7037836SJohn.Forte@Sun.COM {
7047836SJohn.Forte@Sun.COM 	nvlist_t	*list = NULL;
7057836SJohn.Forte@Sun.COM 	nvpair_t	*pair = NULL;
7067836SJohn.Forte@Sun.COM 	uchar_t		*value = NULL;
7077836SJohn.Forte@Sun.COM 	uint_t		vsize;
7087836SJohn.Forte@Sun.COM 	int		rval;
7097836SJohn.Forte@Sun.COM 
7107836SJohn.Forte@Sun.COM 	ASSERT(id != NULL);
7117836SJohn.Forte@Sun.COM 	ASSERT(v != NULL);
7127836SJohn.Forte@Sun.COM 	ASSERT(name != NULL);
7137836SJohn.Forte@Sun.COM 	ASSERT(data != NULL);
7147836SJohn.Forte@Sun.COM 
7157836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_READER);
7167836SJohn.Forte@Sun.COM 	if (nvf_list == NULL) {
7177836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
7187836SJohn.Forte@Sun.COM 		return (B_FALSE);
7197836SJohn.Forte@Sun.COM 	}
7207836SJohn.Forte@Sun.COM 
7217836SJohn.Forte@Sun.COM 	/*
7227836SJohn.Forte@Sun.COM 	 * find the specified list
7237836SJohn.Forte@Sun.COM 	 */
7247836SJohn.Forte@Sun.COM 	rval = nvlist_lookup_nvlist(nvf_list, id, &list);
7257836SJohn.Forte@Sun.COM 	if (rval != 0) {
7267836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
7277836SJohn.Forte@Sun.COM 		return (B_FALSE);
7287836SJohn.Forte@Sun.COM 	}
7297836SJohn.Forte@Sun.COM 
7307836SJohn.Forte@Sun.COM 	/*
7317836SJohn.Forte@Sun.COM 	 * get the next nvpair data item in the list
7327836SJohn.Forte@Sun.COM 	 */
7337836SJohn.Forte@Sun.COM 	pair = nvlist_next_nvpair(list, (nvpair_t *)*v);
7347836SJohn.Forte@Sun.COM 	*v = (void *)pair;
7357836SJohn.Forte@Sun.COM 	if (pair == NULL) {
7367836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
7377836SJohn.Forte@Sun.COM 		return (B_FALSE);
7387836SJohn.Forte@Sun.COM 	}
7397836SJohn.Forte@Sun.COM 
7407836SJohn.Forte@Sun.COM 	/*
7417836SJohn.Forte@Sun.COM 	 * get the data bytes
7427836SJohn.Forte@Sun.COM 	 */
7437836SJohn.Forte@Sun.COM 	rval = nvpair_value_byte_array(pair, &value, &vsize);
7447836SJohn.Forte@Sun.COM 	if (rval != 0) {
7457836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
7467836SJohn.Forte@Sun.COM 		return (B_FALSE);
7477836SJohn.Forte@Sun.COM 	}
7487836SJohn.Forte@Sun.COM 
7497836SJohn.Forte@Sun.COM 	/*
7507836SJohn.Forte@Sun.COM 	 *  ensure data is able to fit into given buffer
7517836SJohn.Forte@Sun.COM 	 */
7527836SJohn.Forte@Sun.COM 	(void) strcpy(name, nvpair_name(pair));
7537836SJohn.Forte@Sun.COM 	if (vsize <= dsize) {
7547836SJohn.Forte@Sun.COM 		bcopy(value, data, vsize);
7557836SJohn.Forte@Sun.COM 	} else {
7567836SJohn.Forte@Sun.COM 		bcopy(value, data, dsize);
7577836SJohn.Forte@Sun.COM 	}
7587836SJohn.Forte@Sun.COM 
7597836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
7607836SJohn.Forte@Sun.COM 	return (B_TRUE);
7617836SJohn.Forte@Sun.COM }
7627836SJohn.Forte@Sun.COM 
7637836SJohn.Forte@Sun.COM /*
7647836SJohn.Forte@Sun.COM  * nvf_data_clear -- remove a data element from the specified list
7657836SJohn.Forte@Sun.COM  */
7667836SJohn.Forte@Sun.COM boolean_t
nvf_data_clear(char * id,char * name)7677836SJohn.Forte@Sun.COM nvf_data_clear(char *id, char *name)
7687836SJohn.Forte@Sun.COM {
7697836SJohn.Forte@Sun.COM 	nvlist_t	*list = NULL;
7707836SJohn.Forte@Sun.COM 	int		rval = B_FALSE;
7717836SJohn.Forte@Sun.COM 
7727836SJohn.Forte@Sun.COM 	ASSERT(id != NULL);
7737836SJohn.Forte@Sun.COM 	ASSERT(name != NULL);
7747836SJohn.Forte@Sun.COM 
7757836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_WRITER);
7767836SJohn.Forte@Sun.COM 
7777836SJohn.Forte@Sun.COM 	if (nvf_list == NULL) {
7787836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
7797836SJohn.Forte@Sun.COM 		return (B_FALSE);
7807836SJohn.Forte@Sun.COM 	}
7817836SJohn.Forte@Sun.COM 
7827836SJohn.Forte@Sun.COM 	/*
7837836SJohn.Forte@Sun.COM 	 * find the specified list
7847836SJohn.Forte@Sun.COM 	 */
7857836SJohn.Forte@Sun.COM 	rval = nvlist_lookup_nvlist(nvf_list, id, &list);
7867836SJohn.Forte@Sun.COM 	if (rval != 0) {
7877836SJohn.Forte@Sun.COM 		rw_exit(&nvf_list_lock);
7887836SJohn.Forte@Sun.COM 		return (B_FALSE);
7897836SJohn.Forte@Sun.COM 	}
7907836SJohn.Forte@Sun.COM 
7917836SJohn.Forte@Sun.COM 	/*
7927836SJohn.Forte@Sun.COM 	 * remove the specified data element
7937836SJohn.Forte@Sun.COM 	 */
7947836SJohn.Forte@Sun.COM 	rval = nvlist_remove(list, name, DATA_TYPE_BYTE_ARRAY);
7957836SJohn.Forte@Sun.COM 	if (rval == 0) {
7967836SJohn.Forte@Sun.COM 		/*
7977836SJohn.Forte@Sun.COM 		 * data was set, so update associated file
7987836SJohn.Forte@Sun.COM 		 */
7997836SJohn.Forte@Sun.COM 		nvf_update();
8007836SJohn.Forte@Sun.COM 	}
8017836SJohn.Forte@Sun.COM 
8027836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
8037836SJohn.Forte@Sun.COM 	return (rval == 0 ? B_TRUE : B_FALSE);
8047836SJohn.Forte@Sun.COM }
8057836SJohn.Forte@Sun.COM 
8067836SJohn.Forte@Sun.COM /*
8077836SJohn.Forte@Sun.COM  * +--------------------------------------------------------------------+
8087836SJohn.Forte@Sun.COM  * | Internal Helper Functions                                          |
8097836SJohn.Forte@Sun.COM  * +--------------------------------------------------------------------+
8107836SJohn.Forte@Sun.COM  */
8117836SJohn.Forte@Sun.COM 
8127836SJohn.Forte@Sun.COM /*
8137836SJohn.Forte@Sun.COM  * nvf_cksum - calculate checksum of given buffer.
8147836SJohn.Forte@Sun.COM  *
8157836SJohn.Forte@Sun.COM  * This function was derived from like function (nvp_cksum) in
8167836SJohn.Forte@Sun.COM  * usr/src/uts/common/os/devctl.c
8177836SJohn.Forte@Sun.COM  */
8187836SJohn.Forte@Sun.COM static uint16_t
nvf_chksum(char * buf,int64_t buflen)8197836SJohn.Forte@Sun.COM nvf_chksum(char *buf, int64_t buflen)
8207836SJohn.Forte@Sun.COM {
8217836SJohn.Forte@Sun.COM 	uint16_t cksum = 0;
8227836SJohn.Forte@Sun.COM 	uint16_t *p = (uint16_t *)buf;
8237836SJohn.Forte@Sun.COM 	int64_t n;
8247836SJohn.Forte@Sun.COM 
8257836SJohn.Forte@Sun.COM 	if ((buflen & 0x01) != 0) {
8267836SJohn.Forte@Sun.COM 		buflen--;
8277836SJohn.Forte@Sun.COM 		cksum = buf[buflen];
8287836SJohn.Forte@Sun.COM 	}
8297836SJohn.Forte@Sun.COM 	n = buflen / 2;
8307836SJohn.Forte@Sun.COM 	while (n-- > 0)
8317836SJohn.Forte@Sun.COM 		cksum ^= *p++;
8327836SJohn.Forte@Sun.COM 	return (cksum);
8337836SJohn.Forte@Sun.COM }
8347836SJohn.Forte@Sun.COM 
8357836SJohn.Forte@Sun.COM 
8367836SJohn.Forte@Sun.COM /*
8377836SJohn.Forte@Sun.COM  * nvf_thread - determines when writing of NVLIST/NVPAIR data to a file
8387836SJohn.Forte@Sun.COM  * should occur.
8397836SJohn.Forte@Sun.COM  */
8407836SJohn.Forte@Sun.COM /* ARGSUSED */
8417836SJohn.Forte@Sun.COM static void
nvf_thread(void * arg)8427836SJohn.Forte@Sun.COM nvf_thread(void *arg)
8437836SJohn.Forte@Sun.COM {
8447836SJohn.Forte@Sun.COM 	clock_t		nticks;
8457836SJohn.Forte@Sun.COM 	boolean_t	rval;
8467836SJohn.Forte@Sun.COM 
8477836SJohn.Forte@Sun.COM 	mutex_enter(&nvf_lock);
8487836SJohn.Forte@Sun.COM 	nticks = nvf_thread_ticks - ddi_get_lbolt();
8497836SJohn.Forte@Sun.COM 
8507836SJohn.Forte@Sun.COM 	/*
8517836SJohn.Forte@Sun.COM 	 * check whether its time to write to file.  If not, reschedule self
8527836SJohn.Forte@Sun.COM 	 */
8538194SJack.Meng@Sun.COM 	if ((nticks > NVF_RESCHED_MIN_TICKS) || !modrootloaded) {
8547836SJohn.Forte@Sun.COM 		if (NVF_IS_ACTIVE(nvf_flags)) {
8557836SJohn.Forte@Sun.COM 			mutex_exit(&nvf_lock);
8567836SJohn.Forte@Sun.COM 			nvf_thread_id = timeout(nvf_thread, NULL, nticks);
8577836SJohn.Forte@Sun.COM 			mutex_enter(&nvf_lock);
8587836SJohn.Forte@Sun.COM 		}
8597836SJohn.Forte@Sun.COM 		mutex_exit(&nvf_lock);
8607836SJohn.Forte@Sun.COM 		return;
8617836SJohn.Forte@Sun.COM 	}
8627836SJohn.Forte@Sun.COM 
8637836SJohn.Forte@Sun.COM 	/*
8647836SJohn.Forte@Sun.COM 	 * flush NVLIST/NVPAIR data to file
8657836SJohn.Forte@Sun.COM 	 */
8667836SJohn.Forte@Sun.COM 	NVF_CLEAR_DIRTY(nvf_flags);
8677836SJohn.Forte@Sun.COM 	nvf_flags |= NVF_FLUSHING;
8687836SJohn.Forte@Sun.COM 	mutex_exit(&nvf_lock);
8697836SJohn.Forte@Sun.COM 
8707836SJohn.Forte@Sun.COM 	rval = nvf_flush();
8717836SJohn.Forte@Sun.COM 
8727836SJohn.Forte@Sun.COM 	mutex_enter(&nvf_lock);
8737836SJohn.Forte@Sun.COM 	nvf_flags &= ~NVF_FLUSHING;
8747836SJohn.Forte@Sun.COM 	if (rval == B_FALSE) {
8757836SJohn.Forte@Sun.COM 		NVF_MARK_DIRTY(nvf_flags);
8767836SJohn.Forte@Sun.COM 		if ((nvf_flags & NVF_ERROR) == 0) {
8777836SJohn.Forte@Sun.COM 			if (nvf_written_once) {
8787836SJohn.Forte@Sun.COM 				cmn_err(CE_NOTE,
8797836SJohn.Forte@Sun.COM 				    "!iscsi persistent store update "
8807836SJohn.Forte@Sun.COM 				    "failed file:%s", nvf_curr_filename);
8817836SJohn.Forte@Sun.COM 			}
8827836SJohn.Forte@Sun.COM 			nvf_flags |= NVF_ERROR;
8837836SJohn.Forte@Sun.COM 		}
8847836SJohn.Forte@Sun.COM 		nvf_thread_ticks = NVF_FLUSH_BACKOFF_DELAY + ddi_get_lbolt();
8857836SJohn.Forte@Sun.COM 	} else if (nvf_flags & NVF_ERROR) {
8867836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store update ok now "
8877836SJohn.Forte@Sun.COM 		    "filename:%s", nvf_curr_filename);
8887836SJohn.Forte@Sun.COM 		nvf_flags &= ~NVF_ERROR;
8897836SJohn.Forte@Sun.COM 	}
8907836SJohn.Forte@Sun.COM 
8917836SJohn.Forte@Sun.COM 	/*
8927836SJohn.Forte@Sun.COM 	 * re-check whether data is dirty and reschedule if necessary
8937836SJohn.Forte@Sun.COM 	 */
8947836SJohn.Forte@Sun.COM 	if (NVF_IS_ACTIVE(nvf_flags) && NVF_IS_DIRTY(nvf_flags)) {
8957836SJohn.Forte@Sun.COM 		nticks = nvf_thread_ticks - ddi_get_lbolt();
8967836SJohn.Forte@Sun.COM 		mutex_exit(&nvf_lock);
8977836SJohn.Forte@Sun.COM 		if (nticks > NVF_FLUSH_DELAY) {
8987836SJohn.Forte@Sun.COM 			nvf_thread_id = timeout(nvf_thread, NULL, nticks);
8997836SJohn.Forte@Sun.COM 		} else {
9007836SJohn.Forte@Sun.COM 			nvf_thread_id = timeout(nvf_thread, NULL,
9017836SJohn.Forte@Sun.COM 			    NVF_FLUSH_DELAY);
9027836SJohn.Forte@Sun.COM 		}
9037836SJohn.Forte@Sun.COM 	} else {
9047836SJohn.Forte@Sun.COM 		NVF_CLEAR_SCHED(nvf_flags);
9057836SJohn.Forte@Sun.COM 		mutex_exit(&nvf_lock);
9067836SJohn.Forte@Sun.COM 	}
9077836SJohn.Forte@Sun.COM }
9087836SJohn.Forte@Sun.COM 
9097836SJohn.Forte@Sun.COM /*
9107836SJohn.Forte@Sun.COM  * nvf_flush - write contents of NVLIST/NVPAIR to a backing file.
9117836SJohn.Forte@Sun.COM  *
9127836SJohn.Forte@Sun.COM  * This function is derived from a like NVPAIR/NVFILE implementation
9137836SJohn.Forte@Sun.COM  * in usr/src/uts/common/os/devctl.c
9147836SJohn.Forte@Sun.COM  */
9157836SJohn.Forte@Sun.COM static boolean_t
nvf_flush(void)9167836SJohn.Forte@Sun.COM nvf_flush(void)
9177836SJohn.Forte@Sun.COM {
9187836SJohn.Forte@Sun.COM 	int		rval;
9197836SJohn.Forte@Sun.COM 	nvlist_t	*tmpnvl;
9207836SJohn.Forte@Sun.COM 	char		*nvfbuf;
9217836SJohn.Forte@Sun.COM 	char		*nvlbuf;
9227836SJohn.Forte@Sun.COM 	size_t		nvllen;
9237836SJohn.Forte@Sun.COM 	size_t		nvflen;
9247836SJohn.Forte@Sun.COM 	int		file;
9257836SJohn.Forte@Sun.COM 	int		bytes_written;
9267836SJohn.Forte@Sun.COM 
9277836SJohn.Forte@Sun.COM 	/*
9287836SJohn.Forte@Sun.COM 	 * duplicate data so access isn't blocked while writing to disk
9297836SJohn.Forte@Sun.COM 	 */
9308294SShengliang.Zhang@Sun.COM 	rw_enter(&nvf_list_lock, RW_READER);
9317836SJohn.Forte@Sun.COM 	rval = nvlist_dup(nvf_list, &tmpnvl, KM_SLEEP);
9327836SJohn.Forte@Sun.COM 	if (rval != 0) {
9337836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed to "
9347836SJohn.Forte@Sun.COM 		    "duplicate nvf_list (%d)", rval);
9358294SShengliang.Zhang@Sun.COM 		rw_exit(&nvf_list_lock);
9367836SJohn.Forte@Sun.COM 		return (B_FALSE);
9377836SJohn.Forte@Sun.COM 	}
9388294SShengliang.Zhang@Sun.COM 	rw_exit(&nvf_list_lock);
9397836SJohn.Forte@Sun.COM 
9407836SJohn.Forte@Sun.COM 	/*
9417836SJohn.Forte@Sun.COM 	 * pack duplicated list to get ready for file write
9427836SJohn.Forte@Sun.COM 	 */
9437836SJohn.Forte@Sun.COM 	nvlbuf = NULL;
9447836SJohn.Forte@Sun.COM 	rval = nvlist_pack(tmpnvl, &nvlbuf, &nvllen, NV_ENCODE_NATIVE, 0);
9457836SJohn.Forte@Sun.COM 	if (rval != 0) {
9467836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed to pack "
9477836SJohn.Forte@Sun.COM 		    "nvf_list (%d)", rval);
9487836SJohn.Forte@Sun.COM 		nvlist_free(tmpnvl);
9497836SJohn.Forte@Sun.COM 		return (B_FALSE);
9507836SJohn.Forte@Sun.COM 	}
9517836SJohn.Forte@Sun.COM 
9527836SJohn.Forte@Sun.COM 	/*
9537836SJohn.Forte@Sun.COM 	 * allocate buffer to store both the header and the data.
9547836SJohn.Forte@Sun.COM 	 */
9557836SJohn.Forte@Sun.COM 	nvflen = nvllen + sizeof (nvf_hdr_t);
9567836SJohn.Forte@Sun.COM 	nvfbuf = kmem_zalloc(nvflen, KM_SLEEP);
9577836SJohn.Forte@Sun.COM 
9587836SJohn.Forte@Sun.COM 	/*
9597836SJohn.Forte@Sun.COM 	 * fill buffer with contents of file header
9607836SJohn.Forte@Sun.COM 	 */
9617836SJohn.Forte@Sun.COM 	((nvf_hdr_t *)nvfbuf)->nvfh_magic = NVF_HDR_MAGIC;
9627836SJohn.Forte@Sun.COM 	((nvf_hdr_t *)nvfbuf)->nvfh_ver = NVF_HDR_VERSION;
9637836SJohn.Forte@Sun.COM 	((nvf_hdr_t *)nvfbuf)->nvfh_size = nvllen;
9647836SJohn.Forte@Sun.COM 	((nvf_hdr_t *)nvfbuf)->nvfh_datasum = nvf_chksum((char *)nvlbuf,
9657836SJohn.Forte@Sun.COM 	    nvllen);
9667836SJohn.Forte@Sun.COM 	((nvf_hdr_t *)nvfbuf)->nvfh_hdrsum = nvf_chksum((char *)nvfbuf,
9677836SJohn.Forte@Sun.COM 	    sizeof (nvf_hdr_t));
9687836SJohn.Forte@Sun.COM 
9697836SJohn.Forte@Sun.COM 	/*
9707836SJohn.Forte@Sun.COM 	 * copy packed nvlist into buffer
9717836SJohn.Forte@Sun.COM 	 */
9727836SJohn.Forte@Sun.COM 	bcopy(nvlbuf, nvfbuf + sizeof (nvf_hdr_t), nvllen);
9737836SJohn.Forte@Sun.COM 
9747836SJohn.Forte@Sun.COM 	/*
9757836SJohn.Forte@Sun.COM 	 * free memory used for packed nvlist
9767836SJohn.Forte@Sun.COM 	 */
9777836SJohn.Forte@Sun.COM 	nvlist_free(tmpnvl);
9787836SJohn.Forte@Sun.COM 	kmem_free(nvlbuf, nvllen);
9797836SJohn.Forte@Sun.COM 
9807836SJohn.Forte@Sun.COM 	/*
9817836SJohn.Forte@Sun.COM 	 *  To make it unlikely we suffer data loss, write
9827836SJohn.Forte@Sun.COM 	 * data to the new temporary file.  Once successful
9837836SJohn.Forte@Sun.COM 	 * complete the transaction by renaming the new file
9847836SJohn.Forte@Sun.COM 	 * to replace the previous.
9857836SJohn.Forte@Sun.COM 	 */
9867836SJohn.Forte@Sun.COM 
9877836SJohn.Forte@Sun.COM 	/*
9887836SJohn.Forte@Sun.COM 	 * remove temporary file to ensure data content is written correctly
9897836SJohn.Forte@Sun.COM 	 */
9907836SJohn.Forte@Sun.COM 	rval = nvf_remove(NVF_TMP_FILENAME);
9917836SJohn.Forte@Sun.COM 	if (rval == -1) {
9927836SJohn.Forte@Sun.COM 		kmem_free(nvfbuf, nvflen);
9937836SJohn.Forte@Sun.COM 		return (B_FALSE);
9947836SJohn.Forte@Sun.COM 	}
9957836SJohn.Forte@Sun.COM 
9967836SJohn.Forte@Sun.COM 	/*
9977836SJohn.Forte@Sun.COM 	 * create tempororary file
9987836SJohn.Forte@Sun.COM 	 */
9997836SJohn.Forte@Sun.COM 	file = nvf_open(NVF_TMP_FILENAME, O_RDWR | O_CREAT, 0600);
10007836SJohn.Forte@Sun.COM 	if (file == -1) {
10017836SJohn.Forte@Sun.COM 		mutex_enter(&nvf_lock);
10027836SJohn.Forte@Sun.COM 		if (nvf_written_once) {
10037836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE,
10047836SJohn.Forte@Sun.COM 			    "!iscsi persistent store failed to create "
10057836SJohn.Forte@Sun.COM 			    "%s (errno:%d)", NVF_TMP_FILENAME, nvf_errno);
10067836SJohn.Forte@Sun.COM 		}
10077836SJohn.Forte@Sun.COM 		mutex_exit(&nvf_lock);
10087836SJohn.Forte@Sun.COM 		kmem_free(nvfbuf, nvflen);
10097836SJohn.Forte@Sun.COM 		return (B_FALSE);
10107836SJohn.Forte@Sun.COM 	}
10117836SJohn.Forte@Sun.COM 
10127836SJohn.Forte@Sun.COM 	/*
10137836SJohn.Forte@Sun.COM 	 * write data to tempororary file
10147836SJohn.Forte@Sun.COM 	 */
10157836SJohn.Forte@Sun.COM 	bytes_written = nvf_write(file, nvfbuf, nvflen);
10167836SJohn.Forte@Sun.COM 	kmem_free(nvfbuf, nvflen);
10177836SJohn.Forte@Sun.COM 	if (bytes_written == -1) {
10187836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed to write "
10197836SJohn.Forte@Sun.COM 		    "%s (errno:%d)", NVF_TMP_FILENAME, nvf_errno);
10207836SJohn.Forte@Sun.COM 		return (B_FALSE);
10217836SJohn.Forte@Sun.COM 	}
10227836SJohn.Forte@Sun.COM 
10237836SJohn.Forte@Sun.COM 	if (bytes_written != nvflen) {
10247836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed to write "
10257836SJohn.Forte@Sun.COM 		    "%s (errno:%d)\n\tpartial write %d of %ld bytes\n",
10267836SJohn.Forte@Sun.COM 		    NVF_TMP_FILENAME, nvf_errno, bytes_written, nvflen);
10277836SJohn.Forte@Sun.COM 		return (B_FALSE);
10287836SJohn.Forte@Sun.COM 	}
10297836SJohn.Forte@Sun.COM 
10307836SJohn.Forte@Sun.COM 	/*
10317836SJohn.Forte@Sun.COM 	 * close tempororary file
10327836SJohn.Forte@Sun.COM 	 */
10337836SJohn.Forte@Sun.COM 	rval = nvf_close(file);
10347836SJohn.Forte@Sun.COM 	if (rval == -1) {
10357836SJohn.Forte@Sun.COM 		return (B_FALSE);
10367836SJohn.Forte@Sun.COM 	}
10377836SJohn.Forte@Sun.COM 
10387836SJohn.Forte@Sun.COM 	mutex_enter(&nvf_lock);
10397836SJohn.Forte@Sun.COM 	/*
10407836SJohn.Forte@Sun.COM 	 * File has been written.  Set flag to allow the create and update
10417836SJohn.Forte@Sun.COM 	 * messages to be displayed in case of create or update failures.
10427836SJohn.Forte@Sun.COM 	 */
10437836SJohn.Forte@Sun.COM 	nvf_written_once = B_TRUE;
10447836SJohn.Forte@Sun.COM 
10457836SJohn.Forte@Sun.COM 	/*
10467836SJohn.Forte@Sun.COM 	 * rename current original file to previous original file
10477836SJohn.Forte@Sun.COM 	 */
10487836SJohn.Forte@Sun.COM 	rval = nvf_rename(nvf_curr_filename, nvf_prev_filename);
10497836SJohn.Forte@Sun.COM 	if (rval == -1) {
10507836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed to "
10517836SJohn.Forte@Sun.COM 		    "rename %s (errno:%d)", nvf_curr_filename, nvf_errno);
10527836SJohn.Forte@Sun.COM 		mutex_exit(&nvf_lock);
10537836SJohn.Forte@Sun.COM 		return (B_FALSE);
10547836SJohn.Forte@Sun.COM 	}
10557836SJohn.Forte@Sun.COM 
10567836SJohn.Forte@Sun.COM 	/*
10577836SJohn.Forte@Sun.COM 	 * rename temporary file to current original file
10587836SJohn.Forte@Sun.COM 	 */
10597836SJohn.Forte@Sun.COM 	rval = nvf_rename(NVF_TMP_FILENAME, nvf_curr_filename);
10607836SJohn.Forte@Sun.COM 	if (rval == -1) {
10617836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed to "
10627836SJohn.Forte@Sun.COM 		    "rename %s (errno:%d)", NVF_TMP_FILENAME, nvf_errno);
10637836SJohn.Forte@Sun.COM 		mutex_exit(&nvf_lock);
10647836SJohn.Forte@Sun.COM 		return (B_FALSE);
10657836SJohn.Forte@Sun.COM 	}
10667836SJohn.Forte@Sun.COM 
10677836SJohn.Forte@Sun.COM 	NVF_CLEAR_DIRTY(nvf_flags);
10687836SJohn.Forte@Sun.COM 
10697836SJohn.Forte@Sun.COM 	mutex_exit(&nvf_lock);
10707836SJohn.Forte@Sun.COM 	return (B_TRUE);
10717836SJohn.Forte@Sun.COM }
10727836SJohn.Forte@Sun.COM 
10737836SJohn.Forte@Sun.COM /*
10747836SJohn.Forte@Sun.COM  * nvf_parse - read contents of NVLIST/NVPAIR file.
10757836SJohn.Forte@Sun.COM  *
10767836SJohn.Forte@Sun.COM  * This function is derived from a like NVPAIR/NVFILE implementation
10777836SJohn.Forte@Sun.COM  * in usr/src/uts/common/os/devctl.c
10787836SJohn.Forte@Sun.COM  */
10797836SJohn.Forte@Sun.COM static boolean_t
nvf_parse(char * filename)10807836SJohn.Forte@Sun.COM nvf_parse(char *filename)
10817836SJohn.Forte@Sun.COM {
10827836SJohn.Forte@Sun.COM 	int		file;
10837836SJohn.Forte@Sun.COM 	nvf_hdr_t	hdr;
10847836SJohn.Forte@Sun.COM 	int		bytes_read;
10857836SJohn.Forte@Sun.COM 	int		rval;
10867836SJohn.Forte@Sun.COM 	uint16_t	chksum;
10877836SJohn.Forte@Sun.COM 	uint16_t	hdrsum;
10887836SJohn.Forte@Sun.COM 	char		*buf;
10897836SJohn.Forte@Sun.COM 	char		overfill;
10907836SJohn.Forte@Sun.COM 	nvlist_t	*nvl;
10917836SJohn.Forte@Sun.COM 	nvlist_t	*old_nvl;
10927836SJohn.Forte@Sun.COM 
10937836SJohn.Forte@Sun.COM 
10947836SJohn.Forte@Sun.COM 	/*
10957836SJohn.Forte@Sun.COM 	 * open current file
10967836SJohn.Forte@Sun.COM 	 */
10977836SJohn.Forte@Sun.COM 	file = nvf_open(filename, O_RDONLY, 0600);
10987836SJohn.Forte@Sun.COM 	if (file == -1) {
10997836SJohn.Forte@Sun.COM 		return (B_FALSE);
11007836SJohn.Forte@Sun.COM 	}
11017836SJohn.Forte@Sun.COM 
11027836SJohn.Forte@Sun.COM 	/*
11037836SJohn.Forte@Sun.COM 	 * read file header
11047836SJohn.Forte@Sun.COM 	 */
11057836SJohn.Forte@Sun.COM 	bytes_read = nvf_read(file, (char *)&hdr, sizeof (hdr));
11067836SJohn.Forte@Sun.COM 	if (bytes_read != sizeof (hdr)) {
11077836SJohn.Forte@Sun.COM 		(void) nvf_close(file);
11087836SJohn.Forte@Sun.COM 		return (B_FALSE);
11097836SJohn.Forte@Sun.COM 	}
11107836SJohn.Forte@Sun.COM 
11117836SJohn.Forte@Sun.COM 	/*
11127836SJohn.Forte@Sun.COM 	 * calculate checksum over file header bytes
11137836SJohn.Forte@Sun.COM 	 */
11147836SJohn.Forte@Sun.COM 	chksum = hdr.nvfh_hdrsum;
11157836SJohn.Forte@Sun.COM 	hdr.nvfh_hdrsum = 0;
11167836SJohn.Forte@Sun.COM 	hdrsum = nvf_chksum((char *)&hdr, sizeof (hdr));
11177836SJohn.Forte@Sun.COM 
11187836SJohn.Forte@Sun.COM 	/*
11197836SJohn.Forte@Sun.COM 	 * validate file header is as expected
11207836SJohn.Forte@Sun.COM 	 */
11217836SJohn.Forte@Sun.COM 	if ((hdr.nvfh_magic != NVF_HDR_MAGIC) ||
11227836SJohn.Forte@Sun.COM 	    (hdr.nvfh_ver != NVF_HDR_VERSION) ||
11237836SJohn.Forte@Sun.COM 	    (hdrsum != chksum)) {
11247836SJohn.Forte@Sun.COM 		(void) nvf_close(file);
11257836SJohn.Forte@Sun.COM 		if (hdrsum != chksum) {
11267836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, "!iscsi persistent store "
11277836SJohn.Forte@Sun.COM 			    "checksum error %s actual:0x%x expected:0x%x",
11287836SJohn.Forte@Sun.COM 			    filename, hdrsum, chksum);
11297836SJohn.Forte@Sun.COM 		}
11307836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store %s has an "
11317836SJohn.Forte@Sun.COM 		    "incorrect header", filename);
11327836SJohn.Forte@Sun.COM 		return (B_FALSE);
11337836SJohn.Forte@Sun.COM 	}
11347836SJohn.Forte@Sun.COM 
11357836SJohn.Forte@Sun.COM 	ASSERT(hdr.nvfh_size >= 0);
11367836SJohn.Forte@Sun.COM 
11377836SJohn.Forte@Sun.COM 	/*
11387836SJohn.Forte@Sun.COM 	 * read expected remaining content of file
11397836SJohn.Forte@Sun.COM 	 */
11407836SJohn.Forte@Sun.COM 	buf = kmem_alloc(hdr.nvfh_size, KM_SLEEP);
11417836SJohn.Forte@Sun.COM 	bytes_read = nvf_read(file, buf, hdr.nvfh_size);
11427836SJohn.Forte@Sun.COM 	if (bytes_read != hdr.nvfh_size) {
11437836SJohn.Forte@Sun.COM 		kmem_free(buf, hdr.nvfh_size);
11447836SJohn.Forte@Sun.COM 		(void) nvf_close(file);
11457836SJohn.Forte@Sun.COM 		if (bytes_read < 0) {
11467836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, "!iscsi persistent store failed "
11477836SJohn.Forte@Sun.COM 			    "to read %s bytes:%d", filename, bytes_read);
11487836SJohn.Forte@Sun.COM 		} else {
11497836SJohn.Forte@Sun.COM 			cmn_err(CE_NOTE, "!iscsi persistent store incomplete "
11507836SJohn.Forte@Sun.COM 			    "read %s bytes:%d/%lld", filename,
11517836SJohn.Forte@Sun.COM 			    bytes_read, (longlong_t)hdr.nvfh_size);
11527836SJohn.Forte@Sun.COM 		}
11537836SJohn.Forte@Sun.COM 		return (B_FALSE);
11547836SJohn.Forte@Sun.COM 	}
11557836SJohn.Forte@Sun.COM 
11567836SJohn.Forte@Sun.COM 	/*
11577836SJohn.Forte@Sun.COM 	 * check whether file has anymore data.  If so this is an error
11587836SJohn.Forte@Sun.COM 	 */
11597836SJohn.Forte@Sun.COM 	bytes_read = nvf_read(file, &overfill, 1);
11607836SJohn.Forte@Sun.COM 	(void) nvf_close(file);
11617836SJohn.Forte@Sun.COM 	if (bytes_read > 0) {
11627836SJohn.Forte@Sun.COM 		kmem_free(buf, hdr.nvfh_size);
11637836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store file is larger "
11647836SJohn.Forte@Sun.COM 		    "than expected %s bytes:%lld",
11657836SJohn.Forte@Sun.COM 		    filename, (longlong_t)hdr.nvfh_size);
11667836SJohn.Forte@Sun.COM 		return (B_FALSE);
11677836SJohn.Forte@Sun.COM 	}
11687836SJohn.Forte@Sun.COM 
11697836SJohn.Forte@Sun.COM 	DTRACE_PROBE1(hdr, nvf_hdr_t *, &hdr);
11707836SJohn.Forte@Sun.COM 
11717836SJohn.Forte@Sun.COM 	/*
11727836SJohn.Forte@Sun.COM 	 * validate file data is as expected
11737836SJohn.Forte@Sun.COM 	 */
11747836SJohn.Forte@Sun.COM 	chksum = nvf_chksum(buf, hdr.nvfh_size);
11757836SJohn.Forte@Sun.COM 	if (hdr.nvfh_datasum != chksum) {
11767836SJohn.Forte@Sun.COM 		kmem_free(buf, hdr.nvfh_size);
11777836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store checksum error %s "
11787836SJohn.Forte@Sun.COM 		    "actual:0x%x expected:0x%x", filename,
11797836SJohn.Forte@Sun.COM 		    hdr.nvfh_datasum, chksum);
11807836SJohn.Forte@Sun.COM 		return (B_FALSE);
11817836SJohn.Forte@Sun.COM 	}
11827836SJohn.Forte@Sun.COM 
11837836SJohn.Forte@Sun.COM 	nvl = NULL;
11847836SJohn.Forte@Sun.COM 	rval = nvlist_unpack(buf, hdr.nvfh_size, &nvl, 0);
11857836SJohn.Forte@Sun.COM 	if (rval != 0) {
11867836SJohn.Forte@Sun.COM 		kmem_free(buf, hdr.nvfh_size);
11877836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "!iscsi persistent store failed unpacking "
11887836SJohn.Forte@Sun.COM 		    "nvlist %s (%d)", filename, rval);
11897836SJohn.Forte@Sun.COM 		return (B_FALSE);
11907836SJohn.Forte@Sun.COM 	}
11917836SJohn.Forte@Sun.COM 
11927836SJohn.Forte@Sun.COM 	kmem_free(buf, hdr.nvfh_size);
11937836SJohn.Forte@Sun.COM 
11947836SJohn.Forte@Sun.COM 	/*
11957836SJohn.Forte@Sun.COM 	 * activate nvlist
11967836SJohn.Forte@Sun.COM 	 */
11977836SJohn.Forte@Sun.COM 	rw_enter(&nvf_list_lock, RW_WRITER);
11987836SJohn.Forte@Sun.COM 	old_nvl = nvf_list;
11997836SJohn.Forte@Sun.COM 	nvf_list = nvl;
12007836SJohn.Forte@Sun.COM 	rw_exit(&nvf_list_lock);
12017836SJohn.Forte@Sun.COM 
12027836SJohn.Forte@Sun.COM 	/*
12037836SJohn.Forte@Sun.COM 	 * free up old nvlist
12047836SJohn.Forte@Sun.COM 	 */
12057836SJohn.Forte@Sun.COM 	if (old_nvl) {
12067836SJohn.Forte@Sun.COM 		nvlist_free(old_nvl);
12077836SJohn.Forte@Sun.COM 	}
12087836SJohn.Forte@Sun.COM 
12097836SJohn.Forte@Sun.COM 	return (B_TRUE);
12107836SJohn.Forte@Sun.COM }
12117836SJohn.Forte@Sun.COM 
12127836SJohn.Forte@Sun.COM /*
12137836SJohn.Forte@Sun.COM  * iscsid_getf -- given a file descriptor returns a file pointer
12147836SJohn.Forte@Sun.COM  */
12157836SJohn.Forte@Sun.COM static file_t *
nvf_getf(int fdes)12167836SJohn.Forte@Sun.COM nvf_getf(int fdes)
12177836SJohn.Forte@Sun.COM {
12187836SJohn.Forte@Sun.COM 	file_t	*fp = NULL;
12197836SJohn.Forte@Sun.COM 
12207836SJohn.Forte@Sun.COM 	mutex_enter(&nvf_getf_lock);
12217836SJohn.Forte@Sun.COM 	if ((fdes >= 0) && (fdes < NVF_GETF)) {
12227836SJohn.Forte@Sun.COM 		fp = nvf_fd[fdes];
12237836SJohn.Forte@Sun.COM 		if (fp != NULL)
12247836SJohn.Forte@Sun.COM 			mutex_enter(&fp->f_tlock);
12257836SJohn.Forte@Sun.COM 	}
12267836SJohn.Forte@Sun.COM 	mutex_exit(&nvf_getf_lock);
12277836SJohn.Forte@Sun.COM 
12287836SJohn.Forte@Sun.COM 	return (fp);
12297836SJohn.Forte@Sun.COM }
12307836SJohn.Forte@Sun.COM 
12317836SJohn.Forte@Sun.COM /*
12327836SJohn.Forte@Sun.COM  * nvf_releasef -- release lock on file pointer
12337836SJohn.Forte@Sun.COM  */
12347836SJohn.Forte@Sun.COM static void
nvf_releasef(int fdes)12357836SJohn.Forte@Sun.COM nvf_releasef(int fdes)
12367836SJohn.Forte@Sun.COM {
12377836SJohn.Forte@Sun.COM 	file_t  *fp;
12387836SJohn.Forte@Sun.COM 
12397836SJohn.Forte@Sun.COM 	mutex_enter(&nvf_getf_lock);
12407836SJohn.Forte@Sun.COM 	if ((fdes >= 0) && (fdes < NVF_GETF)) {
12417836SJohn.Forte@Sun.COM 		fp = nvf_fd[fdes];
12427836SJohn.Forte@Sun.COM 		mutex_exit(&fp->f_tlock);
12437836SJohn.Forte@Sun.COM 	}
12447836SJohn.Forte@Sun.COM 	mutex_exit(&nvf_getf_lock);
12457836SJohn.Forte@Sun.COM }
12467836SJohn.Forte@Sun.COM 
12477836SJohn.Forte@Sun.COM /*
12487836SJohn.Forte@Sun.COM  * nvf_setf -- stores the file pointer in an empty slot returning index
12497836SJohn.Forte@Sun.COM  */
12507836SJohn.Forte@Sun.COM static int
nvf_setf(file_t * fp)12517836SJohn.Forte@Sun.COM nvf_setf(file_t *fp)
12527836SJohn.Forte@Sun.COM {
12537836SJohn.Forte@Sun.COM 	int	i = -1;
12547836SJohn.Forte@Sun.COM 
12557836SJohn.Forte@Sun.COM 	mutex_enter(&nvf_getf_lock);
12567836SJohn.Forte@Sun.COM 	for (i = 0; i < NVF_GETF; i++) {
12577836SJohn.Forte@Sun.COM 		if (nvf_fd[i] == 0) {
12587836SJohn.Forte@Sun.COM 			nvf_fd[i] = fp;
12597836SJohn.Forte@Sun.COM 			break;
12607836SJohn.Forte@Sun.COM 		}
12617836SJohn.Forte@Sun.COM 	}
12627836SJohn.Forte@Sun.COM 	mutex_exit(&nvf_getf_lock);
12637836SJohn.Forte@Sun.COM 	return (i);
12647836SJohn.Forte@Sun.COM }
12657836SJohn.Forte@Sun.COM 
12667836SJohn.Forte@Sun.COM /*
12677836SJohn.Forte@Sun.COM  * nvf_freef -- gets the file pointer based on index and releases memory.
12687836SJohn.Forte@Sun.COM  */
12697836SJohn.Forte@Sun.COM static void
nvf_freef(int fdes)12707836SJohn.Forte@Sun.COM nvf_freef(int fdes)
12717836SJohn.Forte@Sun.COM {
12727836SJohn.Forte@Sun.COM 	file_t *fp;
12737836SJohn.Forte@Sun.COM 
12747836SJohn.Forte@Sun.COM 	mutex_enter(&nvf_getf_lock);
12757836SJohn.Forte@Sun.COM 	if ((fdes >= 0) && (fdes < NVF_GETF)) {
12767836SJohn.Forte@Sun.COM 		fp = nvf_fd[fdes];
12777836SJohn.Forte@Sun.COM 		unfalloc(fp);
12787836SJohn.Forte@Sun.COM 		nvf_fd[fdes] = NULL;
12797836SJohn.Forte@Sun.COM 	}
12807836SJohn.Forte@Sun.COM 	mutex_exit(&nvf_getf_lock);
12817836SJohn.Forte@Sun.COM }
12827836SJohn.Forte@Sun.COM 
12837836SJohn.Forte@Sun.COM /*
12847836SJohn.Forte@Sun.COM  * nvf_open -- acts like syscall open, but works for kernel
12857836SJohn.Forte@Sun.COM  *
12867836SJohn.Forte@Sun.COM  * Note: This works for regular files only. No umask is provided to
12877836SJohn.Forte@Sun.COM  * vn_open which means whatever mode is passed in will be used to
12887836SJohn.Forte@Sun.COM  * create a file.
12897836SJohn.Forte@Sun.COM  */
12907836SJohn.Forte@Sun.COM static int
nvf_open(char * path,int flags,int mode)12917836SJohn.Forte@Sun.COM nvf_open(char *path, int flags, int mode)
12927836SJohn.Forte@Sun.COM {
12937836SJohn.Forte@Sun.COM 	file_t		*fp	= NULL;
12947836SJohn.Forte@Sun.COM 	vnode_t		*vp	= NULL;
12957836SJohn.Forte@Sun.COM 	int		fdes	= -1;
12967836SJohn.Forte@Sun.COM 	int		fflags;
12977836SJohn.Forte@Sun.COM 
12987836SJohn.Forte@Sun.COM 	/*
12997836SJohn.Forte@Sun.COM 	 * Need to convert from user mode flags to file system flags.
13007836SJohn.Forte@Sun.COM 	 * It's unfortunate that the kernel doesn't define a mask for
13017836SJohn.Forte@Sun.COM 	 * the read/write bits which would make this conversion easier.
13027836SJohn.Forte@Sun.COM 	 * Only O_RDONLY/O_WRONLY/O_RDWR are different than their FXXXXX
13037836SJohn.Forte@Sun.COM 	 * counterparts. If one was provided something like
13047836SJohn.Forte@Sun.COM 	 *	fflags = ((flags & mask) + 1) | (flags & ~mask)
13057836SJohn.Forte@Sun.COM 	 * would work. But, that would only be true if the relationship
13067836SJohn.Forte@Sun.COM 	 * be O_XXX and FXXX was defined and it's not. So we have the
13077836SJohn.Forte@Sun.COM 	 * following.
13087836SJohn.Forte@Sun.COM 	 */
13097836SJohn.Forte@Sun.COM 	if (flags & O_WRONLY)
13107836SJohn.Forte@Sun.COM 		fflags = FWRITE;
13117836SJohn.Forte@Sun.COM 	else if (flags & O_RDWR)
13127836SJohn.Forte@Sun.COM 		fflags = FWRITE | FREAD;
13137836SJohn.Forte@Sun.COM 	else
13147836SJohn.Forte@Sun.COM 		fflags = FREAD;
13157836SJohn.Forte@Sun.COM 
13167836SJohn.Forte@Sun.COM 	/*
13177836SJohn.Forte@Sun.COM 	 * Now that fflags has been initialized with the read/write bits
13187836SJohn.Forte@Sun.COM 	 * look at the other flags and OR them in.
13197836SJohn.Forte@Sun.COM 	 */
13207836SJohn.Forte@Sun.COM 	if (flags & O_CREAT)
13217836SJohn.Forte@Sun.COM 		fflags |= FCREAT;
13227836SJohn.Forte@Sun.COM 	if (flags & O_TRUNC)
13237836SJohn.Forte@Sun.COM 		fflags |= FTRUNC;
13247836SJohn.Forte@Sun.COM 
13257836SJohn.Forte@Sun.COM 	if (nvf_errno = vn_open(path, UIO_SYSSPACE, fflags,
13267836SJohn.Forte@Sun.COM 	    mode & MODEMASK, &vp, CRCREAT, 0)) {
13277836SJohn.Forte@Sun.COM 		return (-1);
13287836SJohn.Forte@Sun.COM 	}
13297836SJohn.Forte@Sun.COM 
13307836SJohn.Forte@Sun.COM 	if (falloc(vp, fflags, &fp, NULL) != 0) {
13317836SJohn.Forte@Sun.COM 		VN_RELE(vp);
13327836SJohn.Forte@Sun.COM 		return (-1);
13337836SJohn.Forte@Sun.COM 	}
13347836SJohn.Forte@Sun.COM 	/* ---- falloc returns with f_tlock held on success ---- */
13357836SJohn.Forte@Sun.COM 	mutex_exit(&fp->f_tlock);
13367836SJohn.Forte@Sun.COM 
13377836SJohn.Forte@Sun.COM 	if ((fdes = nvf_setf(fp)) == -1) {
13387836SJohn.Forte@Sun.COM 		VN_RELE(vp);
13397836SJohn.Forte@Sun.COM 	}
13407836SJohn.Forte@Sun.COM 	return (fdes);
13417836SJohn.Forte@Sun.COM }
13427836SJohn.Forte@Sun.COM 
13437836SJohn.Forte@Sun.COM /*
13447836SJohn.Forte@Sun.COM  * nvf_close -- closes down the file by releasing locks and memory.
13457836SJohn.Forte@Sun.COM  */
13467836SJohn.Forte@Sun.COM static int
nvf_close(int fdes)13477836SJohn.Forte@Sun.COM nvf_close(int fdes)
13487836SJohn.Forte@Sun.COM {
13497836SJohn.Forte@Sun.COM 	file_t  *fp;
13507836SJohn.Forte@Sun.COM 	vnode_t *vp;
13517836SJohn.Forte@Sun.COM 
13527836SJohn.Forte@Sun.COM 	if ((fp = nvf_getf(fdes)) == NULL)
13537836SJohn.Forte@Sun.COM 		return (-1);
13547836SJohn.Forte@Sun.COM 	vp = fp->f_vnode;
13557836SJohn.Forte@Sun.COM 
13567836SJohn.Forte@Sun.COM 	(void) VOP_CLOSE(vp, fp->f_flag, 1, 0, kcred, NULL);
13577836SJohn.Forte@Sun.COM 	VN_RELE(vp);
13587836SJohn.Forte@Sun.COM 	/*
13597836SJohn.Forte@Sun.COM 	 * unfalloc which is called from here will do a mutex_exit
13607836SJohn.Forte@Sun.COM 	 * on t_lock in the fp. So don't call nvf_releasef() here.
13617836SJohn.Forte@Sun.COM 	 */
13627836SJohn.Forte@Sun.COM 	nvf_freef(fdes);
13637836SJohn.Forte@Sun.COM 
13647836SJohn.Forte@Sun.COM 	return (0);
13657836SJohn.Forte@Sun.COM }
13667836SJohn.Forte@Sun.COM 
13677836SJohn.Forte@Sun.COM /*
13687836SJohn.Forte@Sun.COM  * nvf_remove -- remove file from filesystem
13697836SJohn.Forte@Sun.COM  */
13707836SJohn.Forte@Sun.COM static int
nvf_remove(char * filename)13717836SJohn.Forte@Sun.COM nvf_remove(char *filename)
13727836SJohn.Forte@Sun.COM {
13737836SJohn.Forte@Sun.COM 	return (vn_remove(filename, UIO_SYSSPACE, RMFILE));
13747836SJohn.Forte@Sun.COM }
13757836SJohn.Forte@Sun.COM 
13767836SJohn.Forte@Sun.COM /*
13777836SJohn.Forte@Sun.COM  * nvf_rename -- rename file from one name to another
13787836SJohn.Forte@Sun.COM  */
13797836SJohn.Forte@Sun.COM static int
nvf_rename(char * oldname,char * newname)13807836SJohn.Forte@Sun.COM nvf_rename(char *oldname, char *newname)
13817836SJohn.Forte@Sun.COM {
13827836SJohn.Forte@Sun.COM 	return (vn_rename(oldname, newname, UIO_SYSSPACE));
13837836SJohn.Forte@Sun.COM }
13847836SJohn.Forte@Sun.COM 
13857836SJohn.Forte@Sun.COM /*
13867836SJohn.Forte@Sun.COM  * nvf_rw -- common read/write code. Very simplistic.
13877836SJohn.Forte@Sun.COM  */
13887836SJohn.Forte@Sun.COM static ssize_t
nvf_rw(int fdes,void * cbuf,ssize_t count,enum uio_rw rw)13897836SJohn.Forte@Sun.COM nvf_rw(int fdes, void *cbuf, ssize_t count, enum uio_rw rw)
13907836SJohn.Forte@Sun.COM {
13917836SJohn.Forte@Sun.COM 	file_t	*fp;
13927836SJohn.Forte@Sun.COM 	vnode_t	*vp;
13937836SJohn.Forte@Sun.COM 	ssize_t	resid   = 0;
13947836SJohn.Forte@Sun.COM 
13957836SJohn.Forte@Sun.COM 	if ((fp  = nvf_getf(fdes)) == NULL)
13967836SJohn.Forte@Sun.COM 		return (-1);
13977836SJohn.Forte@Sun.COM 	vp = fp->f_vnode;
13987836SJohn.Forte@Sun.COM 
13997836SJohn.Forte@Sun.COM 	if (nvf_errno = vn_rdwr(rw, vp, (caddr_t)cbuf, count, fp->f_offset,
14007836SJohn.Forte@Sun.COM 	    UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid)) {
14017836SJohn.Forte@Sun.COM 		nvf_releasef(fdes);
14027836SJohn.Forte@Sun.COM 		return (-1);
14037836SJohn.Forte@Sun.COM 	}
14047836SJohn.Forte@Sun.COM 
14057836SJohn.Forte@Sun.COM 	if ((count - resid) > 0)
14067836SJohn.Forte@Sun.COM 		fp->f_offset += count;
14077836SJohn.Forte@Sun.COM 
14087836SJohn.Forte@Sun.COM 	nvf_releasef(fdes);
14097836SJohn.Forte@Sun.COM 	return (count - resid);
14107836SJohn.Forte@Sun.COM }
14117836SJohn.Forte@Sun.COM 
14127836SJohn.Forte@Sun.COM /*
14137836SJohn.Forte@Sun.COM  * nvf_write -- kernel write function
14147836SJohn.Forte@Sun.COM  */
14157836SJohn.Forte@Sun.COM static ssize_t
nvf_write(int fdes,void * cbuf,ssize_t count)14167836SJohn.Forte@Sun.COM nvf_write(int fdes, void *cbuf, ssize_t count)
14177836SJohn.Forte@Sun.COM {
14187836SJohn.Forte@Sun.COM 	return (nvf_rw(fdes, cbuf, count, UIO_WRITE));
14197836SJohn.Forte@Sun.COM }
14207836SJohn.Forte@Sun.COM 
14217836SJohn.Forte@Sun.COM /*
14227836SJohn.Forte@Sun.COM  * nvf_read -- kernel read function
14237836SJohn.Forte@Sun.COM  */
14247836SJohn.Forte@Sun.COM static ssize_t
nvf_read(int fdes,void * cbuf,ssize_t count)14257836SJohn.Forte@Sun.COM nvf_read(int fdes, void *cbuf, ssize_t count)
14267836SJohn.Forte@Sun.COM {
14277836SJohn.Forte@Sun.COM 	return (nvf_rw(fdes, cbuf, count, UIO_READ));
14287836SJohn.Forte@Sun.COM }
1429