erase.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:12k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * JFFS2 -- Journalling Flash File System, Version 2.
  3.  *
  4.  * Copyright (C) 2001 Red Hat, Inc.
  5.  *
  6.  * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
  7.  *
  8.  * The original JFFS, from which the design for JFFS2 was derived,
  9.  * was designed and implemented by Axis Communications AB.
  10.  *
  11.  * The contents of this file are subject to the Red Hat eCos Public
  12.  * License Version 1.1 (the "Licence"); you may not use this file
  13.  * except in compliance with the Licence.  You may obtain a copy of
  14.  * the Licence at http://www.redhat.com/
  15.  *
  16.  * Software distributed under the Licence is distributed on an "AS IS"
  17.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
  18.  * See the Licence for the specific language governing rights and
  19.  * limitations under the Licence.
  20.  *
  21.  * The Original Code is JFFS2 - Journalling Flash File System, version 2
  22.  *
  23.  * Alternatively, the contents of this file may be used under the
  24.  * terms of the GNU General Public License version 2 (the "GPL"), in
  25.  * which case the provisions of the GPL are applicable instead of the
  26.  * above.  If you wish to allow the use of your version of this file
  27.  * only under the terms of the GPL and not to allow others to use your
  28.  * version of this file under the RHEPL, indicate your decision by
  29.  * deleting the provisions above and replace them with the notice and
  30.  * other provisions required by the GPL.  If you do not delete the
  31.  * provisions above, a recipient may use your version of this file
  32.  * under either the RHEPL or the GPL.
  33.  *
  34.  * $Id: erase.c,v 1.24 2001/12/06 16:38:38 dwmw2 Exp $
  35.  *
  36.  */
  37. #include <linux/kernel.h>
  38. #include <linux/slab.h>
  39. #include <linux/mtd/mtd.h>
  40. #include <linux/jffs2.h>
  41. #include <linux/interrupt.h>
  42. #include "nodelist.h"
  43. #include "crc32.h"
  44. struct erase_priv_struct {
  45. struct jffs2_eraseblock *jeb;
  46. struct jffs2_sb_info *c;
  47. };
  48.       
  49. static void jffs2_erase_callback(struct erase_info *);
  50. static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
  51. void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
  52. {
  53. struct erase_info *instr;
  54. int ret;
  55. instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
  56. if (!instr) {
  57. printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for latern");
  58. spin_lock_bh(&c->erase_completion_lock);
  59. list_del(&jeb->list);
  60. list_add(&jeb->list, &c->erase_pending_list);
  61. c->erasing_size -= c->sector_size;
  62. spin_unlock_bh(&c->erase_completion_lock);
  63. return;
  64. }
  65. memset(instr, 0, sizeof(*instr));
  66. instr->mtd = c->mtd;
  67. instr->addr = jeb->offset;
  68. instr->len = c->sector_size;
  69. instr->callback = jffs2_erase_callback;
  70. instr->priv = (unsigned long)(&instr[1]);
  71. ((struct erase_priv_struct *)instr->priv)->jeb = jeb;
  72. ((struct erase_priv_struct *)instr->priv)->c = c;
  73. ret = c->mtd->erase(c->mtd, instr);
  74. if (!ret) {
  75. return;
  76. }
  77. if (ret == -ENOMEM || ret == -EAGAIN) {
  78. /* Erase failed immediately. Refile it on the list */
  79. D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_listn", jeb->offset, ret));
  80. spin_lock_bh(&c->erase_completion_lock);
  81. list_del(&jeb->list);
  82. list_add(&jeb->list, &c->erase_pending_list);
  83. c->erasing_size -= c->sector_size;
  84. spin_unlock_bh(&c->erase_completion_lock);
  85. kfree(instr);
  86. return;
  87. }
  88. if (ret == -EROFS) 
  89. printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?n", jeb->offset);
  90. else
  91. printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %dn", jeb->offset, ret);
  92. spin_lock_bh(&c->erase_completion_lock);
  93. list_del(&jeb->list);
  94. list_add(&jeb->list, &c->bad_list);
  95. c->nr_erasing_blocks--;
  96. c->bad_size += c->sector_size;
  97. c->erasing_size -= c->sector_size;
  98. spin_unlock_bh(&c->erase_completion_lock);
  99. wake_up(&c->erase_wait);
  100. kfree(instr);
  101. }
  102. void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
  103. {
  104. struct jffs2_eraseblock *jeb;
  105. spin_lock_bh(&c->erase_completion_lock);
  106. while (!list_empty(&c->erase_pending_list)) {
  107. jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list);
  108. D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08xn", jeb->offset));
  109. list_del(&jeb->list);
  110. c->erasing_size += c->sector_size;
  111. c->free_size -= jeb->free_size;
  112. c->used_size -= jeb->used_size;
  113. c->dirty_size -= jeb->dirty_size;
  114. jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
  115. jffs2_free_all_node_refs(c, jeb);
  116. list_add(&jeb->list, &c->erasing_list);
  117. spin_unlock_bh(&c->erase_completion_lock);
  118. jffs2_erase_block(c, jeb);
  119. /* Be nice */
  120. if (current->need_resched)
  121. schedule();
  122. spin_lock_bh(&c->erase_completion_lock);
  123. }
  124. spin_unlock_bh(&c->erase_completion_lock);
  125. D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completedn"));
  126. }
  127. static void jffs2_erase_callback(struct erase_info *instr)
  128. {
  129. struct erase_priv_struct *priv = (void *)instr->priv;
  130. if(instr->state != MTD_ERASE_DONE) {
  131. printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.n", instr->addr, instr->state);
  132. spin_lock(&priv->c->erase_completion_lock);
  133. priv->c->erasing_size -= priv->c->sector_size;
  134. priv->c->bad_size += priv->c->sector_size;
  135. list_del(&priv->jeb->list);
  136. list_add(&priv->jeb->list, &priv->c->bad_list);
  137. priv->c->nr_erasing_blocks--;
  138. spin_unlock(&priv->c->erase_completion_lock);
  139. wake_up(&priv->c->erase_wait);
  140. } else {
  141. D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08xn", instr->addr));
  142. spin_lock(&priv->c->erase_completion_lock);
  143. list_del(&priv->jeb->list);
  144. list_add_tail(&priv->jeb->list, &priv->c->erase_complete_list);
  145. spin_unlock(&priv->c->erase_completion_lock);
  146. }
  147. /* Make sure someone picks up the block off the erase_complete list */
  148. OFNI_BS_2SFFJ(priv->c)->s_dirt = 1;
  149. kfree(instr);
  150. }
  151. /* Hmmm. Maybe we should accept the extra space it takes and make
  152.    this a standard doubly-linked list? */
  153. static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
  154. struct jffs2_raw_node_ref *ref, struct jffs2_eraseblock *jeb)
  155. {
  156. struct jffs2_inode_cache *ic = NULL;
  157. struct jffs2_raw_node_ref **prev;
  158. prev = &ref->next_in_ino;
  159. /* Walk the inode's list once, removing any nodes from this eraseblock */
  160. while (1) {
  161. if (!(*prev)->next_in_ino) {
  162. /* We're looking at the jffs2_inode_cache, which is 
  163.    at the end of the linked list. Stash it and continue
  164.    from the beginning of the list */
  165. ic = (struct jffs2_inode_cache *)(*prev);
  166. prev = &ic->nodes;
  167. continue;
  168. if (((*prev)->flash_offset & ~(c->sector_size -1)) == jeb->offset) {
  169. /* It's in the block we're erasing */
  170. struct jffs2_raw_node_ref *this;
  171. this = *prev;
  172. *prev = this->next_in_ino;
  173. this->next_in_ino = NULL;
  174. if (this == ref)
  175. break;
  176. continue;
  177. }
  178. /* Not to be deleted. Skip */
  179. prev = &((*prev)->next_in_ino);
  180. }
  181. /* PARANOIA */
  182. if (!ic) {
  183. printk(KERN_WARNING "inode_cache not found in remove_node_refs()!!n");
  184. return;
  185. }
  186. D1(printk(KERN_DEBUG "Removed nodes in range 0x%08x-0x%08x from ino #%un",
  187.   jeb->offset, jeb->offset + c->sector_size, ic->ino));
  188. D2({
  189. int i=0;
  190. struct jffs2_raw_node_ref *this;
  191. printk(KERN_DEBUG "After remove_node_refs_from_ino_list: n" KERN_DEBUG);
  192. this = ic->nodes;
  193.    
  194. while(this) {
  195. printk( "0x%08x(%d)->", this->flash_offset & ~3, this->flash_offset &3);
  196. if (++i == 5) {
  197. printk("n" KERN_DEBUG);
  198. i=0;
  199. }
  200. this = this->next_in_ino;
  201. }
  202. printk("n");
  203. });
  204. if (ic->nodes == (void *)ic) {
  205. D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeingn", ic->ino));
  206. jffs2_del_ino_cache(c, ic);
  207. jffs2_free_inode_cache(ic);
  208. }
  209. }
  210. static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
  211. {
  212. struct jffs2_raw_node_ref *ref;
  213. D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08xn", jeb->offset));
  214. while(jeb->first_node) {
  215. ref = jeb->first_node;
  216. jeb->first_node = ref->next_phys;
  217. /* Remove from the inode-list */
  218. if (ref->next_in_ino)
  219. jffs2_remove_node_refs_from_ino_list(c, ref, jeb);
  220. /* else it was a non-inode node or already removed, so don't bother */
  221. jffs2_free_raw_node_ref(ref);
  222. }
  223. jeb->last_node = NULL;
  224. }
  225. void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
  226. {
  227. OFNI_BS_2SFFJ(c)->s_dirt = 1;
  228. }
  229. void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
  230. {
  231. static struct jffs2_unknown_node marker = {JFFS2_MAGIC_BITMASK, JFFS2_NODETYPE_CLEANMARKER, sizeof(struct jffs2_unknown_node)};
  232. struct jffs2_eraseblock *jeb;
  233. struct jffs2_raw_node_ref *marker_ref;
  234. unsigned char *ebuf;
  235. ssize_t retlen;
  236. int ret;
  237. marker.hdr_crc = crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4);
  238. spin_lock_bh(&c->erase_completion_lock);
  239. while (!list_empty(&c->erase_complete_list)) {
  240. jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
  241. list_del(&jeb->list);
  242. spin_unlock_bh(&c->erase_completion_lock);
  243. marker_ref = jffs2_alloc_raw_node_ref();
  244. if (!marker_ref) {
  245. printk(KERN_WARNING "Failed to allocate raw node ref for clean markern");
  246. /* Come back later */
  247. jffs2_erase_pending_trigger(c);
  248. return;
  249. }
  250. ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  251. if (!ebuf) {
  252. printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Assuming it workedn", jeb->offset);
  253. } else {
  254. __u32 ofs = jeb->offset;
  255. D1(printk(KERN_DEBUG "Verifying erase at 0x%08xn", jeb->offset));
  256. while(ofs < jeb->offset + c->sector_size) {
  257. __u32 readlen = min((__u32)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
  258. int i;
  259. ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf);
  260. if (ret < 0) {
  261. printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_listn", ofs, ret);
  262. goto bad;
  263. }
  264. if (retlen != readlen) {
  265. printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %dn", ofs, readlen, retlen);
  266. goto bad;
  267. }
  268. for (i=0; i<readlen; i += sizeof(unsigned long)) {
  269. /* It's OK. We know it's properly aligned */
  270. unsigned long datum = *(unsigned long *)(&ebuf[i]);
  271. if (datum + 1) {
  272. printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08xn", datum, ofs + i);
  273. bad: 
  274. jffs2_free_raw_node_ref(marker_ref);
  275. kfree(ebuf);
  276. bad2:
  277. spin_lock_bh(&c->erase_completion_lock);
  278. c->erasing_size -= c->sector_size;
  279. c->bad_size += c->sector_size;
  280. list_add_tail(&jeb->list, &c->bad_list);
  281. c->nr_erasing_blocks--;
  282. spin_unlock_bh(&c->erase_completion_lock);
  283. wake_up(&c->erase_wait);
  284. return;
  285. }
  286. }
  287. ofs += readlen;
  288. }
  289. kfree(ebuf);
  290. }
  291. /* Write the erase complete marker */
  292. D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08xn", jeb->offset));
  293. ret = c->mtd->write(c->mtd, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
  294. if (ret) {
  295. printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %dn",
  296.        jeb->offset, ret);
  297. goto bad2;
  298. }
  299. if (retlen != sizeof(marker)) {
  300. printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %dn",
  301.        jeb->offset, sizeof(marker), retlen);
  302. goto bad2;
  303. }
  304. marker_ref->next_in_ino = NULL;
  305. marker_ref->next_phys = NULL;
  306. marker_ref->flash_offset = jeb->offset;
  307. marker_ref->totlen = PAD(sizeof(marker));
  308. jeb->first_node = jeb->last_node = marker_ref;
  309. jeb->free_size = c->sector_size - marker_ref->totlen;
  310. jeb->used_size = marker_ref->totlen;
  311. jeb->dirty_size = 0;
  312. spin_lock_bh(&c->erase_completion_lock);
  313. c->erasing_size -= c->sector_size;
  314. c->free_size += jeb->free_size;
  315. c->used_size += jeb->used_size;
  316. ACCT_SANITY_CHECK(c,jeb);
  317. ACCT_PARANOIA_CHECK(jeb);
  318. list_add_tail(&jeb->list, &c->free_list);
  319. c->nr_erasing_blocks--;
  320. c->nr_free_blocks++;
  321. wake_up(&c->erase_wait);
  322. }
  323. spin_unlock_bh(&c->erase_completion_lock);
  324. }