aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/upd.c
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-01-24 11:48:21 -0500
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-01-25 09:41:26 -0500
commite653879c269735c9ff6684e03edf1d4e041ff3d3 (patch)
tree2019a018e3fd809798dabfa92e356acc8030cdd4 /drivers/mtd/ubi/upd.c
parent866136827b9a71c39dcb06d23ce523f719eab74b (diff)
UBI: implement atomic LEB change ioctl
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd/ubi/upd.c')
-rw-r--r--drivers/mtd/ubi/upd.c112
1 files changed, 100 insertions, 12 deletions
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 59c61ab4f2aa..ddaa1a56cc69 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -22,7 +22,8 @@
22 */ 22 */
23 23
24/* 24/*
25 * This file contains implementation of the volume update functionality. 25 * This file contains implementation of the volume update and atomic LEB change
26 * functionality.
26 * 27 *
27 * The update operation is based on the per-volume update marker which is 28 * The update operation is based on the per-volume update marker which is
28 * stored in the volume table. The update marker is set before the update 29 * stored in the volume table. The update marker is set before the update
@@ -133,6 +134,7 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
133 uint64_t tmp; 134 uint64_t tmp;
134 135
135 dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes); 136 dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes);
137 ubi_assert(!vol->updating && !vol->changing_leb);
136 vol->updating = 1; 138 vol->updating = 1;
137 139
138 err = set_update_marker(ubi, vol); 140 err = set_update_marker(ubi, vol);
@@ -168,6 +170,39 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
168} 170}
169 171
170/** 172/**
173 * ubi_start_leb_change - start atomic LEB change.
174 * @ubi: UBI device description object
175 * @vol: volume description object
176 * @req: operation request
177 *
178 * This function starts atomic LEB change operation. Returns zero in case of
179 * success and a negative error code in case of failure.
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_msg("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/**
171 * write_leb - write update data. 206 * write_leb - write update data.
172 * @ubi: UBI device description object 207 * @ubi: UBI device description object
173 * @vol: volume description object 208 * @vol: volume description object
@@ -199,21 +234,19 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
199static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, 234static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
200 void *buf, int len, int used_ebs) 235 void *buf, int len, int used_ebs)
201{ 236{
202 int err, l; 237 int err;
203 238
204 if (vol->vol_type == UBI_DYNAMIC_VOLUME) { 239 if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
205 l = ALIGN(len, ubi->min_io_size); 240 len = ALIGN(len, ubi->min_io_size);
206 memset(buf + len, 0xFF, l - len); 241 memset(buf + len, 0xFF, len - len);
207 242
208 l = ubi_calc_data_len(ubi, buf, l); 243 len = ubi_calc_data_len(ubi, buf, len);
209 if (l == 0) { 244 if (len == 0) {
210 dbg_msg("all %d bytes contain 0xFF - skip", len); 245 dbg_msg("all %d bytes contain 0xFF - skip", len);
211 return 0; 246 return 0;
212 } 247 }
213 if (len != l)
214 dbg_msg("skip last %d bytes (0xFF)", len - l);
215 248
216 err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, l, UBI_UNKNOWN); 249 err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len, UBI_UNKNOWN);
217 } else { 250 } else {
218 /* 251 /*
219 * When writing static volume, and this is the last logical 252 * When writing static volume, and this is the last logical
@@ -239,9 +272,9 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
239 * @count: how much bytes to write 272 * @count: how much bytes to write
240 * 273 *
241 * This function writes more data to the volume which is being updated. It may 274 * This function writes more data to the volume which is being updated. It may
242 * be called arbitrary number of times until all of the update data arrive. 275 * be called arbitrary number of times until all the update data arriveis. This
243 * This function returns %0 in case of success, number of bytes written during 276 * function returns %0 in case of success, number of bytes written during the
244 * the last call if the whole volume update was successfully finished, and a 277 * last call if the whole volume update has been successfully finished, and a
245 * negative error code in case of failure. 278 * negative error code in case of failure.
246 */ 279 */
247int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, 280int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
@@ -340,6 +373,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
340 return err; 373 return err;
341 err = ubi_wl_flush(ubi); 374 err = ubi_wl_flush(ubi);
342 if (err == 0) { 375 if (err == 0) {
376 vol->updating = 0;
343 err = to_write; 377 err = to_write;
344 vfree(vol->upd_buf); 378 vfree(vol->upd_buf);
345 } 379 }
@@ -347,3 +381,57 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
347 381
348 return err; 382 return err;
349} 383}
384
385/**
386 * ubi_more_leb_change_data - accept more data for atomic LEB change.
387 * @vol: volume description object
388 * @buf: write data (user-space memory buffer)
389 * @count: how much bytes to write
390 *
391 * This function accepts more data to the volume which is being under the
392 * "atomic LEB change" operation. It may be called arbitrary number of times
393 * until all data arrives. This function returns %0 in case of success, number
394 * of bytes written during the last call if the whole "atomic LEB change"
395 * operation has been successfully finished, and a negative error code in case
396 * of failure.
397 */
398int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
399 const void __user *buf, int count)
400{
401 int err;
402
403 dbg_msg("write %d of %lld bytes, %lld already passed",
404 count, vol->upd_bytes, vol->upd_received);
405
406 if (ubi->ro_mode)
407 return -EROFS;
408
409 if (vol->upd_received + count > vol->upd_bytes)
410 count = vol->upd_bytes - vol->upd_received;
411
412 err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count);
413 if (err)
414 return -EFAULT;
415
416 vol->upd_received += count;
417
418 if (vol->upd_received == vol->upd_bytes) {
419 int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size);
420
421 memset(vol->upd_buf + vol->upd_bytes, 0xFF, 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}