⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftl.patch

📁 linux交叉编译环境个软件和内核的补丁。
💻 PATCH
📖 第 1 页 / 共 4 页
字号:
+/*======================================================================++    reclaim_block() picks a full erase unit and a transfer unit and+    then calls copy_erase_unit() to copy one to the other.  Then, it+    schedules an erase on the expired block.++    What's a good way to decide which transfer unit and which erase+    unit to use?  Beats me.  My way is to always pick the transfer+    unit with the fewest erases, and usually pick the data unit with+    the most deleted blocks.  But with a small probability, pick the+    oldest data unit instead.  This means that we generally postpone+    the next reclaimation as long as possible, but shuffle static+    stuff around a bit for wear leveling.++======================================================================*/++static int reclaim_block(ftl_dev_t *dev)+{+    u_short i, eun, xfer;+    u_int best;+    int queued, ret;++    DEBUG("ftl: reclaiming space...\n");++    /* Pick the least erased transfer unit */+    best = 0xffffffff; xfer = 0xffff;+    do {+	queued = 0;+	for (i = 0; i < dev->header.NumTransferUnits; i++) {++	    if (dev->XferInfo[i].state == XFER_UNKNOWN) {+		erase_xfer(dev, i);+	    }+	    if (dev->XferInfo[i].state == XFER_ERASING) {+		queued = 1;+	    } else {+	        if (dev->XferInfo[i].state == XFER_ERASED) {+		    prepare_xfer(dev, i);+		}+	    }+	    if ((dev->XferInfo[i].state == XFER_PREPARED) &&+		(dev->XferInfo[i].EraseCount <= best)) {+		    best = dev->XferInfo[i].EraseCount;+		    xfer = i;+		}+	}+	if (xfer == 0xffff) {+	    if (queued) {+		DEBUG("ftl: waiting for transfer unit to be prepared...\n");+                DEBUG("ftl: Hupp...\n");+		/*sleep_on(&dev->erase_pending); */+	    } else {+		static int ne = 0;+		if (++ne < 5)+		    printk(KERN_NOTICE "ftl: reclaim failed: no suitable transfer units!\n");+		return -EIO;+	    }+	}+    } while (xfer == 0xffff);++    eun = 0;+    if ((jiffies % shuffle_freq) == 0) {+	DEBUG("ftl: recycling freshest block...\n");+	best = 0xffffffff;+	for (i = 0; i < dev->DataUnits; i++)+	    if (dev->EUNInfo[i].EraseCount <= best) {+		best = dev->EUNInfo[i].EraseCount;+		eun = i;+	    }+    } else {+	best = 0;+	for (i = 0; i < dev->DataUnits; i++)+	    if (dev->EUNInfo[i].Deleted >= best) {+		best = dev->EUNInfo[i].Deleted;+		eun = i;+	    }+	if (best == 0) {+	    static int ne = 0;+	    if (++ne < 5)+		printk(KERN_NOTICE "ftl: reclaim failed: no free blocks!\n");+	    return -EIO;+	}+    }++    ret = copy_erase_unit(dev, eun, xfer);+    if (!ret) {+	erase_xfer(dev, xfer);+    } else {+	printk(KERN_NOTICE "ftl: copy_erase_unit failed!\n");+    }+    return ret;+} /* reclaim_block */++/*======================================================================++    Find_free() searches for a free block.  If necessary, it updates+    the BAM cache for the erase unit containing the free block.  It+    returns the block index -- the erase unit is just the currently+    cached unit.  If there are no free blocks, it returns 0 -- this+    is never a valid data block because it contains the header.++======================================================================*/++#ifdef PSYCHO_DEBUG+static void dump_lists(ftl_dev_t *dev)+{+    int i;+    printk(KERN_DEBUG "ftl: Free total = %d\n", dev->FreeTotal);+    for (i = 0; i < dev->DataUnits; i++)+	printk(KERN_DEBUG+               "ftl:   unit %d: %d phys, %d free, %d deleted\n", i,+	       dev->EUNInfo[i].Offset >> dev->header.EraseUnitSize,+	       dev->EUNInfo[i].Free, dev->EUNInfo[i].Deleted);+}+#endif++static u_int find_free(ftl_dev_t *dev)+{+    u_short stop, eun;+    u_int blk;+    int ret;+    off_t offset;+    size_t count;++    /* Find an erase unit with some free space */+    stop = (dev->bam_index == 0xffff) ? 0 : dev->bam_index;+    eun = stop;+    do {+	if (dev->EUNInfo[eun].Free != 0) break;+	/* Wrap around at end of table */+	if (++eun == dev->DataUnits) eun = 0;+    } while (eun != stop);++    if (dev->EUNInfo[eun].Free == 0)+	return 0;++    /* Is this unit's BAM cached? */+    if (eun != dev->bam_index) {+	/* Invalidate cache */+	dev->bam_index = 0xffff;+	count = dev->BlocksPerUnit * sizeof(u_int);+	offset = dev->EUNInfo[eun].Offset + dev->header.BAMOffset;+	ret = (*dev->flash->ops->read)(dev->flash, (char *)dev->bam_cache,+                                       count, offset + dev->base_offset, 0);+	if (ret) {+            printk("Error reading flash mem.\n");+	    return 0;+	}+	dev->bam_index = eun;+    }++    /* Find a free block */+    for (blk = 0; blk < dev->BlocksPerUnit; blk++)+	if (BLOCK_FREE(dev->bam_cache[blk])) break;+    if (blk == dev->BlocksPerUnit) {+#ifdef PSYCHO_DEBUG+	static int ne = 0;+	if (++ne == 1)+	    dump_lists(dev);+#endif+	printk(KERN_NOTICE "ftl: bad free list!\n");+	return 0;+    }+    /*DEBUG("ftl: found free block at %d in %d\n", blk, eun);*/+    return blk;++} /* find_free */++/*======================================================================++    This gets a memory handle for the region corresponding to the+    minor device number.++======================================================================*/++static int ftl_open(struct inode *inode, struct file *file)+{+    int minor = MINOR(inode->i_rdev);+    ftl_dev_t *dev;++    DEBUG("ftl_open(minor=%d, dev_nr(minor)=0x%x)\n", minor, DEVICE_NR(minor));++    dev = dev_table[DEVICE_NR(minor)];++    if ( dev == NULL )+      return -ENODEV;++    if (dev->region.RegionSize == 0)+      return -ENODEV;++    while (dev->locked) {+      DEBUG("dev->locked, sleeping on ftl_wait_open\n");+	sleep_on(&ftl_wait_open);+    }+    if ((scan_header(dev) == 0) &&+        (build_maps(dev) == 0)) {+      dev->state = FTL_FORMATTED;+      ftl_reread_partitions(minor);+#ifdef FLASH_DEBUG+      printk(KERN_INFO "ftl: opening %d kb FTL partition\n",+             dev->header.FormattedSize >> 10);+#endif+    } else {+      printk(KERN_NOTICE "ftl: FTL partition is invalid.\n");+      return -ENODEV;+    }++    dev->open++;++    /*    MOD_INC_USE_COUNT; */+    return 0;+} /* ftl_open */++/*====================================================================*/++static int ftl_close(struct inode *inode, struct file *file)+{+    int minor = MINOR(inode->i_rdev);+    ftl_dev_t *dev;+    int i;+    struct super_block *sb;++    DEBUG("ftl: ftl_close(%d)\n", minor);++    /* Flush all writes */+    fsync_dev(inode->i_rdev);+    sb = get_super(inode->i_rdev);+    if (sb)+      invalidate_inodes(sb);+    invalidate_buffers(inode->i_rdev);++    dev = dev_table[DEVICE_NR(minor)];++    /* Wait for any pending erase operations to complete */+    for (i = 0; i < dev->header.NumTransferUnits; i++) {+      if (dev->XferInfo[i].state == XFER_ERASING) {+        printk("ftl: Hmmm... close before all erased...\n");+	/*    sleep_on(&dev->erase_pending); */+      }+      if (dev->XferInfo[i].state == XFER_ERASED)+        prepare_xfer(dev, i);+    }++    dev->open--;+    if (dev->open == 0) {+      DEBUG("ftl: Last close. deallocating stuff\n");+	if (dev->VirtualBlockMap) {+	    vfree(dev->VirtualBlockMap);+	    dev->VirtualBlockMap = NULL;+	}+	if (dev->VirtualPageMap) {+	    kfree(dev->VirtualPageMap);+	    dev->VirtualPageMap = NULL;+	}+	if (dev->EUNInfo) {+	    kfree(dev->EUNInfo);+	    dev->EUNInfo = NULL;+	}+	if (dev->XferInfo) {+	    kfree(dev->XferInfo);+	    dev->XferInfo = NULL;+	}+	if (dev->bam_cache) {+	    kfree(dev->bam_cache);+	    dev->bam_cache = NULL;+	}+    }++    /*    MOD_DEC_USE_COUNT; */+    return 0;+} /* ftl_close */++/*======================================================================++    Read a series of sectors from an FTL partition.++======================================================================*/++static int ftl_read(ftl_dev_t *dev, caddr_t buffer,+		    u_long sector, u_long nblocks)+{+    u_int log_addr, bsize;+    u_long i;+    int ret;+    off_t offset;+    size_t count;++    if (!(dev->state & FTL_FORMATTED)) {+	printk(KERN_NOTICE "ftl: bad partition\n");+	return -EIO;+    }+    bsize = dev->region.BlockSize;++    count = SECTOR_SIZE;+    for (i = 0; i < nblocks; i++) {+	if (((sector+i) * SECTOR_SIZE) >= dev->header.FormattedSize) {+	    printk(KERN_NOTICE "ftl: bad read offset\n");+	    return -EIO;+	}+	log_addr = dev->VirtualBlockMap[sector+i];+	if (log_addr == 0xffffffff)+	    memset(buffer, 0, SECTOR_SIZE);+	else {+	    offset = (dev->EUNInfo[log_addr / bsize].Offset + (log_addr % bsize));+	    ret = (*dev->flash->ops->read)(dev->flash, buffer,+                                           count, offset + dev->base_offset, 0);+	    if (ret) {+                printk("Error reading flash mem.\n");+		return -EIO;+	    }+	}+	buffer += SECTOR_SIZE;+    }+    return 0;+} /* ftl_read */++/*======================================================================++    Write a series of sectors to an FTL partition++======================================================================*/++static int set_bam_entry(ftl_dev_t *dev,+                         u_int log_addr, u_int virt_addr)+{+    u_int bsize, blk;+#ifdef PSYCHO_DEBUG+    u_int old_addr;+#endif+    u_short eun;+    int ret;+    off_t offset;+    size_t count;++    /*DEBUG("ftl: set_bam_entry(0x%p, 0x%x, 0x%x)\n", dev, log_addr, virt_addr);*/++    bsize = dev->region.BlockSize;+    eun = log_addr / bsize;+    blk = (log_addr % bsize) / SECTOR_SIZE;+    count = sizeof(u_int);+    offset = (dev->EUNInfo[eun].Offset + blk * sizeof(u_int) ++              dev->header.BAMOffset);++#ifdef PSYCHO_DEBUG+    ret = (*dev->flash->ops->read)(dev->flash, (char *)&old_addr,+                                   count, offset + dev->base_offset, 0);+    if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||+	((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||+	(!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {+	static int ne = 0;+	if (++ne < 5) {+	    printk(KERN_NOTICE "ftl: set_bam_entry() inconsistency!\n");+	    printk(KERN_NOTICE "ftl:   log_addr = 0x%x, old = 0x%x"+		   ", new = 0x%x\n", log_addr, old_addr, virt_addr);+	}+	return -1;+    }+#endif+    if (dev->bam_index == eun) {+#ifdef PSYCHO_DEBUG+	if (dev->bam_cache[blk] != old_addr) {+	    static int ne = 0;+	    if (++ne < 5) {+		printk(KERN_NOTICE "ftl: set_bam_entry() inconsistency!\n");+		printk(KERN_NOTICE "ftl:   log_addr = 0x%x, cache"+		       " = 0x%x, card = 0x%x\n",+		       dev->bam_cache[blk], old_addr, 0);+	    }+	    return -1;+	}+#endif+	dev->bam_cache[blk] = virt_addr;+    }++    ret = (*dev->flash->ops->write)(dev->flash, (char *)&virt_addr,+                                    count, offset + dev->base_offset, 0);+#ifdef PSYCHO_DEBUG+    if (ret) {+	printk(KERN_NOTICE "ftl: set_bam_entry() failed!\n");+	printk(KERN_NOTICE "ftl:   log_addr = 0x%x, old = 0x%x,"+	       " new = 0x%x\n", log_addr, old_addr, virt_addr);+        printk("Error writing flash mem.\n");+    }+#endif+    return ret;+} /* set_bam_entry */++static int ftl_write(ftl_dev_t *dev, caddr_t buffer,+		     u_long sector, u_long nblocks)+{+    u_int bsize, log_addr, virt_addr, old_addr, blk;+    u_long i;+    int ret;+    off_t offset;+    size_t count;++    /*DEBUG("ftl: ftl_write(0x%p, %ld, %ld)\n", dev, sector, nblocks);*/++    if (!(dev->state & FTL_FORMATTED)) {+	printk(KERN_NOTICE "ftl: bad partition\n");+	return -EIO;+    }+    /* See if we need to reclaim space, before we start */+    while (dev->FreeTotal < nblocks) {+	ret = reclaim_block(dev);+	if (ret)+	    return ret;+    }++    bsize = dev->region.BlockSize;+    count = SECTOR_SIZE;+    virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;+    for (i = 0; i < nblocks; i++) {+	if (virt_addr >= dev->header.FormattedSize) {+	    printk(KERN_NOTICE "ftl: bad write offset\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -