UBI: allocate memory with GFP_NOFS
Use GFP_NOFS flag when allocating memory on I/O path, because otherwise
we may deadlock the filesystem which works on top of us. We observed
the deadlocks with UBIFS. Example:
VFS->FS lock a lock->UBI->kmalloc()->VFS writeback->FS locks the same
lock again.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 7c5e29e..8919310 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -157,7 +157,7 @@
{
struct ltree_entry *le, *le1, *le_free;
- le = kmem_cache_alloc(ltree_slab, GFP_KERNEL);
+ le = kmem_cache_alloc(ltree_slab, GFP_NOFS);
if (!le)
return ERR_PTR(-ENOMEM);
@@ -397,7 +397,7 @@
retry:
if (check) {
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) {
err = -ENOMEM;
goto out_unlock;
@@ -497,7 +497,7 @@
struct ubi_vid_hdr *vid_hdr;
unsigned char *new_buf;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) {
return -ENOMEM;
}
@@ -627,7 +627,7 @@
* The logical eraseblock is not mapped. We have to get a free physical
* eraseblock and write the volume identifier header there first.
*/
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) {
leb_write_unlock(ubi, vol_id, lnum);
return -ENOMEM;
@@ -738,7 +738,7 @@
else
ubi_assert(len % ubi->min_io_size == 0);
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
@@ -844,7 +844,7 @@
if (ubi->ro_mode)
return -EROFS;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 9284763..ba5bc4a 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -1099,7 +1099,7 @@
uint32_t crc, hdr_crc;
struct ubi_ec_hdr *ec_hdr;
- ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
@@ -1179,7 +1179,7 @@
struct ubi_vid_hdr *vid_hdr;
void *p;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 18c347b..1c1401d 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -323,7 +323,7 @@
} else {
pnum = seb->pnum;
- vh = ubi_zalloc_vid_hdr(ubi);
+ vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vh)
return -ENOMEM;
@@ -948,7 +948,7 @@
if (!ech)
goto out_si;
- vidh = ubi_zalloc_vid_hdr(ubi);
+ vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh)
goto out_ech;
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 5959f91..3296631 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -439,16 +439,18 @@
/**
* ubi_zalloc_vid_hdr - allocate a volume identifier header object.
* @ubi: UBI device description object
+ * @gfp_flags: GFP flags to allocate with
*
* This function returns a pointer to the newly allocated and zero-filled
* volume identifier header object in case of success and %NULL in case of
* failure.
*/
-static inline struct ubi_vid_hdr *ubi_zalloc_vid_hdr(const struct ubi_device *ubi)
+static inline struct ubi_vid_hdr *
+ubi_zalloc_vid_hdr(const struct ubi_device *ubi, gfp_t gfp_flags)
{
void *vid_hdr;
- vid_hdr = kzalloc(ubi->vid_hdr_alsize, GFP_KERNEL);
+ vid_hdr = kzalloc(ubi->vid_hdr_alsize, gfp_flags);
if (!vid_hdr)
return NULL;
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index bc5df50..b0a1e84 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -264,7 +264,7 @@
ubi_msg("create volume table (copy #%d)", copy + 1);
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vid_hdr)
return -ENOMEM;
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 12b25e5..248ff9e 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -508,7 +508,7 @@
ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
dtype == UBI_UNKNOWN);
- pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_KERNEL);
+ pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS);
if (!pe)
return -ENOMEM;
@@ -645,7 +645,7 @@
if (err > 0)
return -EINVAL;
- ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
@@ -768,7 +768,7 @@
dbg_wl("schedule erasure of PEB %d, EC %d, torture %d",
e->pnum, e->ec, torture);
- wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL);
+ wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
if (!wl_wrk)
return -ENOMEM;
@@ -802,7 +802,7 @@
if (cancel)
return 0;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
@@ -1028,7 +1028,7 @@
ubi->wl_scheduled = 1;
spin_unlock(&ubi->wl_lock);
- wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL);
+ wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
if (!wrk) {
err = -ENOMEM;
goto out_cancel;
@@ -1631,7 +1631,7 @@
long long read_ec;
struct ubi_ec_hdr *ec_hdr;
- ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;