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