aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi
diff options
context:
space:
mode:
authorRichard Weinberger <richard@nod.at>2014-10-26 19:46:11 -0400
committerArtem Bityutskiy <artem.bityutskiy@linux.intel.com>2014-11-07 08:14:09 -0500
commitf38aed975c0c3645bbdfc5ebe35726e64caaf588 (patch)
treeab243ab0207667885ec2fe5b431b8b9da2f39c4c /drivers/mtd/ubi
parentaa5ad3b6eb8feb2399a5d26c8fb0060561bb9534 (diff)
UBI: Fix invalid vfree()
The logic of vfree()'ing vol->upd_buf is tied to vol->updating. In ubi_start_update() vol->updating is set long before vmalloc()'ing vol->upd_buf. If we encounter a write failure in ubi_start_update() before vmalloc() the UBI device release function will try to vfree() vol->upd_buf because vol->updating is set. Fix this by allocating vol->upd_buf directly after setting vol->updating. Fixes: [ 31.559338] UBI warning: vol_cdev_release: update of volume 2 not finished, volume is damaged [ 31.559340] ------------[ cut here ]------------ [ 31.559343] WARNING: CPU: 1 PID: 2747 at mm/vmalloc.c:1446 __vunmap+0xe3/0x110() [ 31.559344] Trying to vfree() nonexistent vm area (ffffc90001f2b000) [ 31.559345] Modules linked in: [ 31.565620] 0000000000000bba ffff88002a0cbdb0 ffffffff818f0497 ffff88003b9ba148 [ 31.566347] ffff88002a0cbde0 ffffffff8156f515 ffff88003b9ba148 0000000000000bba [ 31.567073] 0000000000000000 0000000000000000 ffff88002a0cbe88 ffffffff8156c10a [ 31.567793] Call Trace: [ 31.568034] [<ffffffff818f0497>] dump_stack+0x4e/0x7a [ 31.568510] [<ffffffff8156f515>] ubi_io_write_vid_hdr+0x155/0x160 [ 31.569084] [<ffffffff8156c10a>] ubi_eba_write_leb+0x23a/0x870 [ 31.569628] [<ffffffff81569b36>] vol_cdev_write+0x226/0x380 [ 31.570155] [<ffffffff81179265>] vfs_write+0xb5/0x1f0 [ 31.570627] [<ffffffff81179f8a>] SyS_pwrite64+0x6a/0xa0 [ 31.571123] [<ffffffff818fde12>] system_call_fastpath+0x16/0x1b Cc: <stable@vger.kernel.org> Signed-off-by: Richard Weinberger <richard@nod.at> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Diffstat (limited to 'drivers/mtd/ubi')
-rw-r--r--drivers/mtd/ubi/upd.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index ec2c2dc1c1ca..2a1b6e037e1a 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -133,6 +133,10 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
133 ubi_assert(!vol->updating && !vol->changing_leb); 133 ubi_assert(!vol->updating && !vol->changing_leb);
134 vol->updating = 1; 134 vol->updating = 1;
135 135
136 vol->upd_buf = vmalloc(ubi->leb_size);
137 if (!vol->upd_buf)
138 return -ENOMEM;
139
136 err = set_update_marker(ubi, vol); 140 err = set_update_marker(ubi, vol);
137 if (err) 141 if (err)
138 return err; 142 return err;
@@ -152,14 +156,12 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
152 err = clear_update_marker(ubi, vol, 0); 156 err = clear_update_marker(ubi, vol, 0);
153 if (err) 157 if (err)
154 return err; 158 return err;
159
160 vfree(vol->upd_buf);
155 vol->updating = 0; 161 vol->updating = 0;
156 return 0; 162 return 0;
157 } 163 }
158 164
159 vol->upd_buf = vmalloc(ubi->leb_size);
160 if (!vol->upd_buf)
161 return -ENOMEM;
162
163 vol->upd_ebs = div_u64(bytes + vol->usable_leb_size - 1, 165 vol->upd_ebs = div_u64(bytes + vol->usable_leb_size - 1,
164 vol->usable_leb_size); 166 vol->usable_leb_size);
165 vol->upd_bytes = bytes; 167 vol->upd_bytes = bytes;