static void mtdblock_release(struct mtd_blktrans_dev *mbd) { struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); pr_debug("mtdblock_release\n"); mutex_lock(&mtdblks_lock); mutex_lock(&mtdblk->cache_mutex); write_cached_data(mtdblk); mutex_unlock(&mtdblk->cache_mutex); if (!--mtdblk->count) { /* * It was the last usage. Free the cache, but only sync if * opened for writing. */ if (mbd->file_mode & FMODE_WRITE) mtd_sync(mbd->mtd); vfree(mtdblk->cache_data); } mutex_unlock(&mtdblks_lock); pr_debug("ok\n"); }
static int mtdblock_release(struct mtd_blktrans_dev *mbd) { struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); mutex_lock(&mtdblks_lock); mutex_lock(&mtdblk->cache_mutex); write_cached_data(mtdblk); mutex_unlock(&mtdblk->cache_mutex); if (!--mtdblk->count) { /* It was the last usage. Free the cache */ if (mbd->mtd->sync) mbd->mtd->sync(mbd->mtd); vfree(mtdblk->cache_data); } mutex_unlock(&mtdblks_lock); DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); return 0; }
static int mtdblock_release(struct mtd_blktrans_dev *mbd) { int dev = mbd->devnum; struct mtdblk_dev *mtdblk = mtdblks[dev]; DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); mutex_lock(&mtdblks_lock); mutex_lock(&mtdblk->cache_mutex); write_cached_data(mtdblk); mutex_unlock(&mtdblk->cache_mutex); if (!--mtdblk->count) { /* It was the last usage. Free the device */ mtdblks[dev] = NULL; if (mtdblk->mtd->sync) mtdblk->mtd->sync(mtdblk->mtd); vfree(mtdblk->cache_data); kfree(mtdblk); } mutex_unlock(&mtdblks_lock); DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); return 0; }
static int mtdblock_flush(struct mtd_blktrans_dev *dev) { struct mtdblk_dev *mtdblk = container_of(dev, struct mtdblk_dev, mbd); mutex_lock(&mtdblk->cache_mutex); write_cached_data(mtdblk); mutex_unlock(&mtdblk->cache_mutex); mtd_sync(dev->mtd); return 0; }
static int mtdblock_flush(struct mtd_blktrans_dev *dev) { struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; down(&mtdblk->cache_sem); write_cached_data(mtdblk); up(&mtdblk->cache_sem); if (mtdblk->mtd->sync) mtdblk->mtd->sync(mtdblk->mtd); return 0; }
static int mtdblock_flush(struct mtd_blktrans_dev *dev) { struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; mutex_lock(&mtdblk->cache_mutex); write_cached_data(mtdblk); mutex_unlock(&mtdblk->cache_mutex); if (mtdblk->mtd->sync) mtdblk->mtd->sync(mtdblk->mtd); return 0; }
void mtdblock_flush_all(void) { int i; for (i = 0; i < MAX_MTD_DEVICES; i++) { struct mtdblk_dev *mtdblk = mtdblks[i]; if (mtdblk) { down(&mtdblk->cache_sem); write_cached_data(mtdblk); up(&mtdblk->cache_sem); if (mtdblk->mtd->sync) mtdblk->mtd->sync(mtdblk->mtd); } } }
static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, int len, const char *buf) { struct mtd_info *mtd = mtdblk->mbd.mtd; unsigned int sect_size = mtdblk->cache_size; size_t retlen; int ret; DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", mtd->name, pos, len); if (!sect_size) return mtd->write(mtd, pos, len, &retlen, buf); while (len > 0) { unsigned long sect_start = (pos/sect_size)*sect_size; unsigned int offset = pos - sect_start; unsigned int size = sect_size - offset; if( size > len ) size = len; if (size == sect_size) { /* * We are covering a whole sector. Thus there is no * need to bother with the cache while it may still be * useful for other partial writes. */ ret = erase_write (mtd, pos, size, buf); if (ret) return ret; } else { /* Partial sector: need to use the cache */ if (mtdblk->cache_state == STATE_DIRTY && mtdblk->cache_offset != sect_start) { ret = write_cached_data(mtdblk); if (ret) return ret; } if (mtdblk->cache_state == STATE_EMPTY || mtdblk->cache_offset != sect_start) { /* fill the cache with the current sector */ mtdblk->cache_state = STATE_EMPTY; ret = mtd->read(mtd, sect_start, sect_size, &retlen, mtdblk->cache_data); if (ret) return ret; if (retlen != sect_size) return -EIO; mtdblk->cache_offset = sect_start; mtdblk->cache_size = sect_size; mtdblk->cache_state = STATE_CLEAN; } /* write data to our local cache */ memcpy (mtdblk->cache_data + offset, buf, size); mtdblk->cache_state = STATE_DIRTY; } buf += size; pos += size; len -= size; } return 0; }
static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, int len, const char *buf) { struct mtd_info *mtd = mtdblk->mtd; unsigned int sect_size = mtdblk->cache_size; size_t retlen; int ret; DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", mtd->name, pos, len); if (!sect_size) return mtd->write(mtd, pos, len, &retlen, buf); while (len > 0) { unsigned long sect_start = (pos/sect_size)*sect_size; unsigned int offset = pos - sect_start; unsigned int size = sect_size - offset; if( size > len ) size = len; if (size == sect_size) { /* * We are covering a whole sector. Thus there is no * need to bother with the cache while it may still be * useful for other partial writes. */ ret = erase_write (mtd, pos, size, buf); if (ret) return ret; } else if (!sect_start && (offset >= 0x1f000)) { /* * Linux Block device mechanism is forcing the writes to MTD Block device * to be aligned at 4096. * Due to this whenever the first RG_CONF section (at offset 0x1f000) * needs to be written to Flash, it results in RG_FACTORY (at offset 0) * also being written to flash. * This change is to avoid writes to block consisting RG_FACTORY */ #if 0 printk("do_cached_write: %d+%d, %d/%d, not writing RG_FACTORY\n", sect_start, offset, pos, len); #endif } else { /* Partial sector: need to use the cache */ if (mtdblk->cache_state == STATE_DIRTY && mtdblk->cache_offset != sect_start) { ret = write_cached_data(mtdblk); if (ret) return ret; } if (mtdblk->cache_state == STATE_EMPTY || mtdblk->cache_offset != sect_start) { /* fill the cache with the current sector */ mtdblk->cache_state = STATE_EMPTY; ret = mtd->read(mtd, sect_start, sect_size, &retlen, mtdblk->cache_data); if (ret) return ret; if (retlen != sect_size) return -EIO; mtdblk->cache_offset = sect_start; mtdblk->cache_state = STATE_CLEAN; } /* write data to our local cache */ memcpy (mtdblk->cache_data + offset, buf, size); mtdblk->cache_state = STATE_DIRTY; } buf += size; pos += size; len -= size; } return 0; }