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