Home | History | Annotate | Line # | Download | only in chfs
chfs_wbuf.c revision 1.2.2.1
      1 /*	$NetBSD: chfs_wbuf.c,v 1.2.2.1 2012/02/18 07:35:52 mrg 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 
     39 #define DBG_WBUF 1		/* XXX unused, but should be */
     40 
     41 #define PAD(x) (((x)+3)&~3)
     42 
     43 #define EB_ADDRESS(x) ( rounddown((x), chmp->chm_ebh->eb_size) )
     44 
     45 #define PAGE_DIV(x) ( rounddown((x), chmp->chm_wbuf_pagesize) )
     46 #define PAGE_MOD(x) ( (x) % (chmp->chm_wbuf_pagesize) )
     47 
     48 enum {
     49 	WBUF_NOPAD,
     50 	WBUF_SETPAD
     51 };
     52 
     53 /**
     54  * chfs_flush_wbuf - write wbuf to the flash
     55  * @chmp: super block info
     56  * @pad: padding (WBUF_NOPAD / WBUF_SETPAD)
     57  * Returns zero in case of success.
     58  */
     59 static int
     60 chfs_flush_wbuf(struct chfs_mount *chmp, int pad)
     61 {
     62 	int ret;
     63 	size_t retlen;
     64 	struct chfs_node_ref *nref;
     65 	struct chfs_flash_padding_node* padnode;
     66 
     67 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
     68 	KASSERT(mutex_owned(&chmp->chm_lock_sizes));
     69 	KASSERT(rw_write_held(&chmp->chm_lock_wbuf));
     70 	KASSERT(pad == WBUF_SETPAD || pad == WBUF_NOPAD);
     71 
     72 	if (pad == WBUF_SETPAD) {
     73 		chmp->chm_wbuf_len = PAD(chmp->chm_wbuf_len);
     74 		memset(chmp->chm_wbuf + chmp->chm_wbuf_len, 0,
     75 		    chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len);
     76 
     77 		padnode = (void *)(chmp->chm_wbuf + chmp->chm_wbuf_len);
     78 		padnode->magic = htole16(CHFS_FS_MAGIC_BITMASK);
     79 		padnode->type = htole16(CHFS_NODETYPE_PADDING);
     80 		padnode->length = htole32(chmp->chm_wbuf_pagesize
     81 		    - chmp->chm_wbuf_len);
     82 		padnode->hdr_crc = htole32(crc32(0, (uint8_t *)padnode,
     83 			sizeof(*padnode)-4));
     84 
     85 		nref = chfs_alloc_node_ref(chmp->chm_nextblock);
     86 		nref->nref_offset = chmp->chm_wbuf_ofs + chmp->chm_wbuf_len;
     87 		nref->nref_offset = CHFS_GET_OFS(nref->nref_offset) |
     88 		    CHFS_OBSOLETE_NODE_MASK;
     89 		chmp->chm_wbuf_len = chmp->chm_wbuf_pagesize;
     90 
     91 		chfs_change_size_free(chmp, chmp->chm_nextblock,
     92 		    -padnode->length);
     93 		chfs_change_size_wasted(chmp, chmp->chm_nextblock,
     94 		    padnode->length);
     95 	}
     96 
     97 	ret = chfs_write_leb(chmp, chmp->chm_nextblock->lnr, chmp->chm_wbuf,
     98 	    chmp->chm_wbuf_ofs, chmp->chm_wbuf_len, &retlen);
     99 	if (ret) {
    100 		return ret;
    101 	}
    102 
    103 	memset(chmp->chm_wbuf, 0xff, chmp->chm_wbuf_pagesize);
    104 	chmp->chm_wbuf_ofs += chmp->chm_wbuf_pagesize;
    105 	chmp->chm_wbuf_len = 0;
    106 
    107 	return 0;
    108 }
    109 
    110 
    111 /**
    112  * chfs_fill_wbuf - write to wbuf
    113  * @chmp: super block info
    114  * @buf: buffer
    115  * @len: buffer length
    116  * Return the len of the buf what we didn't write to the wbuf.
    117  */
    118 static size_t
    119 chfs_fill_wbuf(struct chfs_mount *chmp, const u_char *buf, size_t len)
    120 {
    121 	if (len && !chmp->chm_wbuf_len && (len >= chmp->chm_wbuf_pagesize)) {
    122 		return 0;
    123 	}
    124 	if (len > (chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len)) {
    125 		len = chmp->chm_wbuf_pagesize - chmp->chm_wbuf_len;
    126 	}
    127 	memcpy(chmp->chm_wbuf + chmp->chm_wbuf_len, buf, len);
    128 
    129 	chmp->chm_wbuf_len += (int) len;
    130 	return len;
    131 }
    132 
    133 /**
    134  * chfs_write_wbuf - write to wbuf and then the flash
    135  * @chmp: super block info
    136  * @invecs: io vectors
    137  * @count: num of vectors
    138  * @to: offset of target
    139  * @retlen: writed bytes
    140  * Returns zero in case of success.
    141  */
    142 int
    143 chfs_write_wbuf(struct chfs_mount* chmp, const struct iovec *invecs, long count,
    144     off_t to, size_t *retlen)
    145 {
    146 	int invec, ret = 0;
    147 	size_t wbuf_retlen, donelen = 0;
    148 	int outvec_to = to;
    149 
    150 	int lnr = chmp->chm_nextblock->lnr;
    151 
    152 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    153 	KASSERT(mutex_owned(&chmp->chm_lock_sizes));
    154 	KASSERT(!rw_write_held(&chmp->chm_lock_wbuf));
    155 
    156 	rw_enter(&chmp->chm_lock_wbuf, RW_WRITER);
    157 
    158 	//dbg("1. wbuf ofs: %zu, len: %zu\n", chmp->chm_wbuf_ofs, chmp->chm_wbuf_len);
    159 
    160 	if (chmp->chm_wbuf_ofs == 0xffffffff) {
    161 		chmp->chm_wbuf_ofs = PAGE_DIV(to);
    162 		chmp->chm_wbuf_len = PAGE_MOD(to);
    163 		memset(chmp->chm_wbuf, 0xff, chmp->chm_wbuf_pagesize);
    164 	}
    165 
    166 	//dbg("2. wbuf ofs: %zu, len: %zu\n", chmp->chm_wbuf_ofs, chmp->chm_wbuf_len);
    167 
    168 	if (EB_ADDRESS(to) != EB_ADDRESS(chmp->chm_wbuf_ofs)) {
    169 		if (chmp->chm_wbuf_len) {
    170 			ret = chfs_flush_wbuf(chmp, WBUF_SETPAD);
    171 			if (ret)
    172 				goto outerr;
    173 		}
    174 		chmp->chm_wbuf_ofs = PAGE_DIV(to);
    175 		chmp->chm_wbuf_len = PAGE_MOD(to);
    176 	}
    177 
    178 	//dbg("3. wbuf ofs: %zu, len: %zu\n", chmp->chm_wbuf_ofs, chmp->chm_wbuf_len);
    179 
    180 	if (to != PAD(chmp->chm_wbuf_ofs + chmp->chm_wbuf_len)) {
    181 		dbg("to: %llu != %zu\n", (unsigned long long)to,
    182 			PAD(chmp->chm_wbuf_ofs + chmp->chm_wbuf_len));
    183 		dbg("Non-contiguous write\n");
    184 		panic("BUG\n");
    185 	}
    186 
    187 	/* adjust alignment offset */
    188 	if (chmp->chm_wbuf_len != PAGE_MOD(to)) {
    189 		chmp->chm_wbuf_len = PAGE_MOD(to);
    190 		/* take care of alignement to next page*/
    191 		if (!chmp->chm_wbuf_len) {
    192 			chmp->chm_wbuf_len += chmp->chm_wbuf_pagesize;
    193 			ret = chfs_flush_wbuf(chmp, WBUF_NOPAD);
    194 			if (ret)
    195 				goto outerr;
    196 		}
    197 	}
    198 
    199 	for (invec = 0; invec < count; invec++) {
    200 		int vlen = invecs[invec].iov_len;
    201 		u_char* v = invecs[invec].iov_base;
    202 
    203 		//dbg("invec:%d len:%d\n", invec, vlen);
    204 
    205 		wbuf_retlen = chfs_fill_wbuf(chmp, v, vlen);
    206 		if (chmp->chm_wbuf_len == chmp->chm_wbuf_pagesize) {
    207 			ret = chfs_flush_wbuf(chmp, WBUF_NOPAD);
    208 			if (ret) {
    209 				goto outerr;
    210 			}
    211 		}
    212 		vlen -= wbuf_retlen;
    213 		outvec_to += wbuf_retlen;
    214 		v += wbuf_retlen;
    215 		donelen += wbuf_retlen;
    216 		if (vlen >= chmp->chm_wbuf_pagesize) {
    217 			ret = chfs_write_leb(chmp, lnr, v, outvec_to, PAGE_DIV(vlen), &wbuf_retlen);
    218 			//dbg("fd->write: %zu\n", wbuf_retlen);
    219 			vlen -= wbuf_retlen;
    220 			outvec_to += wbuf_retlen;
    221 			chmp->chm_wbuf_ofs = outvec_to;
    222 			v += wbuf_retlen;
    223 			donelen += wbuf_retlen;
    224 		}
    225 		wbuf_retlen = chfs_fill_wbuf(chmp, v, vlen);
    226 		if (chmp->chm_wbuf_len == chmp->chm_wbuf_pagesize) {
    227 			ret = chfs_flush_wbuf(chmp, WBUF_NOPAD);
    228 			if (ret)
    229 				goto outerr;
    230 		}
    231 
    232 		// if we write the last vector, we flush with padding
    233 		/*if (invec == count-1) {
    234 		  ret = chfs_flush_wbuf(chmp, WBUF_SETPAD);
    235 		  if (ret)
    236 		  goto outerr;
    237 		  }*/
    238 		outvec_to += wbuf_retlen;
    239 		donelen += wbuf_retlen;
    240 	}
    241 	*retlen = donelen;
    242 	rw_exit(&chmp->chm_lock_wbuf);
    243 	return ret;
    244 
    245 outerr:
    246 	*retlen = 0;
    247 	return ret;
    248 }
    249 
    250 int chfs_flush_pending_wbuf(struct chfs_mount *chmp)
    251 {
    252 	//dbg("flush pending wbuf\n");
    253 	int err;
    254 	KASSERT(mutex_owned(&chmp->chm_lock_mountfields));
    255 	mutex_enter(&chmp->chm_lock_sizes);
    256 	rw_enter(&chmp->chm_lock_wbuf, RW_WRITER);
    257 	err = chfs_flush_wbuf(chmp, WBUF_SETPAD);
    258 	rw_exit(&chmp->chm_lock_wbuf);
    259 	mutex_exit(&chmp->chm_lock_sizes);
    260 	return err;
    261 }
    262