📄 intrep.c
字号:
while (!fm) { /* Deadlocks suck. */ while(fmc->free_size < fmc->min_free_size + total_size + slack) { jffs_fm_write_unlock(fmc); if (!JFFS_ENOUGH_SPACE(c, total_size + slack)) return -ENOSPC; jffs_fm_write_lock(fmc); } /* First try to allocate some flash memory. */ err = jffs_fmalloc(fmc, total_size, node, &fm); if (err == -ENOSPC) { /* Just out of space. GC and try again */ if (fmc->dirty_size < fmc->sector_size) { D(printk("jffs_write_node(): jffs_fmalloc(0x%p, %u) " "failed, no dirty space to GC\n", fmc, total_size)); return err; } D1(printk(KERN_INFO "jffs_write_node(): Calling jffs_garbage_collect_now()\n")); jffs_fm_write_unlock(fmc); if ((err = jffs_garbage_collect_now(c))) { D(printk("jffs_write_node(): jffs_garbage_collect_now() failed\n")); return err; } jffs_fm_write_lock(fmc); continue; } if (err < 0) { jffs_fm_write_unlock(fmc); D(printk("jffs_write_node(): jffs_fmalloc(0x%p, %u) " "failed!\n", fmc, total_size)); return err; } if (!fm->nodes) { /* The jffs_fm struct that we got is not good enough. Make that space dirty and try again */ if ((err = jffs_write_dummy_node(c, fm)) < 0) { kfree(fm); DJM(no_jffs_fm--); jffs_fm_write_unlock(fmc); D(printk("jffs_write_node(): " "jffs_write_dummy_node(): Failed!\n")); return err; } fm = NULL; } } /* while(!fm) */ node->fm = fm; ASSERT(if (fm->nodes == 0) { printk(KERN_ERR "jffs_write_node(): fm->nodes == 0\n"); }); pos = node->fm->offset; /* Increment the version number here. We can't let the caller set it beforehand, because we might have had to do GC on a node of this file - and we'd end up reusing version numbers. */ if (f) { raw_inode->version = f->highest_version + 1; D1(printk (KERN_NOTICE "jffs_write_node(): setting version of %s to %d\n", f->name, raw_inode->version)); } /* Compute the checksum for the data and name chunks. */ raw_inode->dchksum = jffs_checksum(data, raw_inode->dsize); raw_inode->nchksum = jffs_checksum(name, raw_inode->nsize); /* The checksum is calculated without the chksum and accurate fields so set them to zero first. */ raw_inode->accurate = 0; raw_inode->chksum = 0; raw_inode->chksum = jffs_checksum(raw_inode, sizeof(struct jffs_raw_inode)); raw_inode->accurate = 0xff; D3(printk("jffs_write_node(): About to write this raw inode to the " "flash at pos 0x%lx:\n", (long)pos)); D3(jffs_print_raw_inode(raw_inode)); /* Step 1: Write the raw jffs inode to the flash. */ if ((err = flash_safe_write(fmc->mtd, pos, (u_char *)raw_inode, sizeof(struct jffs_raw_inode))) < 0) { jffs_fmfree_partly(fmc, fm, total_name_size + total_data_size); jffs_fm_write_unlock(fmc); printk(KERN_ERR "JFFS: jffs_write_node: Failed to write " "raw_inode.\n"); return err; } pos += sizeof(struct jffs_raw_inode); /* Step 2: Write the name, if there is any. */ if (raw_inode->nsize) { if ((err = flash_safe_write(fmc->mtd, pos, (u_char *)name, raw_inode->nsize)) < 0) { jffs_fmfree_partly(fmc, fm, total_data_size); jffs_fm_write_unlock(fmc); printk(KERN_ERR "JFFS: jffs_write_node: Failed to " "write the name.\n"); return err; } pos += total_name_size; } /* Step 3: Append the actual data, if any. */ if (raw_inode->dsize) { if ((err = flash_safe_write(fmc->mtd, pos, data, raw_inode->dsize)) < 0) { jffs_fmfree_partly(fmc, fm, 0); jffs_fm_write_unlock(fmc); printk(KERN_ERR "JFFS: jffs_write_node: Failed to " "write the data.\n"); return err; } } jffs_fm_write_unlock(fmc); D3(printk("jffs_write_node(): Leaving...\n")); return raw_inode->dsize;} /* jffs_write_node() *//* Read data from the node and write it to the buffer. 'node_offset' is how much we have read from this particular node before and which shouldn't be read again. 'max_size' is how much space there is in the buffer. */static intjffs_get_node_data(struct jffs_file *f, struct jffs_node *node, unsigned char *buf,__u32 node_offset, __u32 max_size, kdev_t dev){ struct jffs_fmcontrol *fmc = f->c->fmc; __u32 pos = node->fm->offset + node->fm_offset + node_offset; __u32 avail = node->data_size - node_offset; __u32 r; D2(printk(" jffs_get_node_data(): file: \"%s\", ino: %u, " "version: %u, node_offset: %u\n", f->name, node->ino, node->version, node_offset)); r = jffs_min(avail, max_size); D3(printk(KERN_NOTICE "jffs_get_node_data\n")); flash_safe_read(fmc->mtd, pos, buf, r); D3(printk(" jffs_get_node_data(): Read %u byte%s.\n", r, (r == 1 ? "" : "s"))); return r;}/* Read data from the file's nodes. Write the data to the buffer 'buf'. 'read_offset' tells how much data we should skip. */intjffs_read_data(struct jffs_file *f, unsigned char *buf, __u32 read_offset, __u32 size){ struct jffs_node *node; __u32 read_data = 0; /* Total amount of read data. */ __u32 node_offset = 0; __u32 pos = 0; /* Number of bytes traversed. */ D2(printk("jffs_read_data(): file = \"%s\", read_offset = %d, " "size = %u\n", (f->name ? f->name : ""), read_offset, size)); if (read_offset >= f->size) { D(printk(" f->size: %d\n", f->size)); return 0; } /* First find the node to read data from. */ node = f->range_head; while (pos <= read_offset) { node_offset = read_offset - pos; if (node_offset >= node->data_size) { pos += node->data_size; node = node->range_next; } else { break; } } /* "Cats are living proof that not everything in nature has to be useful." - Garrison Keilor ('97) */ /* Fill the buffer. */ while (node && (read_data < size)) { int r; if (!node->fm) { /* This node does not refer to real data. */ r = jffs_min(size - read_data, node->data_size - node_offset); memset(&buf[read_data], 0, r); } else if ((r = jffs_get_node_data(f, node, &buf[read_data], node_offset, size - read_data, f->c->sb->s_dev)) < 0) { return r; } read_data += r; node_offset = 0; node = node->range_next; } D3(printk(" jffs_read_data(): Read %u bytes.\n", read_data)); return read_data;}/* Used for traversing all nodes in the hash table. */intjffs_foreach_file(struct jffs_control *c, int (*func)(struct jffs_file *)){ int pos; int r; int result = 0; for (pos = 0; pos < c->hash_len; pos++) { struct list_head *p, *next; for (p = c->hash[pos].next; p != &c->hash[pos]; p = next) { /* We need a reference to the next file in the list because `func' might remove the current file `f'. */ next = p->next; r = func(list_entry(p, struct jffs_file, hash)); if (r < 0) return r; result += r; } } return result;}/* Free all nodes associated with a file. */intjffs_free_node_list(struct jffs_file *f){ struct jffs_node *node; struct jffs_node *p; D3(printk("jffs_free_node_list(): f #%u, \"%s\"\n", f->ino, (f->name ? f->name : ""))); node = f->version_head; while (node) { p = node; node = node->version_next; kfree(p); DJM(no_jffs_node--); } return 0;}/* Free a file and its name. */intjffs_free_file(struct jffs_file *f){ D3(printk("jffs_free_file: f #%u, \"%s\"\n", f->ino, (f->name ? f->name : ""))); if (f->name) { kfree(f->name); DJM(no_name--); } kfree(f); DJM(no_jffs_file--); return 0;}/* See if a file is deleted. If so, mark that file's nodes as obsolete. */intjffs_possibly_delete_file(struct jffs_file *f){ struct jffs_node *n; D3(printk("jffs_possibly_delete_file(): ino: %u\n", f->ino)); ASSERT(if (!f) { printk(KERN_ERR "jffs_possibly_delete_file(): f == NULL\n"); return -1; }); if (f->deleted) { /* First try to remove all older versions. Commence with the oldest node. */ for (n = f->version_head; n; n = n->version_next) { if (!n->fm) { continue; } if (jffs_fmfree(f->c->fmc, n->fm, n) < 0) { break; } } /* Unlink the file from the filesystem. */ if (!f->c->building_fs) { jffs_unlink_file_from_tree(f); } jffs_unlink_file_from_hash(f); jffs_free_node_list(f); jffs_free_file(f); } return 0;}/* Used in conjunction with jffs_foreach_file() to count the number of files in the file system. */intjffs_file_count(struct jffs_file *f){ return 1;}/* Build up a file's range list from scratch by going through the version list. */intjffs_build_file(struct jffs_file *f){ struct jffs_node *n; D3(printk("jffs_build_file(): ino: %u, name: \"%s\"\n", f->ino, (f->name ? f->name : ""))); for (n = f->version_head; n; n = n->version_next) { jffs_update_file(f, n); } return 0;}/* Remove an amount of data from a file. If this amount of data is zero, that could mean that a node should be split in two parts. We remove or change the appropriate nodes in the lists. Starting offset of area to be removed is node->data_offset, and the length of the area is in node->removed_size. */static intjffs_delete_data(struct jffs_file *f, struct jffs_node *node){ struct jffs_node *n; __u32 offset = node->data_offset; __u32 remove_size = node->removed_size; D3(printk("jffs_delete_data(): offset = %u, remove_size = %u\n", offset, remove_size)); if (remove_size == 0 && f->range_tail && f->range_tail->data_offset + f->range_tail->data_size == offset) { /* A simple append; nothing to remove or no node to split. */ return 0; } /* Find the node where we should begin the removal. */ for (n = f->range_head; n; n = n->range_next) { if (n->data_offset + n->data_size > offset) { break; } } if (!n) { /* If there's no data in the file there's no data to remove either. */ return 0; } if (n->data_offset > offset) { /* XXX: Not implemented yet. */ printk(KERN_WARNING "JFFS: An unexpected situation " "occurred in jffs_delete_data.\n"); } else if (n->data_offset < offset) { /* See if the node has to be split into two parts. */ if (n->data_offset + n->data_size > offset + remove_size) { /* Do the split. */ struct jffs_node *new_node; D3(printk("jffs_delete_data(): Split node with " "version number %u.\n", n->version)); if (!(new_node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node), GFP_KERNEL))) { D(printk("jffs_delete_data(): -ENOMEM\n")); return -ENOMEM; } DJM(no_jffs_node++); new_node->ino = n->ino; new_node->version = n->version; new_node->data_offset = offset; new_node->data_size = n->data_size - (remove_size + (offset - n->data_offset)); new_node->fm_offset = n->fm_offset + (remove_size + (offset - n->data_offset)); new_node->name_size = n->name_size; new_node->fm = n->fm; new_node->version_prev = n; new_node->version_next = n->version_next; if (new_node->version_next) { new_node->version_next->version_prev = new_node; } else { f->version_tail = new_node; } n->version_next = new_node; new_node->range_prev = n; new_node->range_next = n->range_next; if (new_node->range_next) { new_node->range_next->range_prev = new_node; } else { f->range_tail = new_node; } /* A very interesting can of worms. */ n->range_next = new_node; n->data_size = offset - n->data_offset; if (new_node->fm) jffs_add_node(new_node); else { D1(printk(KERN_WARNING "jffs_delete_data(): Splitting an empty node (file hold).\n!")); D1(printk(KERN_WARNING "FIXME: Did dwmw2 do the right thing here?\n")); } n = new_node->range_next; remove_size = 0; } else { /* No. No need to split the node. Just remove the end of the node. */ int r = jffs_min(n->data_offset + n->data_size - offset, remove_size); n->data_size -= r; remove_size -= r; n = n->range_next; } } /* Remove as many nodes as necessary. */ while (n && remove_size) { if (n->data_size <= remove_size) { struct jffs_node *p = n; remove_size -= n->data_size; n = n->range_next; D3(printk("jffs_delete_data(): Removing node: " "ino: %u, version: %u%s\n", p->ino, p->version, (p->fm ? "" : " (virtual)"))); if (p->fm) { jffs_fmfree(f->c->fmc, p->fm, p); } jffs_unlink_node_from_range_list(f, p); jffs_unlink_node_from_version_list(f, p); kfree(p); DJM(no_jffs_node--); } else { n->data_size -= remove_size; n->fm_offset += remove_size; n->data_offset -= (node->removed_size - remove_size); n = n->range_next; break; } } /* Adjust the following nodes' information about offsets etc. */ while (n && node->removed_size) { n->data_offset -= node->removed_size; n = n->range_next; } if (node->removed_size > (f->size - node->data_offset)) { /* It's possible that the removed_size is in fact * greater than the amount of data we actually thought * were present in the first place - some of the nodes * which this node originally obsoleted may already have * been deleted from the flash by subsequent garbage
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -