1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#ifndef __UBOOT__
29#include <log.h>
30#include <malloc.h>
31#include <linux/uaccess.h>
32#else
33#include <div64.h>
34#include <ubi_uboot.h>
35#endif
36#include <linux/err.h>
37#include <linux/math64.h>
38
39#include "ubi.h"
40
41
42
43
44
45
46
47
48
49static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol)
50{
51 int err;
52 struct ubi_vtbl_record vtbl_rec;
53
54 dbg_gen("set update marker for volume %d", vol->vol_id);
55
56 if (vol->upd_marker) {
57 ubi_assert(ubi->vtbl[vol->vol_id].upd_marker);
58 dbg_gen("already set");
59 return 0;
60 }
61
62 vtbl_rec = ubi->vtbl[vol->vol_id];
63 vtbl_rec.upd_marker = 1;
64
65 mutex_lock(&ubi->device_mutex);
66 err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
67 vol->upd_marker = 1;
68 mutex_unlock(&ubi->device_mutex);
69 return err;
70}
71
72
73
74
75
76
77
78
79
80
81
82static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol,
83 long long bytes)
84{
85 int err;
86 struct ubi_vtbl_record vtbl_rec;
87
88 dbg_gen("clear update marker for volume %d", vol->vol_id);
89
90 vtbl_rec = ubi->vtbl[vol->vol_id];
91 ubi_assert(vol->upd_marker && vtbl_rec.upd_marker);
92 vtbl_rec.upd_marker = 0;
93
94 if (vol->vol_type == UBI_STATIC_VOLUME) {
95 vol->corrupted = 0;
96 vol->used_bytes = bytes;
97 vol->used_ebs = div_u64_rem(bytes, vol->usable_leb_size,
98 &vol->last_eb_bytes);
99 if (vol->last_eb_bytes)
100 vol->used_ebs += 1;
101 else
102 vol->last_eb_bytes = vol->usable_leb_size;
103 }
104
105 mutex_lock(&ubi->device_mutex);
106 err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec);
107 vol->upd_marker = 0;
108 mutex_unlock(&ubi->device_mutex);
109 return err;
110}
111
112
113
114
115
116
117
118
119
120
121
122int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
123 long long bytes)
124{
125 int i, err;
126
127 dbg_gen("start update of volume %d, %llu bytes", vol->vol_id, bytes);
128 ubi_assert(!vol->updating && !vol->changing_leb);
129 vol->updating = 1;
130
131 vol->upd_buf = vmalloc(ubi->leb_size);
132 if (!vol->upd_buf)
133 return -ENOMEM;
134
135 err = set_update_marker(ubi, vol);
136 if (err)
137 return err;
138
139
140 for (i = 0; i < vol->reserved_pebs; i++) {
141 err = ubi_eba_unmap_leb(ubi, vol, i);
142 if (err)
143 return err;
144 }
145
146 if (bytes == 0) {
147 err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
148 if (err)
149 return err;
150
151 err = clear_update_marker(ubi, vol, 0);
152 if (err)
153 return err;
154
155 vfree(vol->upd_buf);
156 vol->updating = 0;
157 return 0;
158 }
159
160 vol->upd_ebs = div_u64(bytes + vol->usable_leb_size - 1,
161 vol->usable_leb_size);
162 vol->upd_bytes = bytes;
163 vol->upd_received = 0;
164 return 0;
165}
166
167
168
169
170
171
172
173
174
175
176int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
177 const struct ubi_leb_change_req *req)
178{
179 ubi_assert(!vol->updating && !vol->changing_leb);
180
181 dbg_gen("start changing LEB %d:%d, %u bytes",
182 vol->vol_id, req->lnum, req->bytes);
183 if (req->bytes == 0)
184 return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0);
185
186 vol->upd_bytes = req->bytes;
187 vol->upd_received = 0;
188 vol->changing_leb = 1;
189 vol->ch_lnum = req->lnum;
190
191 vol->upd_buf = vmalloc(req->bytes);
192 if (!vol->upd_buf)
193 return -ENOMEM;
194
195 return 0;
196}
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
228 void *buf, int len, int used_ebs)
229{
230 int err;
231
232 if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
233 int l = ALIGN(len, ubi->min_io_size);
234
235 memset(buf + len, 0xFF, l - len);
236 len = ubi_calc_data_len(ubi, buf, l);
237 if (len == 0) {
238 dbg_gen("all %d bytes contain 0xFF - skip", len);
239 return 0;
240 }
241
242 err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len);
243 } else {
244
245
246
247
248
249
250
251
252
253 memset(buf + len, 0, vol->usable_leb_size - len);
254 err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len, used_ebs);
255 }
256
257 return err;
258}
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
274 const void __user *buf, int count)
275{
276#ifndef __UBOOT__
277 int lnum, offs, err = 0, len, to_write = count;
278#else
279 int lnum, err = 0, len, to_write = count;
280 u32 offs;
281#endif
282
283 dbg_gen("write %d of %lld bytes, %lld already passed",
284 count, vol->upd_bytes, vol->upd_received);
285
286 if (ubi->ro_mode)
287 return -EROFS;
288
289 lnum = div_u64_rem(vol->upd_received, vol->usable_leb_size, &offs);
290 if (vol->upd_received + count > vol->upd_bytes)
291 to_write = count = vol->upd_bytes - vol->upd_received;
292
293
294
295
296
297 if (offs != 0) {
298
299
300
301
302
303
304
305 len = vol->usable_leb_size - offs;
306 if (len > count)
307 len = count;
308
309 err = copy_from_user(vol->upd_buf + offs, buf, len);
310 if (err)
311 return -EFAULT;
312
313 if (offs + len == vol->usable_leb_size ||
314 vol->upd_received + len == vol->upd_bytes) {
315 int flush_len = offs + len;
316
317
318
319
320
321 ubi_assert(flush_len <= vol->usable_leb_size);
322 err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len,
323 vol->upd_ebs);
324 if (err)
325 return err;
326 }
327
328 vol->upd_received += len;
329 count -= len;
330 buf += len;
331 lnum += 1;
332 }
333
334
335
336
337
338 while (count) {
339 if (count > vol->usable_leb_size)
340 len = vol->usable_leb_size;
341 else
342 len = count;
343
344 err = copy_from_user(vol->upd_buf, buf, len);
345 if (err)
346 return -EFAULT;
347
348 if (len == vol->usable_leb_size ||
349 vol->upd_received + len == vol->upd_bytes) {
350 err = write_leb(ubi, vol, lnum, vol->upd_buf,
351 len, vol->upd_ebs);
352 if (err)
353 break;
354 }
355
356 vol->upd_received += len;
357 count -= len;
358 lnum += 1;
359 buf += len;
360 }
361
362 ubi_assert(vol->upd_received <= vol->upd_bytes);
363 if (vol->upd_received == vol->upd_bytes) {
364 err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
365 if (err)
366 return err;
367
368 err = clear_update_marker(ubi, vol, vol->upd_bytes);
369 if (err)
370 return err;
371 vol->updating = 0;
372 err = to_write;
373 vfree(vol->upd_buf);
374 }
375
376 return err;
377}
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
394 const void __user *buf, int count)
395{
396 int err;
397
398 dbg_gen("write %d of %lld bytes, %lld already passed",
399 count, vol->upd_bytes, vol->upd_received);
400
401 if (ubi->ro_mode)
402 return -EROFS;
403
404 if (vol->upd_received + count > vol->upd_bytes)
405 count = vol->upd_bytes - vol->upd_received;
406
407 err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count);
408 if (err)
409 return -EFAULT;
410
411 vol->upd_received += count;
412
413 if (vol->upd_received == vol->upd_bytes) {
414 int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size);
415
416 memset(vol->upd_buf + vol->upd_bytes, 0xFF,
417 len - vol->upd_bytes);
418 len = ubi_calc_data_len(ubi, vol->upd_buf, len);
419 err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum,
420 vol->upd_buf, len);
421 if (err)
422 return err;
423 }
424
425 ubi_assert(vol->upd_received <= vol->upd_bytes);
426 if (vol->upd_received == vol->upd_bytes) {
427 vol->changing_leb = 0;
428 err = count;
429 vfree(vol->upd_buf);
430 }
431
432 return err;
433}
434