]> err.no Git - linux-2.6/blobdiff - drivers/mtd/ubi/cdev.c
olpc: sdhci: add quirk for the Marvell CaFe's vdd/powerup issue
[linux-2.6] / drivers / mtd / ubi / cdev.c
index 5ec13dc4705b92a24ab47abb56c9bf4198d4feb7..9d6aae5449b67010e0ba80e247aab81e3b030ce9 100644 (file)
@@ -132,8 +132,15 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
        if (vol->updating) {
                ubi_warn("update of volume %d not finished, volume is damaged",
                         vol->vol_id);
+               ubi_assert(!vol->changing_leb);
                vol->updating = 0;
                vfree(vol->upd_buf);
+       } else if (vol->changing_leb) {
+               dbg_msg("only %lld of %lld bytes received for atomic LEB change"
+                       " for volume %d:%d, cancel", vol->upd_received,
+                       vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id);
+               vol->changing_leb = 0;
+               vfree(vol->upd_buf);
        }
 
        ubi_close_volume(desc);
@@ -184,13 +191,13 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
        struct ubi_volume_desc *desc = file->private_data;
        struct ubi_volume *vol = desc->vol;
        struct ubi_device *ubi = vol->ubi;
-       int err, lnum, off, len,  vol_id = desc->vol->vol_id, tbuf_size;
+       int err, lnum, off, len,  tbuf_size;
        size_t count_save = count;
        void *tbuf;
        uint64_t tmp;
 
        dbg_msg("read %zd bytes from offset %lld of volume %d",
-               count, *offp, vol_id);
+               count, *offp, vol->vol_id);
 
        if (vol->updating) {
                dbg_err("updating");
@@ -204,7 +211,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
                return 0;
 
        if (vol->corrupted)
-               dbg_msg("read from corrupted volume %d", vol_id);
+               dbg_msg("read from corrupted volume %d", vol->vol_id);
 
        if (*offp + count > vol->used_bytes)
                count_save = count = vol->used_bytes - *offp;
@@ -274,7 +281,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
        uint64_t tmp;
 
        dbg_msg("requested: write %zd bytes to offset %lld of volume %u",
-               count, *offp, desc->vol->vol_id);
+               count, *offp, vol->vol_id);
 
        if (vol->vol_type == UBI_STATIC_VOLUME)
                return -EROFS;
@@ -351,23 +358,32 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
        struct ubi_volume *vol = desc->vol;
        struct ubi_device *ubi = vol->ubi;
 
-       if (!vol->updating)
+       if (!vol->updating && !vol->changing_leb)
                return vol_cdev_direct_write(file, buf, count, offp);
 
-       err = ubi_more_update_data(ubi, vol->vol_id, buf, count);
+       if (vol->updating)
+               err = ubi_more_update_data(ubi, vol, buf, count);
+       else
+               err = ubi_more_leb_change_data(ubi, vol, buf, count);
+
        if (err < 0) {
-               ubi_err("cannot write %zd bytes of update data, error %d",
+               ubi_err("cannot accept more %zd bytes of data, error %d",
                        count, err);
                return err;
        }
 
        if (err) {
                /*
-                * Update is finished, @err contains number of actually written
-                * bytes now.
+                * The operation is finished, @err contains number of actually
+                * written bytes.
                 */
                count = err;
 
+               if (vol->changing_leb) {
+                       revoke_exclusive(desc, UBI_READWRITE);
+                       return count;
+               }
+
                err = ubi_check_volume(ubi, vol->vol_id);
                if (err < 0)
                        return err;
@@ -382,7 +398,6 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
                revoke_exclusive(desc, UBI_READWRITE);
        }
 
-       *offp += count;
        return count;
 }
 
@@ -427,11 +442,46 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
                if (err < 0)
                        break;
 
-               err = ubi_start_update(ubi, vol->vol_id, bytes);
+               err = ubi_start_update(ubi, vol, bytes);
                if (bytes == 0)
                        revoke_exclusive(desc, UBI_READWRITE);
+               break;
+       }
+
+       /* Atomic logical eraseblock change command */
+       case UBI_IOCEBCH:
+       {
+               struct ubi_leb_change_req req;
+
+               err = copy_from_user(&req, argp,
+                                    sizeof(struct ubi_leb_change_req));
+               if (err) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (desc->mode == UBI_READONLY ||
+                   vol->vol_type == UBI_STATIC_VOLUME) {
+                       err = -EROFS;
+                       break;
+               }
+
+               /* Validate the request */
+               err = -EINVAL;
+               if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
+                   req.bytes < 0 || req.lnum >= vol->usable_leb_size)
+                       break;
+               if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM &&
+                   req.dtype != UBI_UNKNOWN)
+                       break;
+
+               err = get_exclusive(desc);
+               if (err < 0)
+                       break;
 
-               file->f_pos = 0;
+               err = ubi_start_leb_change(ubi, vol, &req);
+               if (req.bytes == 0)
+                       revoke_exclusive(desc, UBI_READWRITE);
                break;
        }
 
@@ -447,7 +497,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
                        break;
                }
 
-               if (desc->mode == UBI_READONLY) {
+               if (desc->mode == UBI_READONLY ||
+                   vol->vol_type == UBI_STATIC_VOLUME) {
                        err = -EROFS;
                        break;
                }
@@ -457,11 +508,6 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
                        break;
                }
 
-               if (vol->vol_type != UBI_DYNAMIC_VOLUME) {
-                       err = -EROFS;
-                       break;
-               }
-
                dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
                err = ubi_eba_unmap_leb(ubi, vol, lnum);
                if (err)