diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2010-10-31 17:54:14 +0200 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2011-02-06 19:19:23 +0200 |
commit | 6c1e875ca6f3a47b40dce715bd07fdfdb8388d55 (patch) | |
tree | b30ab51df8df7c4ed9ef3adb68b234064816497f | |
parent | 7950d023c562823345892aac2e7c6a49f8de9ad1 (diff) |
UBI: add slab cache for ubi_scan_leb objects
During scanning UBI allocates one struct ubi_scan_leb object for each PEB,
so it can end up allocating thousands of them. Use slab cache to reduce
memory consumption for these 48-byte objects, because currently used
'kmalloc()' ends up allocating 64 bytes per object, instead of 48.
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
-rw-r--r-- | drivers/mtd/ubi/build.c | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/scan.c | 32 | ||||
-rw-r--r-- | drivers/mtd/ubi/scan.h | 2 |
3 files changed, 25 insertions, 11 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index ef296350aa8f..ec0ad19c691a 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -923,6 +923,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) spin_lock_init(&ubi->volumes_lock); ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num); + dbg_msg("sizeof(struct ubi_scan_leb) %zu", sizeof(struct ubi_scan_leb)); + dbg_msg("sizeof(struct ubi_wl_entry) %zu", sizeof(struct ubi_wl_entry)); err = io_init(ubi); if (err) diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 79ca304fc4db..0028bf283930 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -115,7 +115,7 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, int to_head, } else BUG(); - seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); + seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL); if (!seb) return -ENOMEM; @@ -144,7 +144,7 @@ static int add_corrupted(struct ubi_scan_info *si, int pnum, int ec) dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec); - seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); + seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL); if (!seb) return -ENOMEM; @@ -553,7 +553,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, if (err) return err; - seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); + seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL); if (!seb) return -ENOMEM; @@ -1152,9 +1152,15 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) si->volumes = RB_ROOT; err = -ENOMEM; + si->scan_leb_slab = kmem_cache_create("ubi_scan_leb_slab", + sizeof(struct ubi_scan_leb), + 0, 0, NULL); + if (!si->scan_leb_slab) + goto out_si; + ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); if (!ech) - goto out_si; + goto out_slab; vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); if (!vidh) @@ -1215,6 +1221,8 @@ out_vidh: ubi_free_vid_hdr(ubi, vidh); out_ech: kfree(ech); +out_slab: + kmem_cache_destroy(si->scan_leb_slab); out_si: ubi_scan_destroy_si(si); return ERR_PTR(err); @@ -1223,11 +1231,12 @@ out_si: /** * destroy_sv - free the scanning volume information * @sv: scanning volume information + * @si: scanning information * * This function destroys the volume RB-tree (@sv->root) and the scanning * volume information. */ -static void destroy_sv(struct ubi_scan_volume *sv) +static void destroy_sv(struct ubi_scan_info *si, struct ubi_scan_volume *sv) { struct ubi_scan_leb *seb; struct rb_node *this = sv->root.rb_node; @@ -1247,7 +1256,7 @@ static void destroy_sv(struct ubi_scan_volume *sv) this->rb_right = NULL; } - kfree(seb); + kmem_cache_free(si->scan_leb_slab, seb); } } kfree(sv); @@ -1265,19 +1274,19 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si) list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) { list_del(&seb->u.list); - kfree(seb); + kmem_cache_free(si->scan_leb_slab, seb); } list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) { list_del(&seb->u.list); - kfree(seb); + kmem_cache_free(si->scan_leb_slab, seb); } list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) { list_del(&seb->u.list); - kfree(seb); + kmem_cache_free(si->scan_leb_slab, seb); } list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) { list_del(&seb->u.list); - kfree(seb); + kmem_cache_free(si->scan_leb_slab, seb); } /* Destroy the volume RB-tree */ @@ -1298,10 +1307,11 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si) rb->rb_right = NULL; } - destroy_sv(sv); + destroy_sv(si, sv); } } + kmem_cache_destroy(si->scan_leb_slab); kfree(si); } diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h index a3264f0bef2b..d48aef15ab5d 100644 --- a/drivers/mtd/ubi/scan.h +++ b/drivers/mtd/ubi/scan.h @@ -109,6 +109,7 @@ struct ubi_scan_volume { * @mean_ec: mean erase counter value * @ec_sum: a temporary variable used when calculating @mean_ec * @ec_count: a temporary variable used when calculating @mean_ec + * @scan_leb_slab: slab cache for &struct ubi_scan_leb objects * * This data structure contains the result of scanning and may be used by other * UBI sub-systems to build final UBI data structures, further error-recovery @@ -134,6 +135,7 @@ struct ubi_scan_info { int mean_ec; uint64_t ec_sum; int ec_count; + struct kmem_cache *scan_leb_slab; }; struct ubi_device; |