📄 intrep.c
字号:
/* * JFFS -- Journaling Flash File System, Linux implementation. * * Copyright (C) 1999, 2000 Axis Communications, Inc. * * Created by Finn Hakansson <finn@axis.com>. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * $Id: intrep.c,v 1.104 2002/03/05 14:07:39 dwmw2 Exp $ * * Ported to Linux 2.3.x and MTD: * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB * *//* This file contains the code for the internal structure of the Journaling Flash File System, JFFS. *//* * Todo list: * * memcpy_to_flash() and memcpy_from_flash() functions. * * Implementation of hard links. * * Organize the source code in a better way. Against the VFS we could * have jffs_ext.c, and against the block device jffs_int.c. * A better file-internal organization too. * * A better checksum algorithm. * * Consider endianness stuff. ntohl() etc. * * Are we handling the atime, mtime, ctime members of the inode right? * * Remove some duplicated code. Take a look at jffs_write_node() and * jffs_rewrite_data() for instance. * * Implement more meaning of the nlink member in various data structures. * nlink could be used in conjunction with hard links for instance. * * Better memory management. Allocate data structures in larger chunks * if possible. * * If too much meta data is stored, a garbage collect should be issued. * We have experienced problems with too much meta data with for instance * log files. * * Improve the calls to jffs_ioctl(). We would like to retrieve more * information to be able to debug (or to supervise) JFFS during run-time. * */#define __NO_VERSION__#include <linux/config.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/jffs.h>#include <linux/fs.h>#include <linux/stat.h>#include <linux/pagemap.h>#include <linux/locks.h>#include <asm/semaphore.h>#include <asm/byteorder.h>#include <linux/version.h>#include <linux/smp_lock.h>#include <linux/sched.h>#include <linux/ctype.h>#include "intrep.h"#include "jffs_fm.h"long no_jffs_node = 0;long no_jffs_file = 0;#if defined(JFFS_MEMORY_DEBUG) && JFFS_MEMORY_DEBUGlong no_jffs_control = 0;long no_jffs_raw_inode = 0;long no_jffs_node_ref = 0;long no_jffs_fm = 0;long no_jffs_fmcontrol = 0;long no_hash = 0;long no_name = 0;#endifstatic int jffs_scan_flash(struct jffs_control *c);static int jffs_update_file(struct jffs_file *f, struct jffs_node *node);#if CONFIG_JFFS_FS_VERBOSE > 0static __u8flash_read_u8(struct mtd_info *mtd, loff_t from){ size_t retlen; __u8 ret; int res; res = MTD_READ(mtd, from, 1, &retlen, &ret); if (retlen != 1) { printk("Didn't read a byte in flash_read_u8(). Returned %d\n", res); return 0; } return ret;}static voidjffs_hexdump(struct mtd_info *mtd, loff_t pos, int size){ char line[16]; int j = 0; while (size > 0) { int i; printk("%ld:", (long) pos); for (j = 0; j < 16; j++) { line[j] = flash_read_u8(mtd, pos++); } for (i = 0; i < j; i++) { if (!(i & 1)) { printk(" %.2x", line[i] & 0xff); } else { printk("%.2x", line[i] & 0xff); } } /* Print empty space */ for (; i < 16; i++) { if (!(i & 1)) { printk(" "); } else { printk(" "); } } printk(" "); for (i = 0; i < j; i++) { if (isgraph(line[i])) { printk("%c", line[i]); } else { printk("."); } } printk("\n"); size -= 16; }}#endif#define flash_safe_acquire(arg)#define flash_safe_release(arg)static intflash_safe_read(struct mtd_info *mtd, loff_t from, u_char *buf, size_t count){ size_t retlen; int res; D3(printk(KERN_NOTICE "flash_safe_read(%p, %08x, %p, %08x)\n", mtd, (unsigned int) from, buf, count)); res = MTD_READ(mtd, from, count, &retlen, buf); if (retlen != count) { panic("Didn't read all bytes in flash_safe_read(). Returned %d\n", res); } return res?res:retlen;}static __u32flash_read_u32(struct mtd_info *mtd, loff_t from){ size_t retlen; __u32 ret; int res; res = MTD_READ(mtd, from, 4, &retlen, (unsigned char *)&ret); if (retlen != 4) { printk("Didn't read all bytes in flash_read_u32(). Returned %d\n", res); return 0; } return ret;}static intflash_safe_write(struct mtd_info *mtd, loff_t to, const u_char *buf, size_t count){ size_t retlen; int res; D3(printk(KERN_NOTICE "flash_safe_write(%p, %08x, %p, %08x)\n", mtd, (unsigned int) to, buf, count)); res = MTD_WRITE(mtd, to, count, &retlen, buf); if (retlen != count) { printk("Didn't write all bytes in flash_safe_write(). Returned %d\n", res); } return res?res:retlen;}static intflash_safe_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long iovec_cnt, loff_t to){ size_t retlen, retlen_a; int i; int res; D3(printk(KERN_NOTICE "flash_safe_writev(%p, %08x, %p)\n", mtd, (unsigned int) to, vecs)); if (mtd->writev) { res = MTD_WRITEV(mtd, vecs, iovec_cnt, to, &retlen); return res ? res : retlen; } /* Not implemented writev. Repeatedly use write - on the not so unreasonable assumption that the mtd driver doesn't care how many write cycles we use. */ res=0; retlen=0; for (i=0; !res && i<iovec_cnt; i++) { res = MTD_WRITE(mtd, to, vecs[i].iov_len, &retlen_a, vecs[i].iov_base); if (retlen_a != vecs[i].iov_len) { printk("Didn't write all bytes in flash_safe_writev(). Returned %d\n", res); if (i != iovec_cnt-1) return -EIO; } /* If res is non-zero, retlen_a is undefined, but we don't care because in that case it's not going to be returned anyway. */ to += retlen_a; retlen += retlen_a; } return res?res:retlen;}static intflash_memset(struct mtd_info *mtd, loff_t to, const u_char c, size_t size){ static unsigned char pattern[64]; int i; /* fill up pattern */ for(i = 0; i < 64; i++) pattern[i] = c; /* write as many 64-byte chunks as we can */ while (size >= 64) { flash_safe_write(mtd, to, pattern, 64); size -= 64; to += 64; } /* and the rest */ if(size) flash_safe_write(mtd, to, pattern, size); return size;}static voidintrep_erase_callback(struct erase_info *done){ wait_queue_head_t *wait_q; wait_q = (wait_queue_head_t *)done->priv; wake_up(wait_q);}static intflash_erase_region(struct mtd_info *mtd, loff_t start, size_t size){ struct erase_info *erase; DECLARE_WAITQUEUE(wait, current); wait_queue_head_t wait_q; erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL); if (!erase) return -ENOMEM; init_waitqueue_head(&wait_q); erase->mtd = mtd; erase->callback = intrep_erase_callback; erase->addr = start; erase->len = size; erase->priv = (u_long)&wait_q; /* FIXME: Use TASK_INTERRUPTIBLE and deal with being interrupted */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&wait_q, &wait); if (MTD_ERASE(mtd, erase) < 0) { set_current_state(TASK_RUNNING); remove_wait_queue(&wait_q, &wait); kfree(erase); printk(KERN_WARNING "flash: erase of region [0x%lx, 0x%lx] " "totally failed\n", (long)start, (long)start + size); return -1; } schedule(); /* Wait for flash to finish. */ remove_wait_queue(&wait_q, &wait); kfree(erase); return 0;}/* This routine calculates checksums in JFFS. */__u32jffs_checksum(const void *data, int size){ __u32 sum = 0; __u8 *ptr = (__u8 *)data; while (size-- > 0) { sum += *ptr++; } D3(printk(", result: 0x%08x\n", sum)); return sum;}intjffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size, __u32 *result){ __u32 sum = 0; loff_t ptr = start; __u8 *read_buf; int i, length; /* Allocate read buffer */ read_buf = (__u8 *) kmalloc (sizeof(__u8) * 4096, GFP_KERNEL); if (!read_buf) { printk(KERN_NOTICE "kmalloc failed in jffs_checksum_flash()\n"); return -ENOMEM; } /* Loop until checksum done */ while (size) { /* Get amount of data to read */ if (size < 4096) length = size; else length = 4096; /* Perform flash read */ D3(printk(KERN_NOTICE "jffs_checksum_flash\n")); flash_safe_read(mtd, ptr, &read_buf[0], length); /* Compute checksum */ for (i=0; i < length ; i++) sum += read_buf[i]; /* Update pointer and size */ size -= length; ptr += length; } /* Free read buffer */ kfree (read_buf); /* Return result */ D3(printk("checksum result: 0x%08x\n", sum)); *result = sum; return 0;}static __inline__ void jffs_fm_write_lock(struct jffs_fmcontrol *fmc){ // down(&fmc->wlock);}static __inline__ void jffs_fm_write_unlock(struct jffs_fmcontrol *fmc){ // up(&fmc->wlock);}/* Create and initialize a new struct jffs_file. */static struct jffs_file *jffs_create_file(struct jffs_control *c, const struct jffs_raw_inode *raw_inode){ struct jffs_file *f; if (!(f = (struct jffs_file *)kmalloc(sizeof(struct jffs_file), GFP_KERNEL))) { D(printk("jffs_create_file(): Failed!\n")); return 0; } no_jffs_file++; memset(f, 0, sizeof(struct jffs_file)); f->ino = raw_inode->ino; f->pino = raw_inode->pino; f->nlink = raw_inode->nlink; f->deleted = raw_inode->deleted; f->c = c; return f;}/* Build a control block for the file system. */static struct jffs_control *jffs_create_control(kdev_t dev){ struct jffs_control *c; register int s = sizeof(struct jffs_control); int i; D(char *t = 0); D2(printk("jffs_create_control()\n")); if (!(c = (struct jffs_control *)kmalloc(s, GFP_KERNEL))) { goto fail_control; } DJM(no_jffs_control++); c->root = 0; c->gc_task = 0; c->hash_len = JFFS_HASH_SIZE; s = sizeof(struct list_head) * c->hash_len; if (!(c->hash = (struct list_head *)kmalloc(s, GFP_KERNEL))) { goto fail_hash; } DJM(no_hash++); for (i = 0; i < c->hash_len; i++) INIT_LIST_HEAD(&c->hash[i]); if (!(c->fmc = jffs_build_begin(c, dev))) { goto fail_fminit; } c->next_ino = JFFS_MIN_INO + 1; c->delete_list = (struct jffs_delete_list *) 0; return c;fail_fminit: D(t = "c->fmc");fail_hash: kfree(c); DJM(no_jffs_control--); D(t = t ? t : "c->hash");fail_control: D(t = t ? t : "control"); D(printk("jffs_create_control(): Allocation failed: (%s)\n", t)); return (struct jffs_control *)0;}/* Clean up all data structures associated with the file system. */voidjffs_cleanup_control(struct jffs_control *c){ D2(printk("jffs_cleanup_control()\n")); if (!c) { D(printk("jffs_cleanup_control(): c == NULL !!!\n")); return; } while (c->delete_list) { struct jffs_delete_list *delete_list_element; delete_list_element = c->delete_list;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -