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