Home | History | Annotate | Line # | Download | only in chfs
chfs_wbuf.c revision 1.2
      1 /*	$NetBSD: chfs_wbuf.c,v 1.2 2011/11/24 20:50:33 agc Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2010 Department of Software Engineering,
      5  *		      University of Szeged, Hungary
      6  * Copyright (C) 2010 Tamas Toth <ttoth (at) inf.u-szeged.hu>
      7  * Copyright (C) 2010 Adam Hoka <ahoka (at) NetBSD.org>
      8  * All rights reserved.
      9  *
     10  * This code is derived from software contributed to The NetBSD Foundation
     11  * by the Department of Software Engineering, University of Szeged, Hungary
     12  *
     13  * Redistribution and use in source and binary forms, with or without
     14  * modification, are permitted provided that the following conditions
     15  * are met:
     16  * 1. Redistributions of source code must retain the above copyright
     17  *    notice, this list of conditions and the following disclaimer.
     18  * 2. Redistributions in binary form must reproduce the above copyright
     19  *    notice, this list of conditions and the following disclaimer in the
     20  *    documentation and/or other materials provided with the distribution.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <dev/flash/flash.h>
     36 #include <sys/uio.h>
     37 #include "chfs.h"
     38 //#include </root/xipffs/netbsd.chfs/chfs.h>
     39 
     40 #define DBG_WBUF 1
     41 
     42 #define PAD(x) (((x)+3)&~3)
     43 
     44 #define EB_ADDRESS(x) ( ((unsigned long)(x) / chmp->chm_ebh->eb_size) * chmp->chm_ebh->eb_size )
     45 
     46 #define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(chmp->chm_wbuf_pagesize)) * (unsigned long)(chmp->chm_wbuf_pagesize) )
     47 #define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(chmp->chm_wbuf_pagesize) )
     48 
     49 /*
     50 // test functions
     51 int wbuf_test(void);
     52 void wbuf_test_erase_flash(struct chfs_mount*);
     53 void wbuf_test_callback(struct erase_instruction*);
     54 */
     55 
     56 #define NOPAD	0
     57 #define SETPAD	1
     58 
     59 
     60 /**
     61  * chfs_flush_wbuf - write wbuf to the flash
     62  * @chmp: super block info
     63  * @pad: padding (NOPAD / SETPAD)
     64  * Returns zero in case of success.
     65  */
     66 static int
     67 chfs_flush_wbuf(struct chfs_mount *chmp, int pad)
     68 {
     69 	int ret=0;
     70 	size_t retlen = 0;
     71 
     72 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
     73 	KASSERT(mutex_owned(&chmp->chm_lock_sizes));
     74 	KASSERT(rw_write_held(&chmp->chm_lock_wbuf));
     75 
     76 	if (pad) {
     77 		chmp->chm_wbuf_len = PAD(chmp->chm_wbuf_len);
     78 		memset(chmp->chm_wbuf + chmp->chm_wbuf_len, 0, chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len);
     79 
     80 		struct chfs_flash_padding_node* padnode = (void*)(chmp->chm_wbuf + chmp->chm_wbuf_len);
     81 		padnode->magic = htole16(CHFS_FS_MAGIC_BITMASK);
     82 		padnode->type = htole16(CHFS_NODETYPE_PADDING);
     83 		padnode->length = htole32(chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len);
     84 		padnode->hdr_crc = htole32(crc32(0, (uint8_t *)padnode, sizeof(*padnode)-4));
     85 
     86 		struct chfs_node_ref *nref;
     87 		nref = chfs_alloc_node_ref(chmp->chm_nextblock);
     88 		nref->nref_offset = chmp->chm_wbuf_ofs + chmp->chm_wbuf_len;
     89 		nref->nref_offset = CHFS_GET_OFS(nref->nref_offset) |
     90 		    CHFS_OBSOLETE_NODE_MASK;
     91 		chmp->chm_wbuf_len = chmp->chm_wbuf_pagesize;
     92 
     93 		chfs_change_size_free(chmp, chmp->chm_nextblock, -padnode->length);
     94 		chfs_change_size_wasted(chmp, chmp->chm_nextblock, padnode->length);
     95 	}
     96 
     97 	ret = chfs_write_leb(chmp, chmp->chm_nextblock->lnr, chmp->chm_wbuf, chmp->chm_wbuf_ofs, chmp->chm_wbuf_len, &retlen);
     98 	if(ret) {
     99 		return ret;
    100 	}
    101 
    102 	memset(chmp->chm_wbuf,0xff,chmp->chm_wbuf_pagesize);
    103 	chmp->chm_wbuf_ofs += chmp->chm_wbuf_pagesize;
    104 	chmp->chm_wbuf_len = 0;
    105 	return 0;
    106 }
    107 
    108 
    109 /**
    110  * chfs_fill_wbuf - write to wbuf
    111  * @chmp: super block info
    112  * @buf: buffer
    113  * @len: buffer length
    114  * Return the len of the buf what we didn't write to the wbuf.
    115  */
    116 static size_t
    117 chfs_fill_wbuf(struct chfs_mount *chmp, const u_char *buf, size_t len)
    118 {
    119 	if (len && !chmp->chm_wbuf_len && (len >= chmp->chm_wbuf_pagesize)) {
    120 		return 0;
    121 	}
    122 	if (len > (chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len)) {
    123 		len = chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len;
    124 	}
    125 	memcpy(chmp->chm_wbuf + chmp->chm_wbuf_len, buf, len);
    126 
    127 	chmp->chm_wbuf_len += (int) len;
    128 	return len;
    129 }
    130 
    131 /**
    132  * chfs_write_wbuf - write to wbuf and then the flash
    133  * @chmp: super block info
    134  * @invecs: io vectors
    135  * @count: num of vectors
    136  * @to: offset of target
    137  * @retlen: writed bytes
    138  * Returns zero in case of success.
    139  */
    140 int
    141 chfs_write_wbuf(struct chfs_mount* chmp, const struct iovec *invecs, long count,
    142     off_t to, size_t *retlen)
    143 {
    144 	int invec, ret = 0;
    145 	size_t wbuf_retlen, donelen = 0;
    146 	int outvec_to = to;
    147 
    148 	int lnr = chmp->chm_nextblock->lnr;
    149 
    150 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    151 	KASSERT(mutex_owned(&chmp->chm_lock_sizes));
    152 	KASSERT(!rw_write_held(&chmp->chm_lock_wbuf));
    153 
    154 	rw_enter(&chmp->chm_lock_wbuf, RW_WRITER);
    155 
    156 	//dbg("1. wbuf ofs: %zu, len: %zu\n", chmp->chm_wbuf_ofs, chmp->chm_wbuf_len);
    157 
    158 	if (chmp->chm_wbuf_ofs == 0xffffffff) {
    159 		chmp->chm_wbuf_ofs = PAGE_DIV(to);
    160 		chmp->chm_wbuf_len = PAGE_MOD(to);
    161 		memset(chmp->chm_wbuf, 0xff, chmp->chm_wbuf_pagesize);
    162 	}
    163 
    164 	//dbg("2. wbuf ofs: %zu, len: %zu\n", chmp->chm_wbuf_ofs, chmp->chm_wbuf_len);
    165 
    166 	if (EB_ADDRESS(to) != EB_ADDRESS(chmp->chm_wbuf_ofs)) {
    167 		if (chmp->chm_wbuf_len) {
    168 			ret = chfs_flush_wbuf(chmp, SETPAD);
    169 			if (ret)
    170 				goto outerr;
    171 		}
    172 		chmp->chm_wbuf_ofs = PAGE_DIV(to);
    173 		chmp->chm_wbuf_len = PAGE_MOD(to);
    174 	}
    175 
    176 	//dbg("3. wbuf ofs: %zu, len: %zu\n", chmp->chm_wbuf_ofs, chmp->chm_wbuf_len);
    177 
    178 	if (to != PAD(chmp->chm_wbuf_ofs + chmp->chm_wbuf_len)) {
    179 		dbg("to: %llu != %zu\n", (unsigned long long)to,
    180 			PAD(chmp->chm_wbuf_ofs + chmp->chm_wbuf_len));
    181 		dbg("Non-contiguous write\n");
    182 		panic("BUG\n");
    183 	}
    184 
    185 	/* adjust alignment offset */
    186 	if (chmp->chm_wbuf_len != PAGE_MOD(to)) {
    187 		chmp->chm_wbuf_len = PAGE_MOD(to);
    188 		/* take care of alignement to next page*/
    189 		if (!chmp->chm_wbuf_len) {
    190 			chmp->chm_wbuf_len += chmp->chm_wbuf_pagesize;
    191 			ret = chfs_flush_wbuf(chmp, NOPAD);
    192 			if (ret)
    193 				goto outerr;
    194 		}
    195 	}
    196 
    197 	for (invec = 0; invec < count; invec++) {
    198 		int vlen = invecs[invec].iov_len;
    199 		u_char* v = invecs[invec].iov_base;
    200 
    201 		//dbg("invec:%d len:%d\n", invec, vlen);
    202 
    203 		wbuf_retlen = chfs_fill_wbuf(chmp, v, vlen);
    204 		if (chmp->chm_wbuf_len == chmp->chm_wbuf_pagesize) {
    205 			ret = chfs_flush_wbuf(chmp, NOPAD);
    206 			if (ret) {
    207 				goto outerr;
    208 			}
    209 		}
    210 		vlen -= wbuf_retlen;
    211 		outvec_to += wbuf_retlen;
    212 		v += wbuf_retlen;
    213 		donelen += wbuf_retlen;
    214 		if (vlen >= chmp->chm_wbuf_pagesize) {
    215 			ret = chfs_write_leb(chmp, lnr, v, outvec_to, PAGE_DIV(vlen), &wbuf_retlen);
    216 			//dbg("fd->write: %zu\n", wbuf_retlen);
    217 			vlen -= wbuf_retlen;
    218 			outvec_to += wbuf_retlen;
    219 			chmp->chm_wbuf_ofs = outvec_to;
    220 			v += wbuf_retlen;
    221 			donelen += wbuf_retlen;
    222 		}
    223 		wbuf_retlen = chfs_fill_wbuf(chmp, v, vlen);
    224 		if (chmp->chm_wbuf_len == chmp->chm_wbuf_pagesize) {
    225 			ret = chfs_flush_wbuf(chmp, NOPAD);
    226 			if (ret)
    227 				goto outerr;
    228 		}
    229 
    230 		// if we write the last vector, we flush with padding
    231 		/*if (invec == count-1) {
    232 		  ret = chfs_flush_wbuf(chmp, SETPAD);
    233 		  if (ret)
    234 		  goto outerr;
    235 		  }*/
    236 		outvec_to += wbuf_retlen;
    237 		donelen += wbuf_retlen;
    238 	}
    239 	*retlen = donelen;
    240 	rw_exit(&chmp->chm_lock_wbuf);
    241 	return ret;
    242 
    243 outerr:
    244 	*retlen = 0;
    245 	return ret;
    246 }
    247 
    248 int chfs_flush_pending_wbuf(struct chfs_mount *chmp)
    249 {
    250 	//dbg("flush pending wbuf\n");
    251 	int err;
    252 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    253 	mutex_enter(&chmp->chm_lock_sizes);
    254 	rw_enter(&chmp->chm_lock_wbuf, RW_WRITER);
    255 	err = chfs_flush_wbuf(chmp, SETPAD);
    256 	rw_exit(&chmp->chm_lock_wbuf);
    257 	mutex_exit(&chmp->chm_lock_sizes);
    258 	return err;
    259 }
    260