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 = ubi_wl_flush(ubi);
151 if (err)
152 return err;
153
154 err = clear_update_marker(ubi, vol, 0);
155 if (err)
156 return err;
157 vol->updating = 0;
158 return 0;
159 }
160
161 vol->upd_buf = vmalloc(ubi->leb_size);
162 if (!vol->upd_buf)
163 return -ENOMEM;
164
165 vol->upd_ebs = div_u64(bytes + vol->usable_leb_size - 1,
166 vol->usable_leb_size);
167 vol->upd_bytes = bytes;
168 vol->upd_received = 0;
169 return 0;
170}
171
172
173
174
175
176
177
178
179
180
181int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
182 const struct ubi_leb_change_req *req)
183{
184 ubi_assert(!vol->updating && !vol->changing_leb);
185
186 dbg_gen("start changing LEB %d:%d, %u bytes",
187 vol->vol_id, req->lnum, req->bytes);
188 if (req->bytes == 0)
189 return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0,
190 req->dtype);
191
192 vol->upd_bytes = req->bytes;
193 vol->upd_received = 0;
194 vol->changing_leb = 1;
195 vol->ch_lnum = req->lnum;
196 vol->ch_dtype = req->dtype;
197
198 vol->upd_buf = vmalloc(req->bytes);
199 if (!vol->upd_buf)
200 return -ENOMEM;
201
202 return 0;
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
231
232
233
234static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
235 void *buf, int len, int used_ebs)
236{
237 int err;
238
239 if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
240 int l = ALIGN(len, ubi->min_io_size);
241
242 memset(buf + len, 0xFF, l - len);
243 len = ubi_calc_data_len(ubi, buf, l);
244 if (len == 0) {
245 dbg_gen("all %d bytes contain 0xFF - skip", len);
246 return 0;
247 }
248
249 err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len,
250 UBI_UNKNOWN);
251 } else {
252
253
254
255
256
257
258
259
260
261 memset(buf + len, 0, vol->usable_leb_size - len);
262 err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len,
263 UBI_UNKNOWN, used_ebs);
264 }
265
266 return err;
267}
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
283 const void __user *buf, int count)
284{
285 int lnum, offs, err = 0, len, to_write = count;
286
287 dbg_gen("write %d of %lld bytes, %lld already passed",
288 count, vol->upd_bytes, vol->upd_received);
289
290 if (ubi->ro_mode)
291 return -EROFS;
292
293 lnum = div_u64_rem(vol->upd_received, vol->usable_leb_size, &offs);
294 if (vol->upd_received + count > vol->upd_bytes)
295 to_write = count = vol->upd_bytes - vol->upd_received;
296
297
298
299
300
301 if (offs != 0) {
302
303
304
305
306
307
308
309 len = vol->usable_leb_size - offs;
310 if (len > count)
311 len = count;
312
313 err = copy_from_user(vol->upd_buf + offs, buf, len);
314 if (err)
315 return -EFAULT;
316
317 if (offs + len == vol->usable_leb_size ||
318 vol->upd_received + len == vol->upd_bytes) {
319 int flush_len = offs + len;
320
321
322
323
324
325 ubi_assert(flush_len <= vol->usable_leb_size);
326 err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len,
327 vol->upd_ebs);
328 if (err)
329 return err;
330 }
331
332 vol->upd_received += len;
333 count -= len;
334 buf += len;
335 lnum += 1;
336 }
337
338
339
340
341
342 while (count) {
343 if (count > vol->usable_leb_size)
344 len = vol->usable_leb_size;
345 else
346 len = count;
347
348 err = copy_from_user(vol->upd_buf, buf, len);
349 if (err)
350 return -EFAULT;
351
352 if (len == vol->usable_leb_size ||
353 vol->upd_received + len == vol->upd_bytes) {
354 err = write_leb(ubi, vol, lnum, vol->upd_buf,
355 len, vol->upd_ebs);
356 if (err)
357 break;
358 }
359
360 vol->upd_received += len;
361 count -= len;
362 lnum += 1;
363 buf += len;
364 }
365
366 ubi_assert(vol->upd_received <= vol->upd_bytes);
367 if (vol->upd_received == vol->upd_bytes) {
368 err = ubi_wl_flush(ubi);
369 if (err)
370 return err;
371
372 err = clear_update_marker(ubi, vol, vol->upd_bytes);
373 if (err)
374 return err;
375 vol->updating = 0;
376 err = to_write;
377 vfree(vol->upd_buf);
378 }
379
380 return err;
381}
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
398 const void __user *buf, int count)
399{
400 int err;
401
402 dbg_gen("write %d of %lld bytes, %lld already passed",
403 count, vol->upd_bytes, vol->upd_received);
404
405 if (ubi->ro_mode)
406 return -EROFS;
407
408 if (vol->upd_received + count > vol->upd_bytes)
409 count = vol->upd_bytes - vol->upd_received;
410
411 err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count);
412 if (err)
413 return -EFAULT;
414
415 vol->upd_received += count;
416
417 if (vol->upd_received == vol->upd_bytes) {
418 int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size);
419
420 memset(vol->upd_buf + vol->upd_bytes, 0xFF,
421 len - vol->upd_bytes);
422 len = ubi_calc_data_len(ubi, vol->upd_buf, len);
423 err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum,
424 vol->upd_buf, len, UBI_UNKNOWN);
425 if (err)
426 return err;
427 }
428
429 ubi_assert(vol->upd_received <= vol->upd_bytes);
430 if (vol->upd_received == vol->upd_bytes) {
431 vol->changing_leb = 0;
432 err = count;
433 vfree(vol->upd_buf);
434 }
435
436 return err;
437}
438