Add yaffs2 file system: Fourth patchset
cover Add yaffs2 file system: Fourth patchset
This is the fourth submission of a yaffs2 patchset.
I would like to thank everyone that has given comments so far. They have been most helpful.
I would like to thank CELF (now part of Linux Foundation) and Google for sponsoring the effort to get yaffs2 mainlined.
This code is patched from 371b2eaad7d9c4947ec1e5c5f0576b7e118df617 at git://www.aleph1.co.uk/yaffs2.
This patch set takes onboard almost all the comments provided since the last set of patches. Most noteably :
* Removal of almost all the wrapper macros. Pretty much all that remains is some wrapping (YCHAR --> char) to allow Unicode compilation.
* Huge amount of reformating. Code passes checkpatch.pl except for what
* appears to be a checkpatch.pl bug (reported).
* Fixes since last submission.
This code ran various tests for the whole night with no problems seen.
Comments/feedback welcome, but I'm hopefully getting pretty close to acceptance :-).
-- Charles
PATCH 1/10 Add yaffs2 file system: Allocation, block handling and bitmapping code
--- fs/yaffs2/yaffs_allocator.c | 387 ++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_allocator.h | 30 +++ fs/yaffs2/yaffs_bitmap.c | 97 ++++++++++ fs/yaffs2/yaffs_bitmap.h | 33 ++++ fs/yaffs2/yaffs_getblockinfo.h | 35 ++++ 5 files changed, 582 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_allocator.c create mode 100644 fs/yaffs2/yaffs_allocator.h create mode 100644 fs/yaffs2/yaffs_bitmap.c create mode 100644 fs/yaffs2/yaffs_bitmap.h create mode 100644 fs/yaffs2/yaffs_getblockinfo.h
fs/yaffs2/yaffs_allocator.c new file +387 -0
@@ -0,0 +1,387 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_allocator.h" +#include "yaffs_guts.h" +#include "yaffs_trace.h" +#include "yportenv.h" + +#ifdef CONFIG_YAFFS_KMALLOC_ALLOCATOR +/* This is an alternative debug allocator. Don't use for production code. */ + +void yaffs_deinit_raw_tnodes_and_objs (struct yaffs_dev *dev) +{ + dev = dev; +} + +void yaffs_init_raw_tnodes_and_objs (struct yaffs_dev *dev) +{ + dev = dev; +} + +struct yaffs_tnode *yaffs_alloc_raw_tnode (struct yaffs_dev *dev) +{ +return kmalloc (dev->tnode_size,GFP_NOFS ); +} + +void yaffs_free_raw_tnode (struct yaffs_dev *dev,struct yaffs_tnode *tn) +{ + dev = dev; +kfree (tn); +} + +void yaffs_init_raw_objs (struct yaffs_dev *dev) +{ + dev = dev; +} + +void yaffs_deinit_raw_objs (struct yaffs_dev *dev) +{ + dev = dev; +} + +struct yaffs_obj *yaffs_alloc_raw_obj (struct yaffs_dev *dev) +{ + dev = dev; +return kmalloc (sizeof (struct yaffs_obj )); +} + +void yaffs_free_raw_obj (struct yaffs_dev *dev,struct yaffs_obj *obj) +{ + + dev = dev; +kfree (obj); +} + +#else + +struct yaffs_tnode_list { +struct yaffs_tnode_list *next; +struct yaffs_tnode *tnodes; +}; + +struct yaffs_obj_list { +struct yaffs_obj_list *next; +struct yaffs_obj *objects; +}; + +struct yaffs_allocator { +int n_tnodes_created; +struct yaffs_tnode *free_tnodes; +int n_free_tnodes; +struct yaffs_tnode_list *alloc_tnode_list; + +int n_obj_created; +struct yaffs_obj *free_objs; +int n_free_objects; + +struct yaffs_obj_list *allocated_obj_list; +}; + +static void yaffs_deinit_raw_tnodes (struct yaffs_dev *dev) +{ +struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator; +struct yaffs_tnode_list *tmp; + +if (!allocator) { +YBUG (); +return ; + } + +while (allocator->alloc_tnode_list) { + tmp = allocator->alloc_tnode_list->next; + +kfree (allocator->alloc_tnode_list->tnodes); +kfree (allocator->alloc_tnode_list); + allocator->alloc_tnode_list = tmp; + } + + allocator->free_tnodes =NULL ; + allocator->n_free_tnodes =0 ; + allocator->n_tnodes_created =0 ; +} + +static void yaffs_init_raw_tnodes (struct yaffs_dev *dev) +{ +struct yaffs_allocator *allocator = dev->allocator; + +if (allocator) { + allocator->alloc_tnode_list =NULL ; + allocator->free_tnodes =NULL ; + allocator->n_free_tnodes =0 ; + allocator->n_tnodes_created =0 ; + }else { +YBUG (); + } +} + +static int yaffs_create_tnodes (struct yaffs_dev *dev,int n_tnodes) +{ +struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator; +int i; +struct yaffs_tnode *new_tnodes; +u8 *mem; +struct yaffs_tnode *curr; +struct yaffs_tnode *next; +struct yaffs_tnode_list *tnl; + +if (!allocator) { +YBUG (); +return YAFFS_FAIL ; + } + +if (n_tnodes <1 ) +return YAFFS_OK ; + +/* make these things */ + new_tnodes =kmalloc (n_tnodes * dev->tnode_size,GFP_NOFS ); + mem = (u8 *) new_tnodes; + +if (!new_tnodes) { +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs: Could not allocate Tnodes" ); +return YAFFS_FAIL ; + } + +/* New hookup for wide tnodes */ +for (i =0 ; i < n_tnodes -1 ; i++) { + curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size]; + next = (struct yaffs_tnode *)&mem[(i +1 ) * dev->tnode_size]; + curr->internal[0 ] = next; + } + + curr = (struct yaffs_tnode *)&mem[(n_tnodes -1 ) * dev->tnode_size]; + curr->internal[0 ] = allocator->free_tnodes; + allocator->free_tnodes = (struct yaffs_tnode *)mem; + + allocator->n_free_tnodes += n_tnodes; + allocator->n_tnodes_created += n_tnodes; + +/* Now add this bunch of tnodes to a list for freeing up. +* NB If we can't add this to the management list it isn't fatal +* but it just means we can't free this bunch of tnodes later. +*/ + tnl =kmalloc (sizeof (struct yaffs_tnode_list ),GFP_NOFS ); +if (!tnl) { +yaffs_trace (YAFFS_TRACE_ERROR , +"Could not add tnodes to management list" ); +return YAFFS_FAIL ; + }else { + tnl->tnodes = new_tnodes; + tnl->next = allocator->alloc_tnode_list; + allocator->alloc_tnode_list = tnl; + } + +yaffs_trace (YAFFS_TRACE_ALLOCATE ,"Tnodes added" ); + +return YAFFS_OK ; +} + +struct yaffs_tnode *yaffs_alloc_raw_tnode (struct yaffs_dev *dev) +{ +struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator; +struct yaffs_tnode *tn =NULL ; + +if (!allocator) { +YBUG (); +return NULL ; + } + +/* If there are none left make more */ +if (!allocator->free_tnodes) +yaffs_create_tnodes (dev,YAFFS_ALLOCATION_NTNODES ); + +if (allocator->free_tnodes) { + tn = allocator->free_tnodes; + allocator->free_tnodes = allocator->free_tnodes->internal[0 ]; + allocator->n_free_tnodes--; + } + +return tn; +} + +/* FreeTnode frees up a tnode and puts it back on the free list */ +void yaffs_free_raw_tnode (struct yaffs_dev *dev,struct yaffs_tnode *tn) +{ +struct yaffs_allocator *allocator = dev->allocator; + +if (!allocator) { +YBUG (); +return ; + } + +if (tn) { + tn->internal[0 ] = allocator->free_tnodes; + allocator->free_tnodes = tn; + allocator->n_free_tnodes++; + } + dev->checkpoint_blocks_required =0 ;/* force recalculation */ +} + +static void yaffs_init_raw_objs (struct yaffs_dev *dev) +{ +struct yaffs_allocator *allocator = dev->allocator; + +if (allocator) { + allocator->allocated_obj_list =NULL ; + allocator->free_objs =NULL ; + allocator->n_free_objects =0 ; + }else { +YBUG (); + } +} + +static void yaffs_deinit_raw_objs (struct yaffs_dev *dev) +{ +struct yaffs_allocator *allocator = dev->allocator; +struct yaffs_obj_list *tmp; + +if (!allocator) { +YBUG (); +return ; + } + +while (allocator->allocated_obj_list) { + tmp = allocator->allocated_obj_list->next; +kfree (allocator->allocated_obj_list->objects); +kfree (allocator->allocated_obj_list); + + allocator->allocated_obj_list = tmp; + } + + allocator->free_objs =NULL ; + allocator->n_free_objects =0 ; + allocator->n_obj_created =0 ; +} + +static int yaffs_create_free_objs (struct yaffs_dev *dev,int n_obj) +{ +struct yaffs_allocator *allocator = dev->allocator; +int i; +struct yaffs_obj *new_objs; +struct yaffs_obj_list *list; + +if (!allocator) { +YBUG (); +return YAFFS_FAIL ; + } + +if (n_obj <1 ) +return YAFFS_OK ; + +/* make these things */ + new_objs =kmalloc (n_obj *sizeof (struct yaffs_obj ),GFP_NOFS ); + list =kmalloc (sizeof (struct yaffs_obj_list ),GFP_NOFS ); + +if (!new_objs || !list) { +kfree (new_objs); + new_objs =NULL ; +kfree (list); + list =NULL ; +yaffs_trace (YAFFS_TRACE_ALLOCATE , +"Could not allocate more objects" ); +return YAFFS_FAIL ; + } + +/* Hook them into the free list */ +for (i =0 ; i < n_obj -1 ; i++) { + new_objs[i].siblings.next = + (struct list_head *)(&new_objs[i +1 ]); + } + + new_objs[n_obj -1 ].siblings.next = (void *)allocator->free_objs; + allocator->free_objs = new_objs; + allocator->n_free_objects += n_obj; + allocator->n_obj_created += n_obj; + +/* Now add this bunch of Objects to a list for freeing up. */ + + list->objects = new_objs; + list->next = allocator->allocated_obj_list; + allocator->allocated_obj_list = list; + +return YAFFS_OK ; +} + +struct yaffs_obj *yaffs_alloc_raw_obj (struct yaffs_dev *dev) +{ +struct yaffs_obj *obj =NULL ; +struct yaffs_allocator *allocator = dev->allocator; + +if (!allocator) { +YBUG (); +return obj; + } + +/* If there are none left make more */ +if (!allocator->free_objs) +yaffs_create_free_objs (dev,YAFFS_ALLOCATION_NOBJECTS ); + +if (allocator->free_objs) { + obj = allocator->free_objs; + allocator->free_objs = + (struct yaffs_obj *)(allocator->free_objs->siblings.next); + allocator->n_free_objects--; + } + +return obj; +} + +void yaffs_free_raw_obj (struct yaffs_dev *dev,struct yaffs_obj *obj) +{ + +struct yaffs_allocator *allocator = dev->allocator; + +if (!allocator) +YBUG (); +else { +/* Link into the free list. */ + obj->siblings.next = (struct list_head *)(allocator->free_objs); + allocator->free_objs = obj; + allocator->n_free_objects++; + } +} + +void yaffs_deinit_raw_tnodes_and_objs (struct yaffs_dev *dev) +{ +if (dev->allocator) { +yaffs_deinit_raw_tnodes (dev); +yaffs_deinit_raw_objs (dev); + +kfree (dev->allocator); + dev->allocator =NULL ; + }else { +YBUG (); + } +} + +void yaffs_init_raw_tnodes_and_objs (struct yaffs_dev *dev) +{ +struct yaffs_allocator *allocator; + +if (!dev->allocator) { + allocator =kmalloc (sizeof (struct yaffs_allocator ),GFP_NOFS ); +if (allocator) { + dev->allocator = allocator; +yaffs_init_raw_tnodes (dev); +yaffs_init_raw_objs (dev); + } + }else { +YBUG (); + } +} + +#endif
fs/yaffs2/yaffs_allocator.h new file +30 -0
@@ -0,0 +1,30 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_ALLOCATOR_H__ +#define __YAFFS_ALLOCATOR_H__ + +#include "yaffs_guts.h" + +void yaffs_init_raw_tnodes_and_objs (struct yaffs_dev *dev); +void yaffs_deinit_raw_tnodes_and_objs (struct yaffs_dev *dev); + +struct yaffs_tnode *yaffs_alloc_raw_tnode (struct yaffs_dev *dev); +void yaffs_free_raw_tnode (struct yaffs_dev *dev,struct yaffs_tnode *tn); + +struct yaffs_obj *yaffs_alloc_raw_obj (struct yaffs_dev *dev); +void yaffs_free_raw_obj (struct yaffs_dev *dev,struct yaffs_obj *obj); + +#endif
fs/yaffs2/yaffs_bitmap.c new file +97 -0
97 lines not on this page · raw message
fs/yaffs2/yaffs_bitmap.h new file +33 -0
@@ -0,0 +1,33 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +/* +* Chunk bitmap manipulations +*/ + +#ifndef __YAFFS_BITMAP_H__ +#define __YAFFS_BITMAP_H__ + +#include "yaffs_guts.h" + +void yaffs_verify_chunk_bit_id (struct yaffs_dev *dev,int blk,int chunk); +void yaffs_clear_chunk_bits (struct yaffs_dev *dev,int blk); +void yaffs_clear_chunk_bit (struct yaffs_dev *dev,int blk,int chunk); +void yaffs_set_chunk_bit (struct yaffs_dev *dev,int blk,int chunk); +int yaffs_check_chunk_bit (struct yaffs_dev *dev,int blk,int chunk); +int yaffs_still_some_chunks (struct yaffs_dev *dev,int blk); +int yaffs_count_chunk_bits (struct yaffs_dev *dev,int blk); + +#endif
fs/yaffs2/yaffs_getblockinfo.h new file +35 -0
@@ -0,0 +1,35 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_GETBLOCKINFO_H__ +#define __YAFFS_GETBLOCKINFO_H__ + +#include "yaffs_guts.h" +#include "yaffs_trace.h" + +/* Function to manipulate block info */ +static inline struct yaffs_block_info *yaffs_get_block_info (struct yaffs_dev + *dev,int blk) +{ +if (blk < dev->internal_start_block || blk > dev->internal_end_block) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>> yaffs: get_block_info block %d is not valid" , + blk); +YBUG (); + } +return &dev->block_info[blk - dev->internal_start_block]; +} + +#endif
Signature · 1 line
1.7.1
Re: [PATCH 01/10] Add yaffs2 file system: Allocation, block handling and bitmapping code
Quoted 1 line · Charles Manning
Signed-off-by Charles Manning <[email protected]>
Hi Charles,
A few comments below.
~Ryan
Quoted 28 lines
--- fs/yaffs2/yaffs_allocator.c | 387 ++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_allocator.h | 30 +++ fs/yaffs2/yaffs_bitmap.c | 97 ++++++++++ fs/yaffs2/yaffs_bitmap.h | 33 ++++ fs/yaffs2/yaffs_getblockinfo.h | 35 ++++ 5 files changed, 582 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_allocator.c create mode 100644 fs/yaffs2/yaffs_allocator.h create mode 100644 fs/yaffs2/yaffs_bitmap.c create mode 100644 fs/yaffs2/yaffs_bitmap.h create mode 100644 fs/yaffs2/yaffs_getblockinfo.hfs/yaffs2/yaffs_allocator.c new file +9
-0@@ -0,0 +1,387 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify
fs/yaffs2/yaffs_allocator.c line 19
Quoted 10 lines
fs/yaffs2/yaffs_allocator.c new file +10
-0+* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_allocator.h" +#include "yaffs_guts.h" +#include "yaffs_trace.h" +#include "yportenv.h" + +#ifdef CONFIG_YAFFS_KMALLOC_ALLOCATOR
I still don't understand what this is for. It's not in Kconfig. If it is a debugging feature then there should be a comment to that effect.
Also, if you do want to keep the two alternative versions of the code here, it may be better to put them in separate files and use Makefile rules to include the correct one.
fs/yaffs2/yaffs_allocator.c line 22
Quoted 3 lines
fs/yaffs2/yaffs_allocator.c new file +3
-0+/* This is an alternative debug allocator. Don't use for production code. */ + +void yaffs_deinit_raw_tnodes_and_objs (struct yaffs_dev *dev)
You can use the __always_unused attribute instead of the self assignments. Do you actually get warnings without the assignment?
Quoted 62 lines
fs/yaffs2/yaffs_allocator.c new file +62
-0+{ + dev = dev; +} + +void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev) +{ + dev = dev; +} + +struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev) +{ + return kmalloc(dev->tnode_size, GFP_NOFS); +} + +void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) +{ + dev = dev; + kfree(tn); +} + +void yaffs_init_raw_objs(struct yaffs_dev *dev) +{ + dev = dev; +} + +void yaffs_deinit_raw_objs(struct yaffs_dev *dev) +{ + dev = dev; +} + +struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev) +{ + dev = dev; + return kmalloc(sizeof(struct yaffs_obj)); +} + +void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj) +{ + + dev = dev; + kfree(obj); +} + +#else + +struct yaffs_tnode_list { + struct yaffs_tnode_list *next; + struct yaffs_tnode *tnodes; +}; + +struct yaffs_obj_list { + struct yaffs_obj_list *next; + struct yaffs_obj *objects; +}; + +struct yaffs_allocator { + int n_tnodes_created; + struct yaffs_tnode *free_tnodes; + int n_free_tnodes; + struct yaffs_tnode_list *alloc_tnode_list; + + int n_obj_created;
fs/yaffs2/yaffs_allocator.c line 94
Quoted 10 lines
fs/yaffs2/yaffs_allocator.c new file +10
-0+struct yaffs_obj *free_objs; +int n_free_objects; + +struct yaffs_obj_list *allocated_obj_list; +}; + +static void yaffs_deinit_raw_tnodes (struct yaffs_dev *dev) +{ +struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator;
yaffs_dev->allocator is type void *. Is this necessary? It looks like it is always used as struct yaffs_allocator, so would be better to change the type and remove all of the casting.
fs/yaffs2/yaffs_allocator.c line 100
Quoted 6 lines
fs/yaffs2/yaffs_allocator.c new file +6
-0+struct yaffs_tnode_list *tmp; + +if (!allocator) { +YBUG (); +return ; + }
You don't need this bug, the dereference of allocator below will oops with all the same information as bug.
Quoted 15 lines
fs/yaffs2/yaffs_allocator.c new file +15
-0+while (allocator->alloc_tnode_list) { + tmp = allocator->alloc_tnode_list->next; + +kfree (allocator->alloc_tnode_list->tnodes); +kfree (allocator->alloc_tnode_list); + allocator->alloc_tnode_list = tmp; + } + + allocator->free_tnodes =NULL ; + allocator->n_free_tnodes =0 ; + allocator->n_tnodes_created =0 ; +} + +static void yaffs_init_raw_tnodes (struct yaffs_dev *dev) +{
fs/yaffs2/yaffs_allocator.c line 126
Quoted 10 lines
fs/yaffs2/yaffs_allocator.c new file +10
-0+struct yaffs_allocator *allocator = dev->allocator; + +if (allocator) { + allocator->alloc_tnode_list =NULL ; + allocator->free_tnodes =NULL ; + allocator->n_free_tnodes =0 ; + allocator->n_tnodes_created =0 ; + }else { +YBUG (); + }
Again, you don't need the explicit bug. Just dereference allocator and you will oops if it is null. There are several other places where bug can be removed also.
Quoted 25 lines
fs/yaffs2/yaffs_allocator.c new file +25
-0+} + +static int yaffs_create_tnodes (struct yaffs_dev *dev,int n_tnodes) +{ +struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator; +int i; +struct yaffs_tnode *new_tnodes; +u8 *mem; +struct yaffs_tnode *curr; +struct yaffs_tnode *next; +struct yaffs_tnode_list *tnl; + +if (!allocator) { +YBUG (); +return YAFFS_FAIL ; + } + +if (n_tnodes <1 ) +return YAFFS_OK ; + +/* make these things */ + new_tnodes =kmalloc (n_tnodes * dev->tnode_size,GFP_NOFS ); + mem = (u8 *) new_tnodes; +
fs/yaffs2/yaffs_allocator.c line 161
Quoted 10 lines
fs/yaffs2/yaffs_allocator.c new file +10
-0+if (!new_tnodes) { +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs: Could not allocate Tnodes" ); +return YAFFS_FAIL ; + } + +/* New hookup for wide tnodes */ +for (i =0 ; i < n_tnodes -1 ; i++) { + curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size]; + next = (struct yaffs_tnode *)&mem[(i +1 ) * dev->tnode_size];
mem is declared u8 * but is being used as type (struct yaffs_tnode *). I realise that pointer addition won't work correctly because you use dev->tnode_size rather than sizeof(struct yaffs_tnode), but is there a cleaner way to do this without the casting?
Quoted 8 lines
fs/yaffs2/yaffs_allocator.c new file +8
-0+ curr->internal[0 ] = next; + } + + curr = (struct yaffs_tnode *)&mem[(n_tnodes -1 ) * dev->tnode_size]; + curr->internal[0 ] = allocator->free_tnodes; + allocator->free_tnodes = (struct yaffs_tnode *)mem; + + allocator->n_free_tnodes += n_tnodes;
fs/yaffs2/yaffs_allocator.c line 179
Quoted 10 lines
fs/yaffs2/yaffs_allocator.c new file +10
-0+ allocator->n_tnodes_created += n_tnodes; + +/* Now add this bunch of tnodes to a list for freeing up. +* NB If we can't add this to the management list it isn't fatal +* but it just means we can't free this bunch of tnodes later. +*/ + tnl =kmalloc (sizeof (struct yaffs_tnode_list ),GFP_NOFS ); +if (!tnl) { +yaffs_trace (YAFFS_TRACE_ERROR , +"Could not add tnodes to management list" );
Should new_nodes be freed here?
Quoted 103 lines
fs/yaffs2/yaffs_allocator.c new file +103
-0+return YAFFS_FAIL ; + }else { + tnl->tnodes = new_tnodes; + tnl->next = allocator->alloc_tnode_list; + allocator->alloc_tnode_list = tnl; + } + +yaffs_trace (YAFFS_TRACE_ALLOCATE ,"Tnodes added" ); + +return YAFFS_OK ; +} + +struct yaffs_tnode *yaffs_alloc_raw_tnode (struct yaffs_dev *dev) +{ +struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator; +struct yaffs_tnode *tn =NULL ; + +if (!allocator) { +YBUG (); +return NULL ; + } + +/* If there are none left make more */ +if (!allocator->free_tnodes) +yaffs_create_tnodes (dev,YAFFS_ALLOCATION_NTNODES ); + +if (allocator->free_tnodes) { + tn = allocator->free_tnodes; + allocator->free_tnodes = allocator->free_tnodes->internal[0 ]; + allocator->n_free_tnodes--; + } + +return tn; +} + +/* FreeTnode frees up a tnode and puts it back on the free list */ +void yaffs_free_raw_tnode (struct yaffs_dev *dev,struct yaffs_tnode *tn) +{ +struct yaffs_allocator *allocator = dev->allocator; + +if (!allocator) { +YBUG (); +return ; + } +if (tn) { + tn->internal[0 ] = allocator->free_tnodes; + allocator->free_tnodes = tn; + allocator->n_free_tnodes++; + } + dev->checkpoint_blocks_required =0 ;/* force recalculation */ +} + +static void yaffs_init_raw_objs (struct yaffs_dev *dev) +{ +struct yaffs_allocator *allocator = dev->allocator; + +if (allocator) { + allocator->allocated_obj_list =NULL ; + allocator->free_objs =NULL ; + allocator->n_free_objects =0 ; + }else { +YBUG (); + } +} + +static void yaffs_deinit_raw_objs (struct yaffs_dev *dev) +{ +struct yaffs_allocator *allocator = dev->allocator; +struct yaffs_obj_list *tmp; + +if (!allocator) { +YBUG (); +return ; + } + +while (allocator->allocated_obj_list) { + tmp = allocator->allocated_obj_list->next; +kfree (allocator->allocated_obj_list->objects); +kfree (allocator->allocated_obj_list); + + allocator->allocated_obj_list = tmp; + } + + allocator->free_objs =NULL ; + allocator->n_free_objects =0 ; + allocator->n_obj_created =0 ; +} + +static int yaffs_create_free_objs (struct yaffs_dev *dev,int n_obj) +{ +struct yaffs_allocator *allocator = dev->allocator; +int i; +struct yaffs_obj *new_objs; +struct yaffs_obj_list *list; + +if (!allocator) { +YBUG (); +return YAFFS_FAIL ; + } + +if (n_obj <1 ) +return YAFFS_OK ;
fs/yaffs2/yaffs_allocator.c line 293
Quoted 10 lines
fs/yaffs2/yaffs_allocator.c new file +10
-0+ +/* make these things */ + new_objs =kmalloc (n_obj *sizeof (struct yaffs_obj ),GFP_NOFS ); + list =kmalloc (sizeof (struct yaffs_obj_list ),GFP_NOFS ); + +if (!new_objs || !list) { +kfree (new_objs); + new_objs =NULL ; +kfree (list); + list =NULL ;
You don't need to set new_objs and list to NULL here.
fs/yaffs2/yaffs_allocator.c line 302
Quoted 9 lines
fs/yaffs2/yaffs_allocator.c new file +9
-0+yaffs_trace (YAFFS_TRACE_ALLOCATE , +"Could not allocate more objects" ); +return YAFFS_FAIL ; + } + +/* Hook them into the free list */ +for (i =0 ; i < n_obj -1 ; i++) { + new_objs[i].siblings.next = + (struct list_head *)(&new_objs[i +1 ]);
This cast looks like you are doing something with odd with list_head.
fs/yaffs2/yaffs_allocator.c line 305
Quoted 3 lines
fs/yaffs2/yaffs_allocator.c new file +3
-0+ } + + new_objs[n_obj -1 ].siblings.next = (void *)allocator->free_objs;
You shouldn't need the void * cast here.
Quoted 37 lines
fs/yaffs2/yaffs_allocator.c new file +37
-0+ allocator->free_objs = new_objs; + allocator->n_free_objects += n_obj; + allocator->n_obj_created += n_obj; + +/* Now add this bunch of Objects to a list for freeing up. */ + + list->objects = new_objs; + list->next = allocator->allocated_obj_list; + allocator->allocated_obj_list = list; + +return YAFFS_OK ; +} + +struct yaffs_obj *yaffs_alloc_raw_obj (struct yaffs_dev *dev) +{ +struct yaffs_obj *obj =NULL ; +struct yaffs_allocator *allocator = dev->allocator; + +if (!allocator) { +YBUG (); +return obj; + } + +/* If there are none left make more */ +if (!allocator->free_objs) +yaffs_create_free_objs (dev,YAFFS_ALLOCATION_NOBJECTS ); + +if (allocator->free_objs) { + obj = allocator->free_objs; + allocator->free_objs = + (struct yaffs_obj *)(allocator->free_objs->siblings.next); + allocator->n_free_objects--; + } + +return obj; +} +
fs/yaffs2/yaffs_allocator.c line 352
Quoted 10 lines
fs/yaffs2/yaffs_allocator.c new file +10
-0+void yaffs_free_raw_obj (struct yaffs_dev *dev,struct yaffs_obj *obj) +{ + +struct yaffs_allocator *allocator = dev->allocator; + +if (!allocator) +YBUG (); +else { +/* Link into the free list. */ + obj->siblings.next = (struct list_head *)(allocator->free_objs);
More list_head weirdness.
Quoted 254 lines
fs/yaffs2/yaffs_allocator.c new file +35
-0+ allocator->free_objs = obj; + allocator->n_free_objects++; + } +} + +void yaffs_deinit_raw_tnodes_and_objs (struct yaffs_dev *dev) +{ +if (dev->allocator) { +yaffs_deinit_raw_tnodes (dev); +yaffs_deinit_raw_objs (dev); + +kfree (dev->allocator); + dev->allocator =NULL ; + }else { +YBUG (); + } +} + +void yaffs_init_raw_tnodes_and_objs (struct yaffs_dev *dev) +{ +struct yaffs_allocator *allocator; + +if (!dev->allocator) { + allocator =kmalloc (sizeof (struct yaffs_allocator ),GFP_NOFS ); +if (allocator) { + dev->allocator = allocator; +yaffs_init_raw_tnodes (dev); +yaffs_init_raw_objs (dev); + } + }else { +YBUG (); + } +} + +#endif fs/yaffs2/yaffs_allocator.h new file +30
-0@@ -0,0 +1,30 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_ALLOCATOR_H__ +#define __YAFFS_ALLOCATOR_H__ + +#include "yaffs_guts.h" + +void yaffs_init_raw_tnodes_and_objs (struct yaffs_dev *dev); +void yaffs_deinit_raw_tnodes_and_objs (struct yaffs_dev *dev); + +struct yaffs_tnode *yaffs_alloc_raw_tnode (struct yaffs_dev *dev); +void yaffs_free_raw_tnode (struct yaffs_dev *dev,struct yaffs_tnode *tn); + +struct yaffs_obj *yaffs_alloc_raw_obj (struct yaffs_dev *dev); +void yaffs_free_raw_obj (struct yaffs_dev *dev,struct yaffs_obj *obj); + +#endif fs/yaffs2/yaffs_bitmap.c new file +97
-0@@ -0,0 +1,97 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_bitmap.h" +#include "yaffs_trace.h" +/* +* Chunk bitmap manipulations +*/ + +static inline u8 *yaffs_block_bits (struct yaffs_dev *dev,int blk) +{ +if (blk < dev->internal_start_block || blk > dev->internal_end_block) { +yaffs_trace (YAFFS_TRACE_ERROR , +"BlockBits block %d is not valid" , + blk); +YBUG (); + } +return dev->chunk_bits + + (dev->chunk_bit_stride * (blk - dev->internal_start_block)); +} + +void yaffs_verify_chunk_bit_id (struct yaffs_dev *dev,int blk,int chunk) +{ +if (blk < dev->internal_start_block || blk > dev->internal_end_block || + chunk <0 || chunk >= dev->param.chunks_per_block) { +yaffs_trace (YAFFS_TRACE_ERROR , +"Chunk Id (%d:%d) invalid" , + blk, chunk); +YBUG (); + } +} + +void yaffs_clear_chunk_bits (struct yaffs_dev *dev,int blk) +{ +u8 *blk_bits =yaffs_block_bits (dev, blk); + +memset (blk_bits,0 , dev->chunk_bit_stride); +} + +void yaffs_clear_chunk_bit (struct yaffs_dev *dev,int blk,int chunk) +{ +u8 *blk_bits =yaffs_block_bits (dev, blk); + +yaffs_verify_chunk_bit_id (dev, blk, chunk); + blk_bits[chunk /8 ] &= ~(1 << (chunk &7 )); +} + +void yaffs_set_chunk_bit (struct yaffs_dev *dev,int blk,int chunk) +{ +u8 *blk_bits =yaffs_block_bits (dev, blk); + +yaffs_verify_chunk_bit_id (dev, blk, chunk); + blk_bits[chunk /8 ] |= (1 << (chunk &7 )); +} + +int yaffs_check_chunk_bit (struct yaffs_dev *dev,int blk,int chunk) +{ +u8 *blk_bits =yaffs_block_bits (dev, blk); + +yaffs_verify_chunk_bit_id (dev, blk, chunk); +return (blk_bits[chunk /8 ] & (1 << (chunk &7 ))) ?1 :0 ; +} + +int yaffs_still_some_chunks (struct yaffs_dev *dev,int blk) +{ +u8 *blk_bits =yaffs_block_bits (dev, blk); +int i; + +for (i =0 ; i < dev->chunk_bit_stride; i++) { +if (*blk_bits) +return 1 ; + blk_bits++; + } +return 0 ; +} + +int yaffs_count_chunk_bits (struct yaffs_dev *dev,int blk) +{ +u8 *blk_bits =yaffs_block_bits (dev, blk); +int i; +int n =0 ; + +for (i =0 ; i < dev->chunk_bit_stride; i++, blk_bits++) + n +=hweight8 (*blk_bits); + +return n; +}fs/yaffs2/yaffs_bitmap.h new file +33
-0@@ -0,0 +1,33 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +/* +* Chunk bitmap manipulations +*/ + +#ifndef __YAFFS_BITMAP_H__ +#define __YAFFS_BITMAP_H__ + +#include "yaffs_guts.h" + +void yaffs_verify_chunk_bit_id (struct yaffs_dev *dev,int blk,int chunk); +void yaffs_clear_chunk_bits (struct yaffs_dev *dev,int blk); +void yaffs_clear_chunk_bit (struct yaffs_dev *dev,int blk,int chunk); +void yaffs_set_chunk_bit (struct yaffs_dev *dev,int blk,int chunk); +int yaffs_check_chunk_bit (struct yaffs_dev *dev,int blk,int chunk); +int yaffs_still_some_chunks (struct yaffs_dev *dev,int blk); +int yaffs_count_chunk_bits (struct yaffs_dev *dev,int blk); + +#endif fs/yaffs2/yaffs_getblockinfo.h new file +35
-0@@ -0,0 +1,35 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_GETBLOCKINFO_H__ +#define __YAFFS_GETBLOCKINFO_H__ + +#include "yaffs_guts.h" +#include "yaffs_trace.h" + +/* Function to manipulate block info */ +static inline struct yaffs_block_info *yaffs_get_block_info (struct yaffs_dev + *dev,int blk) +{ +if (blk < dev->internal_start_block || blk > dev->internal_end_block) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>> yaffs: get_block_info block %d is not valid" , + blk); +YBUG (); + } +return &dev->block_info[blk - dev->internal_start_block]; +} + +#endif
Signature · 7 lines
Bluewater Systems Ltd - ARM Technology Solution Centre Ryan Mallon 5 Amuri Park, 404 Barbadoes St [email protected] PO Box 13 889, Christchurch 8013 http://www.bluewatersys.com New Zealand Phone: +64 3 3779127 Freecall: Australia 1800 148 751 Fax: +64 3 3779135 USA 1800 261 2934
Re: [PATCH 01/10] Add yaffs2 file system: Allocation, block handling and bitmapping code
Quoted 1 line · Ryan Mallon
On 01/14/2011 04:06 PM, Charles Manning wrote:
[...]
Quoted 8 lines
fs/yaffs2/yaffs_allocator.c line 100
Quoted 4 lines
fs/yaffs2/yaffs_allocator.c new file +4
-0+if (!allocator) { +YBUG (); +return ; + }You don't need this bug, the dereference of allocator below will oops with all the same information as bug.
Is that true for nommu systems too?
David Daney
Re: [PATCH 01/10] Add yaffs2 file system: Allocation, block handling and bitmapping code
Quoted 8 lines · David Daney
Quoted 1 line · Ryan Mallon
On 01/14/2011 04:06 PM, Charles Manning wrote:
[...]
Quoted 5 lines
Quoted 4 lines
fs/yaffs2/yaffs_allocator.c new file +4
-0+if (!allocator) { +YBUG (); +return ; + }
Quoted 5 lines
Quoted 3 lines
You don't need this bug, the dereference of allocator below will oops with all the same information as bug.
Is that true for nommu systems too?
Actually, I'm not too sure. I understood that best practice was to avoid putting BUG in places that will normally oops. Maybe someone can shed some light on this?
~Ryan
Signature · 7 lines
Bluewater Systems Ltd - ARM Technology Solution Centre Ryan Mallon 5 Amuri Park, 404 Barbadoes St [email protected] PO Box 13 889, Christchurch 8013 http://www.bluewatersys.com New Zealand Phone: +64 3 3779127 Freecall: Australia 1800 148 751 Fax: +64 3 3779135 USA 1800 261 2934
PATCH 2/10 Add yaffs2 file system: Attribute and xattrib handling code
In reply to Charles Manning--- fs/yaffs2/yaffs_attribs.c | 124 +++++++++++++++++++++++++++ fs/yaffs2/yaffs_attribs.h | 28 ++++++ fs/yaffs2/yaffs_nameval.c | 204 +++++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_nameval.h | 28 ++++++ 4 files changed, 384 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_attribs.c create mode 100644 fs/yaffs2/yaffs_attribs.h create mode 100644 fs/yaffs2/yaffs_nameval.c create mode 100644 fs/yaffs2/yaffs_nameval.h
fs/yaffs2/yaffs_attribs.c new file +124 -0
@@ -0,0 +1,124 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_guts.h" +#include "yaffs_attribs.h" + +void yaffs_load_attribs (struct yaffs_obj *obj,struct yaffs_obj_hdr *oh) +{ + obj->yst_uid = oh->yst_uid; + obj->yst_gid = oh->yst_gid; + obj->yst_atime = oh->yst_atime; + obj->yst_mtime = oh->yst_mtime; + obj->yst_ctime = oh->yst_ctime; + obj->yst_rdev = oh->yst_rdev; +} + +void yaffs_load_attribs_oh (struct yaffs_obj_hdr *oh,struct yaffs_obj *obj) +{ + oh->yst_uid = obj->yst_uid; + oh->yst_gid = obj->yst_gid; + oh->yst_atime = obj->yst_atime; + oh->yst_mtime = obj->yst_mtime; + oh->yst_ctime = obj->yst_ctime; + oh->yst_rdev = obj->yst_rdev; + +} + +void yaffs_load_current_time (struct yaffs_obj *obj,int do_a,int do_c) +{ + obj->yst_mtime =Y_CURRENT_TIME ; +if (do_a) + obj->yst_atime = obj->yst_mtime; +if (do_c) + obj->yst_ctime = obj->yst_mtime; +} + +void yaffs_attribs_init (struct yaffs_obj *obj,u32 gid,u32 uid,u32 rdev) +{ +yaffs_load_current_time (obj,1 ,1 ); + obj->yst_rdev = rdev; + obj->yst_uid = uid; + obj->yst_gid = gid; +} + +loff_t yaffs_get_file_size (struct yaffs_obj *obj) +{ +YCHAR *alias =NULL ; + obj =yaffs_get_equivalent_obj (obj); + +switch (obj->variant_type) { +case YAFFS_OBJECT_TYPE_FILE : +return obj->variant.file_variant.file_size; +case YAFFS_OBJECT_TYPE_SYMLINK : + alias = obj->variant.symlink_variant.alias; +if (!alias) +return 0 ; +return strnlen (alias,YAFFS_MAX_ALIAS_LENGTH ); +default : +return 0 ; + } +} + +int yaffs_set_attribs (struct yaffs_obj *obj,struct iattr *attr) +{ +unsigned int valid = attr->ia_valid; + +if (valid &ATTR_MODE ) + obj->yst_mode = attr->ia_mode; +if (valid &ATTR_UID ) + obj->yst_uid = attr->ia_uid; +if (valid &ATTR_GID ) + obj->yst_gid = attr->ia_gid; + +if (valid &ATTR_ATIME ) + obj->yst_atime =Y_TIME_CONVERT (attr->ia_atime); +if (valid &ATTR_CTIME ) + obj->yst_ctime =Y_TIME_CONVERT (attr->ia_ctime); +if (valid &ATTR_MTIME ) + obj->yst_mtime =Y_TIME_CONVERT (attr->ia_mtime); + +if (valid &ATTR_SIZE ) +yaffs_resize_file (obj, attr->ia_size); + +yaffs_update_oh (obj,NULL ,1 ,0 ,0 ,NULL ); + +return YAFFS_OK ; + +} + +int yaffs_get_attribs (struct yaffs_obj *obj,struct iattr *attr) +{ +unsigned int valid =0 ; + + attr->ia_mode = obj->yst_mode; + valid |=ATTR_MODE ; + attr->ia_uid = obj->yst_uid; + valid |=ATTR_UID ; + attr->ia_gid = obj->yst_gid; + valid |=ATTR_GID ; + +Y_TIME_CONVERT (attr->ia_atime) = obj->yst_atime; + valid |=ATTR_ATIME ; +Y_TIME_CONVERT (attr->ia_ctime) = obj->yst_ctime; + valid |=ATTR_CTIME ; +Y_TIME_CONVERT (attr->ia_mtime) = obj->yst_mtime; + valid |=ATTR_MTIME ; + + attr->ia_size =yaffs_get_file_size (obj); + valid |=ATTR_SIZE ; + + attr->ia_valid = valid; + +return YAFFS_OK ; +}
fs/yaffs2/yaffs_attribs.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_ATTRIBS_H__ +#define __YAFFS_ATTRIBS_H__ + +#include "yaffs_guts.h" + +void yaffs_load_attribs (struct yaffs_obj *obj,struct yaffs_obj_hdr *oh); +void yaffs_load_attribs_oh (struct yaffs_obj_hdr *oh,struct yaffs_obj *obj); +void yaffs_attribs_init (struct yaffs_obj *obj,u32 gid,u32 uid,u32 rdev); +void yaffs_load_current_time (struct yaffs_obj *obj,int do_a,int do_c); +int yaffs_set_attribs (struct yaffs_obj *obj,struct iattr *attr); +int yaffs_get_attribs (struct yaffs_obj *obj,struct iattr *attr); + +#endif
fs/yaffs2/yaffs_nameval.c new file +204 -0
204 lines not on this page · raw message
fs/yaffs2/yaffs_nameval.h new file +28 -0
@@ -0,0 +1,28 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __NAMEVAL_H__ +#define __NAMEVAL_H__ + +#include "yportenv.h" + +int nval_del (char *xb,int xb_size,const YCHAR * name); +int nval_set (char *xb,int xb_size,const YCHAR * name,const char *buf, +int bsize,int flags); +int nval_get (const char *xb,int xb_size,const YCHAR * name,char *buf, +int bsize); +int nval_list (const char *xb,int xb_size,char *buf,int bsize); +int nval_hasvalues (const char *xb,int xb_size); +#endif
Signature · 1 line
1.7.1
Re: [PATCH 02/10] Add yaffs2 file system: Attribute and xattrib handling code
Quoted 1 line · Charles Manning
Signed-off-by Charles Manning <[email protected]>
Couple of comments below.
~Ryan
Quoted 64 lines
--- fs/yaffs2/yaffs_attribs.c | 124 +++++++++++++++++++++++++++ fs/yaffs2/yaffs_attribs.h | 28 ++++++ fs/yaffs2/yaffs_nameval.c | 204 +++++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_nameval.h | 28 ++++++ 4 files changed, 384 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_attribs.c create mode 100644 fs/yaffs2/yaffs_attribs.h create mode 100644 fs/yaffs2/yaffs_nameval.c create mode 100644 fs/yaffs2/yaffs_nameval.hfs/yaffs2/yaffs_attribs.c new file +47
-0@@ -0,0 +1,124 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_guts.h" +#include "yaffs_attribs.h" + +void yaffs_load_attribs (struct yaffs_obj *obj,struct yaffs_obj_hdr *oh) +{ + obj->yst_uid = oh->yst_uid; + obj->yst_gid = oh->yst_gid; + obj->yst_atime = oh->yst_atime; + obj->yst_mtime = oh->yst_mtime; + obj->yst_ctime = oh->yst_ctime; + obj->yst_rdev = oh->yst_rdev; +} + +void yaffs_load_attribs_oh (struct yaffs_obj_hdr *oh,struct yaffs_obj *obj) +{ + oh->yst_uid = obj->yst_uid; + oh->yst_gid = obj->yst_gid; + oh->yst_atime = obj->yst_atime; + oh->yst_mtime = obj->yst_mtime; + oh->yst_ctime = obj->yst_ctime; + oh->yst_rdev = obj->yst_rdev; + +} + +void yaffs_load_current_time (struct yaffs_obj *obj,int do_a,int do_c) +{ + obj->yst_mtime =Y_CURRENT_TIME ; +if (do_a) + obj->yst_atime = obj->yst_mtime; +if (do_c) + obj->yst_ctime = obj->yst_mtime; +} + +void yaffs_attribs_init (struct yaffs_obj *obj,u32 gid,u32 uid,u32 rdev)
fs/yaffs2/yaffs_attribs.c line 57
Quoted 10 lines
fs/yaffs2/yaffs_attribs.c new file +10
-0+{ +yaffs_load_current_time (obj,1 ,1 ); + obj->yst_rdev = rdev; + obj->yst_uid = uid; + obj->yst_gid = gid; +} + +loff_t yaffs_get_file_size (struct yaffs_obj *obj) +{ +YCHAR *alias =NULL ;
You shouldn't need to initialise alias to NULL here.
Quoted 138 lines
fs/yaffs2/yaffs_attribs.c new file +67
-0+ obj =yaffs_get_equivalent_obj (obj); + +switch (obj->variant_type) { +case YAFFS_OBJECT_TYPE_FILE : +return obj->variant.file_variant.file_size; +case YAFFS_OBJECT_TYPE_SYMLINK : + alias = obj->variant.symlink_variant.alias; +if (!alias) +return 0 ; +return strnlen (alias,YAFFS_MAX_ALIAS_LENGTH ); +default : +return 0 ; + } +} + +int yaffs_set_attribs (struct yaffs_obj *obj,struct iattr *attr) +{ +unsigned int valid = attr->ia_valid; + +if (valid &ATTR_MODE ) + obj->yst_mode = attr->ia_mode; +if (valid &ATTR_UID ) + obj->yst_uid = attr->ia_uid; +if (valid &ATTR_GID ) + obj->yst_gid = attr->ia_gid; + +if (valid &ATTR_ATIME ) + obj->yst_atime =Y_TIME_CONVERT (attr->ia_atime); +if (valid &ATTR_CTIME ) + obj->yst_ctime =Y_TIME_CONVERT (attr->ia_ctime); +if (valid &ATTR_MTIME ) + obj->yst_mtime =Y_TIME_CONVERT (attr->ia_mtime); + +if (valid &ATTR_SIZE ) +yaffs_resize_file (obj, attr->ia_size); + +yaffs_update_oh (obj,NULL ,1 ,0 ,0 ,NULL ); + +return YAFFS_OK ; + +} + +int yaffs_get_attribs (struct yaffs_obj *obj,struct iattr *attr) +{ +unsigned int valid =0 ; + + attr->ia_mode = obj->yst_mode; + valid |=ATTR_MODE ; + attr->ia_uid = obj->yst_uid; + valid |=ATTR_UID ; + attr->ia_gid = obj->yst_gid; + valid |=ATTR_GID ; + +Y_TIME_CONVERT (attr->ia_atime) = obj->yst_atime; + valid |=ATTR_ATIME ; +Y_TIME_CONVERT (attr->ia_ctime) = obj->yst_ctime; + valid |=ATTR_CTIME ; +Y_TIME_CONVERT (attr->ia_mtime) = obj->yst_mtime; + valid |=ATTR_MTIME ; + + attr->ia_size =yaffs_get_file_size (obj); + valid |=ATTR_SIZE ; + + attr->ia_valid = valid; + +return YAFFS_OK ; +}fs/yaffs2/yaffs_attribs.h new file +28
-0@@ -0,0 +1,28 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_ATTRIBS_H__ +#define __YAFFS_ATTRIBS_H__ + +#include "yaffs_guts.h" + +void yaffs_load_attribs (struct yaffs_obj *obj,struct yaffs_obj_hdr *oh); +void yaffs_load_attribs_oh (struct yaffs_obj_hdr *oh,struct yaffs_obj *obj); +void yaffs_attribs_init (struct yaffs_obj *obj,u32 gid,u32 uid,u32 rdev); +void yaffs_load_current_time (struct yaffs_obj *obj,int do_a,int do_c); +int yaffs_set_attribs (struct yaffs_obj *obj,struct iattr *attr); +int yaffs_get_attribs (struct yaffs_obj *obj,struct iattr *attr); + +#endif fs/yaffs2/yaffs_nameval.c new file +31
-0@@ -0,0 +1,204 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +/* +* This simple implementation of a name-value store assumes a small number of +* values and fits into a small finite buffer. +* +* Each attribute is stored as a record: +* sizeof(int) bytes record size. +* strnlen+1 bytes name null terminated. +* nbytes value. +* ---------- +* total size stored in record size +* +* This code has not been tested with unicode yet. +*/ + +#include "yaffs_nameval.h" + +#include "yportenv.h" +
fs/yaffs2/yaffs_nameval.c line 41
Quoted 10 lines
fs/yaffs2/yaffs_nameval.c new file +10
-0+static int nval_find (const char *xb,int xb_size,const YCHAR *name, +int *exist_size) +{ +int pos =0 ; +int size; + +memcpy (&size, xb,sizeof (int )); +while (size >0 && (size < xb_size) && (pos + size < xb_size)) { +if (strncmp + ((YCHAR *) (xb + pos +sizeof (int )), name, size) ==0 ) {
Maybe more readable as:
YCHAR *tmp = xb + pos + sizeof(int);
if (strncmp(tmp, name, size) == 0) {
...fs/yaffs2/yaffs_nameval.c line 54
Quoted 13 lines
fs/yaffs2/yaffs_nameval.c new file +13
-0+if (exist_size) + *exist_size = size; +return pos; + } + pos += size; +if (pos < xb_size -sizeof (int )) +memcpy (&size, xb + pos,sizeof (int )); +else + size =0 ; + } +if (exist_size) + *exist_size =0 ; +return -1 ;
Return a proper errno value.
Quoted 184 lines
fs/yaffs2/yaffs_nameval.c new file +150
-0+} + +static int nval_used (const char *xb,int xb_size) +{ +int pos =0 ; +int size; + +memcpy (&size, xb + pos,sizeof (int )); +while (size >0 && (size < xb_size) && (pos + size < xb_size)) { + pos += size; +if (pos < xb_size -sizeof (int )) +memcpy (&size, xb + pos,sizeof (int )); +else + size =0 ; + } +return pos; +} + +int nval_del (char *xb,int xb_size,const YCHAR *name) +{ +int pos =nval_find (xb, xb_size, name,NULL ); +int size; + +if (pos >=0 && pos < xb_size) { +/* Find size, shift rest over this record, +* then zero out the rest of buffer */ +memcpy (&size, xb + pos,sizeof (int )); +memcpy (xb + pos, xb + pos + size, xb_size - (pos + size)); +memset (xb + (xb_size - size),0 , size); +return 0 ; + }else { +return -ENODATA ; + } +} + +int nval_set (char *xb,int xb_size,const YCHAR *name,const char *buf, +int bsize,int flags) +{ +int pos; +int namelen =strnlen (name, xb_size); +int reclen; +int size_exist =0 ; +int space; +int start; + + pos =nval_find (xb, xb_size, name, &size_exist); + +if (flags &XATTR_CREATE && pos >=0 ) +return -EEXIST ; +if (flags &XATTR_REPLACE && pos <0 ) +return -ENODATA ; + + start =nval_used (xb, xb_size); + space = xb_size - start + size_exist; + + reclen = (sizeof (int ) + namelen +1 + bsize); + +if (reclen > space) +return -ENOSPC ; + +if (pos >=0 ) { +nval_del (xb, xb_size, name); + start =nval_used (xb, xb_size); + } + + pos = start; + +memcpy (xb + pos, &reclen,sizeof (int )); + pos +=sizeof (int ); +strncpy ((YCHAR *) (xb + pos), name, reclen); + pos += (namelen +1 ); +memcpy (xb + pos, buf, bsize); +return 0 ; +} + +int nval_get (const char *xb,int xb_size,const YCHAR * name,char *buf, +int bsize) +{ +int pos =nval_find (xb, xb_size, name,NULL ); +int size; + +if (pos >=0 && pos < xb_size) { + +memcpy (&size, xb + pos,sizeof (int )); + pos +=sizeof (int );/* advance past record length */ + size -=sizeof (int ); + +/* Advance over name string */ +while (xb[pos] && size >0 && pos < xb_size) { + pos++; + size--; + } +/*Advance over NUL */ + pos++; + size--; + +if (size <= bsize) { +memcpy (buf, xb + pos, size); +return size; + } + + } +if (pos >=0 ) +return -ERANGE ; +else +return -ENODATA ; +} + +int nval_list (const char *xb,int xb_size,char *buf,int bsize) +{ +int pos =0 ; +int size; +int name_len; +int ncopied =0 ; +int filled =0 ; + +memcpy (&size, xb + pos,sizeof (int )); +while (size >sizeof (int ) && + size <= xb_size && + (pos + size) < xb_size && + !filled) { + pos +=sizeof (int ); + size -=sizeof (int ); + name_len =strnlen ((YCHAR *) (xb + pos), size); +if (ncopied + name_len +1 < bsize) { +memcpy (buf, xb + pos, name_len *sizeof (YCHAR )); + buf += name_len; + *buf ='\0' ; + buf++; +if (sizeof (YCHAR ) >1 ) { + *buf ='\0' ; + buf++; + } + ncopied += (name_len +1 ); + }else { + filled =1 ; + } + pos += size; +if (pos < xb_size -sizeof (int )) +memcpy (&size, xb + pos,sizeof (int )); +else + size =0 ; + } +return ncopied; +} + +int nval_hasvalues (const char *xb,int xb_size) +{ +return nval_used (xb, xb_size) >0 ; +}fs/yaffs2/yaffs_nameval.h new file +28
-0@@ -0,0 +1,28 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __NAMEVAL_H__ +#define __NAMEVAL_H__ + +#include "yportenv.h" + +int nval_del (char *xb,int xb_size,const YCHAR * name); +int nval_set (char *xb,int xb_size,const YCHAR * name,const char *buf, +int bsize,int flags); +int nval_get (const char *xb,int xb_size,const YCHAR * name,char *buf, +int bsize); +int nval_list (const char *xb,int xb_size,char *buf,int bsize); +int nval_hasvalues (const char *xb,int xb_size); +#endif
Signature · 7 lines
Bluewater Systems Ltd - ARM Technology Solution Centre Ryan Mallon 5 Amuri Park, 404 Barbadoes St [email protected] PO Box 13 889, Christchurch 8013 http://www.bluewatersys.com New Zealand Phone: +64 3 3779127 Freecall: Australia 1800 148 751 Fax: +64 3 3779135 USA 1800 261 2934
PATCH 3/10 Add yaffs2 file system: Checkpoint handing code
In reply to Charles Manning--- fs/yaffs2/yaffs_checkptrw.c | 407 +++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_checkptrw.h | 33 ++++ 2 files changed, 440 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_checkptrw.c create mode 100644 fs/yaffs2/yaffs_checkptrw.h
fs/yaffs2/yaffs_checkptrw.c new file +407 -0
@@ -0,0 +1,407 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_checkptrw.h" +#include "yaffs_getblockinfo.h" + +static int yaffs2_checkpt_space_ok (struct yaffs_dev *dev) +{ +int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"checkpt blocks_avail = %d" , blocks_avail); + +return (blocks_avail <=0 ) ?0 :1 ; +} + +static int yaffs_checkpt_erase (struct yaffs_dev *dev) +{ +int i; + +if (!dev->param.erase_fn) +return 0 ; +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"checking blocks %d to %d" , + dev->internal_start_block, dev->internal_end_block); + +for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { +struct yaffs_block_info *bi =yaffs_get_block_info (dev, i); +if (bi->block_state ==YAFFS_BLOCK_STATE_CHECKPOINT ) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"erasing checkpt block %d" , i); + + dev->n_erasures++; + +if (dev->param. +erase_fn (dev, + i - dev->block_offset/* realign */ )) { + bi->block_state =YAFFS_BLOCK_STATE_EMPTY ; + dev->n_erased_blocks++; + dev->n_free_chunks += + dev->param.chunks_per_block; + }else { + dev->param.bad_block_fn (dev, i); + bi->block_state =YAFFS_BLOCK_STATE_DEAD ; + } + } + } + + dev->blocks_in_checkpt =0 ; + +return 1 ; +} + +static void yaffs2_checkpt_find_erased_block (struct yaffs_dev *dev) +{ +int i; +int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"allocating checkpt block: erased %d reserved %d avail %d next %d " , + dev->n_erased_blocks, dev->param.n_reserved_blocks, + blocks_avail, dev->checkpt_next_block); + +if (dev->checkpt_next_block >=0 && + dev->checkpt_next_block <= dev->internal_end_block && + blocks_avail >0 ) { + +for (i = dev->checkpt_next_block; i <= dev->internal_end_block; + i++) { +struct yaffs_block_info *bi = +yaffs_get_block_info (dev, i); +if (bi->block_state ==YAFFS_BLOCK_STATE_EMPTY ) { + dev->checkpt_next_block = i +1 ; + dev->checkpt_cur_block = i; +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"allocating checkpt block %d" , i); +return ; + } + } + } +yaffs_trace (YAFFS_TRACE_CHECKPOINT ,"out of checkpt blocks" ); + + dev->checkpt_next_block =-1 ; + dev->checkpt_cur_block =-1 ; +} + +static void yaffs2_checkpt_find_block (struct yaffs_dev *dev) +{ +int i; +struct yaffs_ext_tags tags; + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"find next checkpt block: start: blocks %d next %d" , + dev->blocks_in_checkpt, dev->checkpt_next_block); + +if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) +for (i = dev->checkpt_next_block; i <= dev->internal_end_block; + i++) { +int chunk = i * dev->param.chunks_per_block; +int realigned_chunk = chunk - dev->chunk_offset; + + dev->param.read_chunk_tags_fn (dev, realigned_chunk, +NULL , &tags); +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"find next checkpt block: search: block %d oid %d seq %d eccr %d" , + i, tags.obj_id, tags.seq_number, + tags.ecc_result); + +if (tags.seq_number ==YAFFS_SEQUENCE_CHECKPOINT_DATA ) { +/* Right kind of block */ + dev->checkpt_next_block = tags.obj_id; + dev->checkpt_cur_block = i; + dev->checkpt_block_list[dev-> + blocks_in_checkpt] = i; + dev->blocks_in_checkpt++; +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"found checkpt block %d" , i); +return ; + } + } + +yaffs_trace (YAFFS_TRACE_CHECKPOINT ,"found no more checkpt blocks" ); + + dev->checkpt_next_block =-1 ; + dev->checkpt_cur_block =-1 ; +} + +int yaffs2_checkpt_open (struct yaffs_dev *dev,int writing) +{ + dev->checkpt_open_write = writing; + +/* Got the functions we need? */ +if (!dev->param.write_chunk_tags_fn || + !dev->param.read_chunk_tags_fn || + !dev->param.erase_fn || !dev->param.bad_block_fn) +return 0 ; + +if (writing && !yaffs2_checkpt_space_ok (dev)) +return 0 ; + +if (!dev->checkpt_buffer) + dev->checkpt_buffer = +kmalloc (dev->param.total_bytes_per_chunk,GFP_NOFS ); +if (!dev->checkpt_buffer) +return 0 ; + + dev->checkpt_page_seq =0 ; + dev->checkpt_byte_count =0 ; + dev->checkpt_sum =0 ; + dev->checkpt_xor =0 ; + dev->checkpt_cur_block =-1 ; + dev->checkpt_cur_chunk =-1 ; + dev->checkpt_next_block = dev->internal_start_block; + +/* Erase all the blocks in the checkpoint area */ +if (writing) { +memset (dev->checkpt_buffer,0 , dev->data_bytes_per_chunk); + dev->checkpt_byte_offs =0 ; +return yaffs_checkpt_erase (dev); + }else { +int i; +/* Set to a value that will kick off a read */ + dev->checkpt_byte_offs = dev->data_bytes_per_chunk; +/* A checkpoint block list of 1 checkpoint block per 16 block is +* (hopefully) going to be way more than we need */ + dev->blocks_in_checkpt =0 ; + dev->checkpt_max_blocks = + (dev->internal_end_block - dev->internal_start_block) /16 + +2 ; + dev->checkpt_block_list = +kmalloc (sizeof (int ) * dev->checkpt_max_blocks,GFP_NOFS ); +if (!dev->checkpt_block_list) +return 0 ; + +for (i =0 ; i < dev->checkpt_max_blocks; i++) + dev->checkpt_block_list[i] =-1 ; + } + +return 1 ; +} + +int yaffs2_get_checkpt_sum (struct yaffs_dev *dev,u32 * sum) +{ +u32 composite_sum; + + composite_sum = (dev->checkpt_sum <<8 ) | (dev->checkpt_xor &0xFF ); + *sum = composite_sum; +return 1 ; +} + +static int yaffs2_checkpt_flush_buffer (struct yaffs_dev *dev) +{ +int chunk; +int realigned_chunk; +struct yaffs_ext_tags tags; + +if (dev->checkpt_cur_block <0 ) { +yaffs2_checkpt_find_erased_block (dev); + dev->checkpt_cur_chunk =0 ; + } + +if (dev->checkpt_cur_block <0 ) +return 0 ; + + tags.is_deleted =0 ; + tags.obj_id = dev->checkpt_next_block;/* Hint to next place to look */ + tags.chunk_id = dev->checkpt_page_seq +1 ; + tags.seq_number =YAFFS_SEQUENCE_CHECKPOINT_DATA ; + tags.n_bytes = dev->data_bytes_per_chunk; +if (dev->checkpt_cur_chunk ==0 ) { +/* First chunk we write for the block? Set block state to +checkpoint */ +struct yaffs_block_info *bi = +yaffs_get_block_info (dev, dev->checkpt_cur_block); + bi->block_state =YAFFS_BLOCK_STATE_CHECKPOINT ; + dev->blocks_in_checkpt++; + } + + chunk = + dev->checkpt_cur_block * dev->param.chunks_per_block + + dev->checkpt_cur_chunk; + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" , + chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, + tags.obj_id, tags.chunk_id); + + realigned_chunk = chunk - dev->chunk_offset; + + dev->n_page_writes++; + + dev->param.write_chunk_tags_fn (dev, realigned_chunk, + dev->checkpt_buffer, &tags); + dev->checkpt_byte_offs =0 ; + dev->checkpt_page_seq++; + dev->checkpt_cur_chunk++; +if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) { + dev->checkpt_cur_chunk =0 ; + dev->checkpt_cur_block =-1 ; + } +memset (dev->checkpt_buffer,0 , dev->data_bytes_per_chunk); + +return 1 ; +} + +int yaffs2_checkpt_wr (struct yaffs_dev *dev,const void *data,int n_bytes) +{ +int i =0 ; +int ok =1 ; +u8 *data_bytes = (u8 *) data; + +if (!dev->checkpt_buffer) +return 0 ; + +if (!dev->checkpt_open_write) +return -1 ; + +while (i < n_bytes && ok) { + dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes; + dev->checkpt_sum += *data_bytes; + dev->checkpt_xor ^= *data_bytes; + + dev->checkpt_byte_offs++; + i++; + data_bytes++; + dev->checkpt_byte_count++; + +if (dev->checkpt_byte_offs <0 || + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) + ok =yaffs2_checkpt_flush_buffer (dev); + } + +return i; +} + +int yaffs2_checkpt_rd (struct yaffs_dev *dev,void *data,int n_bytes) +{ +int i =0 ; +int ok =1 ; +struct yaffs_ext_tags tags; +int chunk; +int realigned_chunk; +u8 *data_bytes = (u8 *) data; + +if (!dev->checkpt_buffer) +return 0 ; + +if (dev->checkpt_open_write) +return -1 ; + +while (i < n_bytes && ok) { + +if (dev->checkpt_byte_offs <0 || + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) { + +if (dev->checkpt_cur_block <0 ) { +yaffs2_checkpt_find_block (dev); + dev->checkpt_cur_chunk =0 ; + } + +if (dev->checkpt_cur_block <0 ) + ok =0 ; +else { + chunk = dev->checkpt_cur_block * + dev->param.chunks_per_block + + dev->checkpt_cur_chunk; + + realigned_chunk = chunk - dev->chunk_offset; + + dev->n_page_reads++; + +/* read in the next chunk */ + dev->param.read_chunk_tags_fn (dev, + realigned_chunk, + dev->checkpt_buffer, + &tags); + +if (tags.chunk_id != (dev->checkpt_page_seq +1 ) + || tags.ecc_result >YAFFS_ECC_RESULT_FIXED + || tags.seq_number != +YAFFS_SEQUENCE_CHECKPOINT_DATA ) + ok =0 ; + + dev->checkpt_byte_offs =0 ; + dev->checkpt_page_seq++; + dev->checkpt_cur_chunk++; + +if (dev->checkpt_cur_chunk >= + dev->param.chunks_per_block) + dev->checkpt_cur_block =-1 ; + } + } + +if (ok) { + *data_bytes = + dev->checkpt_buffer[dev->checkpt_byte_offs]; + dev->checkpt_sum += *data_bytes; + dev->checkpt_xor ^= *data_bytes; + dev->checkpt_byte_offs++; + i++; + data_bytes++; + dev->checkpt_byte_count++; + } + } + +return i; +} + +int yaffs_checkpt_close (struct yaffs_dev *dev) +{ +if (dev->checkpt_open_write) { +if (dev->checkpt_byte_offs !=0 ) +yaffs2_checkpt_flush_buffer (dev); + }else if (dev->checkpt_block_list) { +int i; +for (i =0 ; + i < dev->blocks_in_checkpt + && dev->checkpt_block_list[i] >=0 ; i++) { +int blk = dev->checkpt_block_list[i]; +struct yaffs_block_info *bi =NULL ; +if (dev->internal_start_block <= blk + && blk <= dev->internal_end_block) + bi =yaffs_get_block_info (dev, blk); +if (bi && bi->block_state ==YAFFS_BLOCK_STATE_EMPTY ) + bi->block_state =YAFFS_BLOCK_STATE_CHECKPOINT ; + } +kfree (dev->checkpt_block_list); + dev->checkpt_block_list =NULL ; + } + + dev->n_free_chunks -= + dev->blocks_in_checkpt * dev->param.chunks_per_block; + dev->n_erased_blocks -= dev->blocks_in_checkpt; + +yaffs_trace (YAFFS_TRACE_CHECKPOINT ,"checkpoint byte count %d" , + dev->checkpt_byte_count); + +if (dev->checkpt_buffer) { +/* free the buffer */ +kfree (dev->checkpt_buffer); + dev->checkpt_buffer =NULL ; +return 1 ; + }else { +return 0 ; + } +} + +int yaffs2_checkpt_invalidate_stream (struct yaffs_dev *dev) +{ +/* Erase the checkpoint data */ + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"checkpoint invalidate of %d blocks" , + dev->blocks_in_checkpt); + +return yaffs_checkpt_erase (dev); +}
fs/yaffs2/yaffs_checkptrw.h new file +33 -0
@@ -0,0 +1,33 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_CHECKPTRW_H__ +#define __YAFFS_CHECKPTRW_H__ + +#include "yaffs_guts.h" + +int yaffs2_checkpt_open (struct yaffs_dev *dev,int writing); + +int yaffs2_checkpt_wr (struct yaffs_dev *dev,const void *data,int n_bytes); + +int yaffs2_checkpt_rd (struct yaffs_dev *dev,void *data,int n_bytes); + +int yaffs2_get_checkpt_sum (struct yaffs_dev *dev,u32 * sum); + +int yaffs_checkpt_close (struct yaffs_dev *dev); + +int yaffs2_checkpt_invalidate_stream (struct yaffs_dev *dev); + +#endif
Signature · 1 line
1.7.1
Re: [PATCH 03/10] Add yaffs2 file system: Checkpoint handing code
Quoted 1 line · Charles Manning
Signed-off-by Charles Manning <[email protected]>
Comments below.
~Ryan
Quoted 27 lines
--- fs/yaffs2/yaffs_checkptrw.c | 407 +++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_checkptrw.h | 33 ++++ 2 files changed, 440 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_checkptrw.c create mode 100644 fs/yaffs2/yaffs_checkptrw.hfs/yaffs2/yaffs_checkptrw.c new file +14
-0@@ -0,0 +1,407 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_checkptrw.h"
fs/yaffs2/yaffs_checkptrw.c line 24
Quoted 10 lines
fs/yaffs2/yaffs_checkptrw.c new file +10
-0+#include "yaffs_getblockinfo.h" + +static int yaffs2_checkpt_space_ok (struct yaffs_dev *dev) +{ +int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"checkpt blocks_avail = %d" , blocks_avail); + +return (blocks_avail <=0 ) ?0 :1 ;
return blocks_avail > 0; ?
Quoted 13 lines
fs/yaffs2/yaffs_checkptrw.c new file +13
-0+} + +static int yaffs_checkpt_erase (struct yaffs_dev *dev) +{ +int i; + +if (!dev->param.erase_fn) +return 0 ; +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"checking blocks %d to %d" , + dev->internal_start_block, dev->internal_end_block); + +for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
fs/yaffs2/yaffs_checkptrw.c line 47
Quoted 10 lines
fs/yaffs2/yaffs_checkptrw.c new file +10
-0+struct yaffs_block_info *bi =yaffs_get_block_info (dev, i); +if (bi->block_state ==YAFFS_BLOCK_STATE_CHECKPOINT ) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"erasing checkpt block %d" , i); + + dev->n_erasures++; + +if (dev->param. +erase_fn (dev, + i - dev->block_offset/* realign */ )) {
Stuff like this gets really hard to read. Try not to split lines on the . operator. Move the comment to the next at least.
Quoted 67 lines
fs/yaffs2/yaffs_checkptrw.c new file +67
-0+ bi->block_state =YAFFS_BLOCK_STATE_EMPTY ; + dev->n_erased_blocks++; + dev->n_free_chunks += + dev->param.chunks_per_block; + }else { + dev->param.bad_block_fn (dev, i); + bi->block_state =YAFFS_BLOCK_STATE_DEAD ; + } + } + } + + dev->blocks_in_checkpt =0 ; + +return 1 ; +} + +static void yaffs2_checkpt_find_erased_block (struct yaffs_dev *dev) +{ +int i; +int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"allocating checkpt block: erased %d reserved %d avail %d next %d " , + dev->n_erased_blocks, dev->param.n_reserved_blocks, + blocks_avail, dev->checkpt_next_block); + +if (dev->checkpt_next_block >=0 && + dev->checkpt_next_block <= dev->internal_end_block && + blocks_avail >0 ) { + +for (i = dev->checkpt_next_block; i <= dev->internal_end_block; + i++) { +struct yaffs_block_info *bi = +yaffs_get_block_info (dev, i); +if (bi->block_state ==YAFFS_BLOCK_STATE_EMPTY ) { + dev->checkpt_next_block = i +1 ; + dev->checkpt_cur_block = i; +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"allocating checkpt block %d" , i); +return ; + } + } + } +yaffs_trace (YAFFS_TRACE_CHECKPOINT ,"out of checkpt blocks" ); + + dev->checkpt_next_block =-1 ; + dev->checkpt_cur_block =-1 ; +} + +static void yaffs2_checkpt_find_block (struct yaffs_dev *dev) +{ +int i; +struct yaffs_ext_tags tags; + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"find next checkpt block: start: blocks %d next %d" , + dev->blocks_in_checkpt, dev->checkpt_next_block); + +if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) +for (i = dev->checkpt_next_block; i <= dev->internal_end_block; + i++) { +int chunk = i * dev->param.chunks_per_block; +int realigned_chunk = chunk - dev->chunk_offset; + + dev->param.read_chunk_tags_fn (dev, realigned_chunk, +NULL , &tags); + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
fs/yaffs2/yaffs_checkptrw.c line 124
Quoted 10 lines
fs/yaffs2/yaffs_checkptrw.c new file +10
-0+"find next checkpt block: search: block %d oid %d seq %d eccr %d" , + i, tags.obj_id, tags.seq_number, + tags.ecc_result); + +if (tags.seq_number ==YAFFS_SEQUENCE_CHECKPOINT_DATA ) { +/* Right kind of block */ + dev->checkpt_next_block = tags.obj_id; + dev->checkpt_cur_block = i; + dev->checkpt_block_list[dev-> + blocks_in_checkpt] = i;
Lines like this can probably just go on one line. It will only just break the 80 columns 'limit' and it makes it a bit more readable.
Quoted 21 lines
fs/yaffs2/yaffs_checkptrw.c new file +21
-0+ dev->blocks_in_checkpt++; +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"found checkpt block %d" , i); +return ; + } + } + +yaffs_trace (YAFFS_TRACE_CHECKPOINT ,"found no more checkpt blocks" ); + + dev->checkpt_next_block =-1 ; + dev->checkpt_cur_block =-1 ; +} + +int yaffs2_checkpt_open (struct yaffs_dev *dev,int writing) +{ + dev->checkpt_open_write = writing; + +/* Got the functions we need? */ +if (!dev->param.write_chunk_tags_fn || + !dev->param.read_chunk_tags_fn || + !dev->param.erase_fn || !dev->param.bad_block_fn)
fs/yaffs2/yaffs_checkptrw.c line 155
Quoted 10 lines
fs/yaffs2/yaffs_checkptrw.c new file +10
-0+return 0 ; + +if (writing && !yaffs2_checkpt_space_ok (dev)) +return 0 ; + +if (!dev->checkpt_buffer) + dev->checkpt_buffer = +kmalloc (dev->param.total_bytes_per_chunk,GFP_NOFS ); +if (!dev->checkpt_buffer) +return 0 ;
Possibly this function should return 0 on success and a negative errno value on error?
Quoted 31 lines
fs/yaffs2/yaffs_checkptrw.c new file +31
-0+ dev->checkpt_page_seq =0 ; + dev->checkpt_byte_count =0 ; + dev->checkpt_sum =0 ; + dev->checkpt_xor =0 ; + dev->checkpt_cur_block =-1 ; + dev->checkpt_cur_chunk =-1 ; + dev->checkpt_next_block = dev->internal_start_block; + +/* Erase all the blocks in the checkpoint area */ +if (writing) { +memset (dev->checkpt_buffer,0 , dev->data_bytes_per_chunk); + dev->checkpt_byte_offs =0 ; +return yaffs_checkpt_erase (dev); + }else { +int i; +/* Set to a value that will kick off a read */ + dev->checkpt_byte_offs = dev->data_bytes_per_chunk; +/* A checkpoint block list of 1 checkpoint block per 16 block is +* (hopefully) going to be way more than we need */ + dev->blocks_in_checkpt =0 ; + dev->checkpt_max_blocks = + (dev->internal_end_block - dev->internal_start_block) /16 + +2 ; + dev->checkpt_block_list = +kmalloc (sizeof (int ) * dev->checkpt_max_blocks,GFP_NOFS ); +if (!dev->checkpt_block_list) +return 0 ; + +for (i =0 ; i < dev->checkpt_max_blocks; i++) + dev->checkpt_block_list[i] =-1 ; + }
fs/yaffs2/yaffs_checkptrw.c line 197
Quoted 10 lines
fs/yaffs2/yaffs_checkptrw.c new file +10
-0+ +return 1 ; +} + +int yaffs2_get_checkpt_sum (struct yaffs_dev *dev,u32 * sum) +{ +u32 composite_sum; + + composite_sum = (dev->checkpt_sum <<8 ) | (dev->checkpt_xor &0xFF ); + *sum = composite_sum;
You don't need the composite_sum temporary, just assign directly to *sum. The return type of this function can probably be changed to void also.
Quoted 59 lines
fs/yaffs2/yaffs_checkptrw.c new file +59
-0+return 1 ; +} + +static int yaffs2_checkpt_flush_buffer (struct yaffs_dev *dev) +{ +int chunk; +int realigned_chunk; +struct yaffs_ext_tags tags; + +if (dev->checkpt_cur_block <0 ) { +yaffs2_checkpt_find_erased_block (dev); + dev->checkpt_cur_chunk =0 ; + } + +if (dev->checkpt_cur_block <0 ) +return 0 ; + + tags.is_deleted =0 ; + tags.obj_id = dev->checkpt_next_block;/* Hint to next place to look */ + tags.chunk_id = dev->checkpt_page_seq +1 ; + tags.seq_number =YAFFS_SEQUENCE_CHECKPOINT_DATA ; + tags.n_bytes = dev->data_bytes_per_chunk; +if (dev->checkpt_cur_chunk ==0 ) { +/* First chunk we write for the block? Set block state to +checkpoint */ +struct yaffs_block_info *bi = +yaffs_get_block_info (dev, dev->checkpt_cur_block); + bi->block_state =YAFFS_BLOCK_STATE_CHECKPOINT ; + dev->blocks_in_checkpt++; + } + + chunk = + dev->checkpt_cur_block * dev->param.chunks_per_block + + dev->checkpt_cur_chunk; + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" , + chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, + tags.obj_id, tags.chunk_id); + + realigned_chunk = chunk - dev->chunk_offset; + + dev->n_page_writes++; + + dev->param.write_chunk_tags_fn (dev, realigned_chunk, + dev->checkpt_buffer, &tags); + dev->checkpt_byte_offs =0 ; + dev->checkpt_page_seq++; + dev->checkpt_cur_chunk++; +if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) { + dev->checkpt_cur_chunk =0 ; + dev->checkpt_cur_block =-1 ; + } +memset (dev->checkpt_buffer,0 , dev->data_bytes_per_chunk); + +return 1 ; +} + +int yaffs2_checkpt_wr (struct yaffs_dev *dev,const void *data,int n_bytes)
fs/yaffs2/yaffs_checkptrw.c line 266
Quoted 10 lines
fs/yaffs2/yaffs_checkptrw.c new file +10
-0+{ +int i =0 ; +int ok =1 ; +u8 *data_bytes = (u8 *) data; + +if (!dev->checkpt_buffer) +return 0 ; + +if (!dev->checkpt_open_write) +return -1 ;
errno value?
Quoted 17 lines
fs/yaffs2/yaffs_checkptrw.c new file +17
-0+ +while (i < n_bytes && ok) { + dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes; + dev->checkpt_sum += *data_bytes; + dev->checkpt_xor ^= *data_bytes; + + dev->checkpt_byte_offs++; + i++; + data_bytes++; + dev->checkpt_byte_count++; + +if (dev->checkpt_byte_offs <0 || + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) + ok =yaffs2_checkpt_flush_buffer (dev); + } + +return i;
fs/yaffs2/yaffs_checkptrw.c line 293
Quoted 10 lines
fs/yaffs2/yaffs_checkptrw.c new file +10
-0+} + +int yaffs2_checkpt_rd (struct yaffs_dev *dev,void *data,int n_bytes) +{ +int i =0 ; +int ok =1 ; +struct yaffs_ext_tags tags; +int chunk; +int realigned_chunk; +u8 *data_bytes = (u8 *) data;
Shouldn't need the cast here.
fs/yaffs2/yaffs_checkptrw.c line 299
Quoted 6 lines
fs/yaffs2/yaffs_checkptrw.c new file +6
-0+ +if (!dev->checkpt_buffer) +return 0 ; + +if (dev->checkpt_open_write) +return -1 ;
errno value?
fs/yaffs2/yaffs_checkptrw.c line 312
Quoted 13 lines
fs/yaffs2/yaffs_checkptrw.c new file +13
-0+ +while (i < n_bytes && ok) { + +if (dev->checkpt_byte_offs <0 || + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) { + +if (dev->checkpt_cur_block <0 ) { +yaffs2_checkpt_find_block (dev); + dev->checkpt_cur_chunk =0 ; + } + +if (dev->checkpt_cur_block <0 ) + ok =0 ;
The if should have braces here. If either the if or the else has braces, then both should.
fs/yaffs2/yaffs_checkptrw.c line 313
Quoted 1 line
fs/yaffs2/yaffs_checkptrw.c new file +1
-0+else {
Possibly worth moving the body of this else to a separate function to reduce indentation craziness.
Quoted 7 lines
fs/yaffs2/yaffs_checkptrw.c new file +7
-0+ chunk = dev->checkpt_cur_block * + dev->param.chunks_per_block + + dev->checkpt_cur_chunk; + + realigned_chunk = chunk - dev->chunk_offset; + + dev->n_page_reads++;
fs/yaffs2/yaffs_checkptrw.c line 330
Quoted 10 lines
fs/yaffs2/yaffs_checkptrw.c new file +10
-0+ +/* read in the next chunk */ + dev->param.read_chunk_tags_fn (dev, + realigned_chunk, + dev->checkpt_buffer, + &tags); + +if (tags.chunk_id != (dev->checkpt_page_seq +1 ) + || tags.ecc_result >YAFFS_ECC_RESULT_FIXED + || tags.seq_number !=
There is a mix of putting && and || at the end and the beginning of lines in this file. Pick one and be consistent. I think that end of line is generally preferred.
Quoted 30 lines
fs/yaffs2/yaffs_checkptrw.c new file +30
-0+ YAFFS_SEQUENCE_CHECKPOINT_DATA) + ok =0 ; + + dev->checkpt_byte_offs =0 ; + dev->checkpt_page_seq++; + dev->checkpt_cur_chunk++; + +if (dev->checkpt_cur_chunk >= + dev->param.chunks_per_block) + dev->checkpt_cur_block =-1 ; + } + } + +if (ok) { + *data_bytes = + dev->checkpt_buffer[dev->checkpt_byte_offs]; + dev->checkpt_sum += *data_bytes; + dev->checkpt_xor ^= *data_bytes; + dev->checkpt_byte_offs++; + i++; + data_bytes++; + dev->checkpt_byte_count++; + } + } + +return i; +} + +int yaffs_checkpt_close (struct yaffs_dev *dev) +{
fs/yaffs2/yaffs_checkptrw.c line 370
Quoted 10 lines
fs/yaffs2/yaffs_checkptrw.c new file +10
-0+if (dev->checkpt_open_write) { +if (dev->checkpt_byte_offs !=0 ) +yaffs2_checkpt_flush_buffer (dev); + }else if (dev->checkpt_block_list) { +int i; +for (i =0 ; + i < dev->blocks_in_checkpt + && dev->checkpt_block_list[i] >=0 ; i++) { +int blk = dev->checkpt_block_list[i]; +struct yaffs_block_info *bi =NULL ;
Blank line between variable declarations and code.
Quoted 9 lines
fs/yaffs2/yaffs_checkptrw.c new file +9
-0+if (dev->internal_start_block <= blk + && blk <= dev->internal_end_block) + bi =yaffs_get_block_info (dev, blk); +if (bi && bi->block_state ==YAFFS_BLOCK_STATE_EMPTY ) + bi->block_state =YAFFS_BLOCK_STATE_CHECKPOINT ; + } +kfree (dev->checkpt_block_list); + dev->checkpt_block_list =NULL ; + }
fs/yaffs2/yaffs_checkptrw.c line 389
Quoted 10 lines
fs/yaffs2/yaffs_checkptrw.c new file +10
-0+ + dev->n_free_chunks -= + dev->blocks_in_checkpt * dev->param.chunks_per_block; + dev->n_erased_blocks -= dev->blocks_in_checkpt; + +yaffs_trace (YAFFS_TRACE_CHECKPOINT ,"checkpoint byte count %d" , + dev->checkpt_byte_count); + +if (dev->checkpt_buffer) { +/* free the buffer */
Pointless comment :-).
fs/yaffs2/yaffs_checkptrw.c line 395
Quoted 6 lines
fs/yaffs2/yaffs_checkptrw.c new file +6
-0+kfree (dev->checkpt_buffer); + dev->checkpt_buffer =NULL ; +return 1 ; + }else { +return 0 ; + }
You don't really need the else, just put return 0 at the end of the function.
Quoted 51 lines
fs/yaffs2/yaffs_checkptrw.c new file +12
-0+} + +int yaffs2_checkpt_invalidate_stream (struct yaffs_dev *dev) +{ +/* Erase the checkpoint data */ + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"checkpoint invalidate of %d blocks" , + dev->blocks_in_checkpt); + +return yaffs_checkpt_erase (dev); +}fs/yaffs2/yaffs_checkptrw.h new file +33
-0@@ -0,0 +1,33 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_CHECKPTRW_H__ +#define __YAFFS_CHECKPTRW_H__ + +#include "yaffs_guts.h" + +int yaffs2_checkpt_open (struct yaffs_dev *dev,int writing); + +int yaffs2_checkpt_wr (struct yaffs_dev *dev,const void *data,int n_bytes); + +int yaffs2_checkpt_rd (struct yaffs_dev *dev,void *data,int n_bytes); + +int yaffs2_get_checkpt_sum (struct yaffs_dev *dev,u32 * sum); + +int yaffs_checkpt_close (struct yaffs_dev *dev); + +int yaffs2_checkpt_invalidate_stream (struct yaffs_dev *dev); + +#endif
Signature · 7 lines
Bluewater Systems Ltd - ARM Technology Solution Centre Ryan Mallon 5 Amuri Park, 404 Barbadoes St [email protected] PO Box 13 889, Christchurch 8013 http://www.bluewatersys.com New Zealand Phone: +64 3 3779127 Freecall: Australia 1800 148 751 Fax: +64 3 3779135 USA 1800 261 2934
PATCH 4/10 Add yaffs2 file system: Flash interfacing and ECC handling code
In reply to Charles Manning--- fs/yaffs2/yaffs_ecc.c | 296 +++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_ecc.h | 44 ++++++ fs/yaffs2/yaffs_mtdif.c | 53 ++++++++ fs/yaffs2/yaffs_mtdif.h | 23 ++++ fs/yaffs2/yaffs_mtdif1.c | 329 ++++++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_mtdif1.h | 29 ++++ fs/yaffs2/yaffs_mtdif2.c | 215 ++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_mtdif2.h | 29 ++++ fs/yaffs2/yaffs_nand.c | 120 +++++++++++++++++ fs/yaffs2/yaffs_nand.h | 38 ++++++ 10 files changed, 1176 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_ecc.c create mode 100644 fs/yaffs2/yaffs_ecc.h create mode 100644 fs/yaffs2/yaffs_mtdif.c create mode 100644 fs/yaffs2/yaffs_mtdif.h create mode 100644 fs/yaffs2/yaffs_mtdif1.c create mode 100644 fs/yaffs2/yaffs_mtdif1.h create mode 100644 fs/yaffs2/yaffs_mtdif2.c create mode 100644 fs/yaffs2/yaffs_mtdif2.h create mode 100644 fs/yaffs2/yaffs_nand.c create mode 100644 fs/yaffs2/yaffs_nand.h
fs/yaffs2/yaffs_ecc.c new file +296 -0
@@ -0,0 +1,296 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +/* +* This code implements the ECC algorithm used in SmartMedia. +* +* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. +* The two unused bit are set to 1. +* The ECC can correct single bit errors in a 256-byte page of data. Thus, two +* such ECC blocks are used on a 512-byte NAND page. +* +*/ + +/* Table generated by gen-ecc.c +* Using a table means we do not have to calculate p1..p4 and p1'..p4' +* for each byte of data. These are instead provided in a table in bits7..2. +* Bit 0 of each entry indicates whether the entry has an odd or even parity, +* and therefore this bytes influence on the line parity. +*/ + +#include "yportenv.h" + +#include "yaffs_ecc.h" + +static const unsigned char column_parity_table[] = { +0x00 ,0x55 ,0x59 ,0x0c ,0x65 ,0x30 ,0x3c ,0x69 , +0x69 ,0x3c ,0x30 ,0x65 ,0x0c ,0x59 ,0x55 ,0x00 , +0x95 ,0xc0 ,0xcc ,0x99 ,0xf0 ,0xa5 ,0xa9 ,0xfc , +0xfc ,0xa9 ,0xa5 ,0xf0 ,0x99 ,0xcc ,0xc0 ,0x95 , +0x99 ,0xcc ,0xc0 ,0x95 ,0xfc ,0xa9 ,0xa5 ,0xf0 , +0xf0 ,0xa5 ,0xa9 ,0xfc ,0x95 ,0xc0 ,0xcc ,0x99 , +0x0c ,0x59 ,0x55 ,0x00 ,0x69 ,0x3c ,0x30 ,0x65 , +0x65 ,0x30 ,0x3c ,0x69 ,0x00 ,0x55 ,0x59 ,0x0c , +0xa5 ,0xf0 ,0xfc ,0xa9 ,0xc0 ,0x95 ,0x99 ,0xcc , +0xcc ,0x99 ,0x95 ,0xc0 ,0xa9 ,0xfc ,0xf0 ,0xa5 , +0x30 ,0x65 ,0x69 ,0x3c ,0x55 ,0x00 ,0x0c ,0x59 , +0x59 ,0x0c ,0x00 ,0x55 ,0x3c ,0x69 ,0x65 ,0x30 , +0x3c ,0x69 ,0x65 ,0x30 ,0x59 ,0x0c ,0x00 ,0x55 , +0x55 ,0x00 ,0x0c ,0x59 ,0x30 ,0x65 ,0x69 ,0x3c , +0xa9 ,0xfc ,0xf0 ,0xa5 ,0xcc ,0x99 ,0x95 ,0xc0 , +0xc0 ,0x95 ,0x99 ,0xcc ,0xa5 ,0xf0 ,0xfc ,0xa9 , +0xa9 ,0xfc ,0xf0 ,0xa5 ,0xcc ,0x99 ,0x95 ,0xc0 , +0xc0 ,0x95 ,0x99 ,0xcc ,0xa5 ,0xf0 ,0xfc ,0xa9 , +0x3c ,0x69 ,0x65 ,0x30 ,0x59 ,0x0c ,0x00 ,0x55 , +0x55 ,0x00 ,0x0c ,0x59 ,0x30 ,0x65 ,0x69 ,0x3c , +0x30 ,0x65 ,0x69 ,0x3c ,0x55 ,0x00 ,0x0c ,0x59 , +0x59 ,0x0c ,0x00 ,0x55 ,0x3c ,0x69 ,0x65 ,0x30 , +0xa5 ,0xf0 ,0xfc ,0xa9 ,0xc0 ,0x95 ,0x99 ,0xcc , +0xcc ,0x99 ,0x95 ,0xc0 ,0xa9 ,0xfc ,0xf0 ,0xa5 , +0x0c ,0x59 ,0x55 ,0x00 ,0x69 ,0x3c ,0x30 ,0x65 , +0x65 ,0x30 ,0x3c ,0x69 ,0x00 ,0x55 ,0x59 ,0x0c , +0x99 ,0xcc ,0xc0 ,0x95 ,0xfc ,0xa9 ,0xa5 ,0xf0 , +0xf0 ,0xa5 ,0xa9 ,0xfc ,0x95 ,0xc0 ,0xcc ,0x99 , +0x95 ,0xc0 ,0xcc ,0x99 ,0xf0 ,0xa5 ,0xa9 ,0xfc , +0xfc ,0xa9 ,0xa5 ,0xf0 ,0x99 ,0xcc ,0xc0 ,0x95 , +0x00 ,0x55 ,0x59 ,0x0c ,0x65 ,0x30 ,0x3c ,0x69 , +0x69 ,0x3c ,0x30 ,0x65 ,0x0c ,0x59 ,0x55 ,0x00 , +}; + + +/* Calculate the ECC for a 256-byte block of data */ +void yaffs_ecc_cacl (const unsigned char *data,unsigned char *ecc) +{ +unsigned int i; +unsigned char col_parity =0 ; +unsigned char line_parity =0 ; +unsigned char line_parity_prime =0 ; +unsigned char t; +unsigned char b; + +for (i =0 ; i <256 ; i++) { + b = column_parity_table[*data++]; + col_parity ^= b; + +if (b &0x01 ) {/* odd number of bits in the byte */ + line_parity ^= i; + line_parity_prime ^= ~i; + } + } + + ecc[2 ] = (~col_parity) |0x03 ; + + t =0 ; +if (line_parity &0x80 ) + t |=0x80 ; +if (line_parity_prime &0x80 ) + t |=0x40 ; +if (line_parity &0x40 ) + t |=0x20 ; +if (line_parity_prime &0x40 ) + t |=0x10 ; +if (line_parity &0x20 ) + t |=0x08 ; +if (line_parity_prime &0x20 ) + t |=0x04 ; +if (line_parity &0x10 ) + t |=0x02 ; +if (line_parity_prime &0x10 ) + t |=0x01 ; + ecc[1 ] = ~t; + + t =0 ; +if (line_parity &0x08 ) + t |=0x80 ; +if (line_parity_prime &0x08 ) + t |=0x40 ; +if (line_parity &0x04 ) + t |=0x20 ; +if (line_parity_prime &0x04 ) + t |=0x10 ; +if (line_parity &0x02 ) + t |=0x08 ; +if (line_parity_prime &0x02 ) + t |=0x04 ; +if (line_parity &0x01 ) + t |=0x02 ; +if (line_parity_prime &0x01 ) + t |=0x01 ; + ecc[0 ] = ~t; + +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER +/* Swap the bytes into the wrong order */ + t = ecc[0 ]; + ecc[0 ] = ecc[1 ]; + ecc[1 ] = t; +#endif +} + +/* Correct the ECC on a 256 byte block of data */ + +int yaffs_ecc_correct (unsigned char *data,unsigned char *read_ecc, +const unsigned char *test_ecc) +{ +unsigned char d0, d1, d2;/* deltas */ + + d0 = read_ecc[0 ] ^ test_ecc[0 ]; + d1 = read_ecc[1 ] ^ test_ecc[1 ]; + d2 = read_ecc[2 ] ^ test_ecc[2 ]; + +if ((d0 | d1 | d2) ==0 ) +return 0 ;/* no error */ + +if (((d0 ^ (d0 >>1 )) &0x55 ) ==0x55 && + ((d1 ^ (d1 >>1 )) &0x55 ) ==0x55 && + ((d2 ^ (d2 >>1 )) &0x54 ) ==0x54 ) { +/* Single bit (recoverable) error in data */ + +unsigned byte; +unsigned bit; + +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER +/* swap the bytes to correct for the wrong order */ +unsigned char t; + + t = d0; + d0 = d1; + d1 = t; +#endif + + bit = byte =0 ; + +if (d1 &0x80 ) + byte |=0x80 ; +if (d1 &0x20 ) + byte |=0x40 ; +if (d1 &0x08 ) + byte |=0x20 ; +if (d1 &0x02 ) + byte |=0x10 ; +if (d0 &0x80 ) + byte |=0x08 ; +if (d0 &0x20 ) + byte |=0x04 ; +if (d0 &0x08 ) + byte |=0x02 ; +if (d0 &0x02 ) + byte |=0x01 ; + +if (d2 &0x80 ) + bit |=0x04 ; +if (d2 &0x20 ) + bit |=0x02 ; +if (d2 &0x08 ) + bit |=0x01 ; + + data[byte] ^= (1 << bit); + +return 1 ;/* Corrected the error */ + } + +if ((hweight8 (d0) +hweight8 (d1) +hweight8 (d2)) ==1 ) { +/* Reccoverable error in ecc */ + + read_ecc[0 ] = test_ecc[0 ]; + read_ecc[1 ] = test_ecc[1 ]; + read_ecc[2 ] = test_ecc[2 ]; + +return 1 ;/* Corrected the error */ + } + +/* Unrecoverable error */ + +return -1 ; + +} + +/* +* ECCxxxOther does ECC calcs on arbitrary n bytes of data +*/ +void yaffs_ecc_calc_other (const unsigned char *data,unsigned n_bytes, +struct yaffs_ecc_other *ecc_other) +{ +unsigned int i; +unsigned char col_parity =0 ; +unsigned line_parity =0 ; +unsigned line_parity_prime =0 ; +unsigned char b; + +for (i =0 ; i < n_bytes; i++) { + b = column_parity_table[*data++]; + col_parity ^= b; + +if (b &0x01 ) { +/* odd number of bits in the byte */ + line_parity ^= i; + line_parity_prime ^= ~i; + } + + } + + ecc_other->col_parity = (col_parity >>2 ) &0x3f ; + ecc_other->line_parity = line_parity; + ecc_other->line_parity_prime = line_parity_prime; +} + +int yaffs_ecc_correct_other (unsigned char *data,unsigned n_bytes, +struct yaffs_ecc_other *read_ecc, +const struct yaffs_ecc_other *test_ecc) +{ +unsigned char delta_col;/* column parity delta */ +unsigned delta_line;/* line parity delta */ +unsigned delta_line_prime;/* line parity delta */ +unsigned bit; + + delta_col = read_ecc->col_parity ^ test_ecc->col_parity; + delta_line = read_ecc->line_parity ^ test_ecc->line_parity; + delta_line_prime = + read_ecc->line_parity_prime ^ test_ecc->line_parity_prime; + +if ((delta_col | delta_line | delta_line_prime) ==0 ) +return 0 ;/* no error */ + +if (delta_line == ~delta_line_prime && + (((delta_col ^ (delta_col >>1 )) &0x15 ) ==0x15 )) { +/* Single bit (recoverable) error in data */ + + bit =0 ; + +if (delta_col &0x20 ) + bit |=0x04 ; +if (delta_col &0x08 ) + bit |=0x02 ; +if (delta_col &0x02 ) + bit |=0x01 ; + +if (delta_line >= n_bytes) +return -1 ; + + data[delta_line] ^= (1 << bit); + +return 1 ;/* corrected */ + } + +if ((hweight32 (delta_line) + +hweight32 (delta_line_prime) + +hweight8 (delta_col)) ==1 ) { +/* Reccoverable error in ecc */ + + *read_ecc = *test_ecc; +return 1 ;/* corrected */ + } + +/* Unrecoverable error */ + +return -1 ; +}
fs/yaffs2/yaffs_ecc.h new file +44 -0
44 lines not on this page · raw message
fs/yaffs2/yaffs_mtdif.c new file +53 -0
53 lines not on this page · raw message
fs/yaffs2/yaffs_mtdif.h new file +23 -0
@@ -0,0 +1,23 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_MTDIF_H__ +#define __YAFFS_MTDIF_H__ + +#include "yaffs_guts.h" + +int nandmtd_erase_block (struct yaffs_dev *dev,int block_no); +int nandmtd_initialise (struct yaffs_dev *dev); +#endif
fs/yaffs2/yaffs_mtdif1.c new file +329 -0
329 lines not on this page · raw message
fs/yaffs2/yaffs_mtdif1.h new file +29 -0
@@ -0,0 +1,29 @@ +/* +* YAFFS: Yet another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_MTDIF1_H__ +#define __YAFFS_MTDIF1_H__ + +int nandmtd1_write_chunk_tags (struct yaffs_dev *dev,int nand_chunk, +const u8 *data, +const struct yaffs_ext_tags *tags); + +int nandmtd1_read_chunk_tags (struct yaffs_dev *dev,int nand_chunk, +u8 *data,struct yaffs_ext_tags *tags); + +int nandmtd1_mark_block_bad (struct yaffs_dev *dev,int block_no); + +int nandmtd1_query_block (struct yaffs_dev *dev,int block_no, +enum yaffs_block_state *state,u32 *seq_number); + +#endif
fs/yaffs2/yaffs_mtdif2.c new file +215 -0
215 lines not on this page · raw message
fs/yaffs2/yaffs_mtdif2.h new file +29 -0
@@ -0,0 +1,29 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_MTDIF2_H__ +#define __YAFFS_MTDIF2_H__ + +#include "yaffs_guts.h" +int nandmtd2_write_chunk_tags (struct yaffs_dev *dev,int nand_chunk, +const u8 *data, +const struct yaffs_ext_tags *tags); +int nandmtd2_read_chunk_tags (struct yaffs_dev *dev,int nand_chunk, +u8 *data,struct yaffs_ext_tags *tags); +int nandmtd2_mark_block_bad (struct yaffs_dev *dev,int block_no); +int nandmtd2_query_block (struct yaffs_dev *dev,int block_no, +enum yaffs_block_state *state,u32 *seq_number); + +#endif
fs/yaffs2/yaffs_nand.c new file +120 -0
120 lines not on this page · raw message
fs/yaffs2/yaffs_nand.h new file +38 -0
@@ -0,0 +1,38 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_NAND_H__ +#define __YAFFS_NAND_H__ +#include "yaffs_guts.h" + +int yaffs_rd_chunk_tags_nand (struct yaffs_dev *dev,int nand_chunk, +u8 *buffer,struct yaffs_ext_tags *tags); + +int yaffs_wr_chunk_tags_nand (struct yaffs_dev *dev, +int nand_chunk, +const u8 *buffer,struct yaffs_ext_tags *tags); + +int yaffs_mark_bad (struct yaffs_dev *dev,int block_no); + +int yaffs_query_init_block_state (struct yaffs_dev *dev, +int block_no, +enum yaffs_block_state *state, +unsigned *seq_number); + +int yaffs_erase_block (struct yaffs_dev *dev,int flash_block); + +int yaffs_init_nand (struct yaffs_dev *dev); + +#endif
Signature · 1 line
1.7.1
Re: [PATCH 04/10] Add yaffs2 file system: Flash interfacing and ECC handling code
Quoted 1 line · Charles Manning
Signed-off-by Charles Manning <[email protected]>
Hi Charles,
Is it possible to make features like yaffs doing its own ecc, ecc wrong order and 9 byte tags mount options? It would reduce the number of Kconfig options and the amount of ifdefery in these files.
More comments below.
~Ryan
Quoted 232 lines
--- fs/yaffs2/yaffs_ecc.c | 296 +++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_ecc.h | 44 ++++++ fs/yaffs2/yaffs_mtdif.c | 53 ++++++++ fs/yaffs2/yaffs_mtdif.h | 23 ++++ fs/yaffs2/yaffs_mtdif1.c | 329 ++++++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_mtdif1.h | 29 ++++ fs/yaffs2/yaffs_mtdif2.c | 215 ++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_mtdif2.h | 29 ++++ fs/yaffs2/yaffs_nand.c | 120 +++++++++++++++++ fs/yaffs2/yaffs_nand.h | 38 ++++++ 10 files changed, 1176 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_ecc.c create mode 100644 fs/yaffs2/yaffs_ecc.h create mode 100644 fs/yaffs2/yaffs_mtdif.c create mode 100644 fs/yaffs2/yaffs_mtdif.h create mode 100644 fs/yaffs2/yaffs_mtdif1.c create mode 100644 fs/yaffs2/yaffs_mtdif1.h create mode 100644 fs/yaffs2/yaffs_mtdif2.c create mode 100644 fs/yaffs2/yaffs_mtdif2.h create mode 100644 fs/yaffs2/yaffs_nand.c create mode 100644 fs/yaffs2/yaffs_nand.hfs/yaffs2/yaffs_ecc.c new file +203
-0@@ -0,0 +1,296 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +/* +* This code implements the ECC algorithm used in SmartMedia. +* +* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. +* The two unused bit are set to 1. +* The ECC can correct single bit errors in a 256-byte page of data. Thus, two +* such ECC blocks are used on a 512-byte NAND page. +* +*/ + +/* Table generated by gen-ecc.c +* Using a table means we do not have to calculate p1..p4 and p1'..p4' +* for each byte of data. These are instead provided in a table in bits7..2. +* Bit 0 of each entry indicates whether the entry has an odd or even parity, +* and therefore this bytes influence on the line parity. +*/ + +#include "yportenv.h" + +#include "yaffs_ecc.h" + +static const unsigned char column_parity_table[] = { +0x00 ,0x55 ,0x59 ,0x0c ,0x65 ,0x30 ,0x3c ,0x69 , +0x69 ,0x3c ,0x30 ,0x65 ,0x0c ,0x59 ,0x55 ,0x00 , +0x95 ,0xc0 ,0xcc ,0x99 ,0xf0 ,0xa5 ,0xa9 ,0xfc , +0xfc ,0xa9 ,0xa5 ,0xf0 ,0x99 ,0xcc ,0xc0 ,0x95 , +0x99 ,0xcc ,0xc0 ,0x95 ,0xfc ,0xa9 ,0xa5 ,0xf0 , +0xf0 ,0xa5 ,0xa9 ,0xfc ,0x95 ,0xc0 ,0xcc ,0x99 , +0x0c ,0x59 ,0x55 ,0x00 ,0x69 ,0x3c ,0x30 ,0x65 , +0x65 ,0x30 ,0x3c ,0x69 ,0x00 ,0x55 ,0x59 ,0x0c , +0xa5 ,0xf0 ,0xfc ,0xa9 ,0xc0 ,0x95 ,0x99 ,0xcc , +0xcc ,0x99 ,0x95 ,0xc0 ,0xa9 ,0xfc ,0xf0 ,0xa5 , +0x30 ,0x65 ,0x69 ,0x3c ,0x55 ,0x00 ,0x0c ,0x59 , +0x59 ,0x0c ,0x00 ,0x55 ,0x3c ,0x69 ,0x65 ,0x30 , +0x3c ,0x69 ,0x65 ,0x30 ,0x59 ,0x0c ,0x00 ,0x55 , +0x55 ,0x00 ,0x0c ,0x59 ,0x30 ,0x65 ,0x69 ,0x3c , +0xa9 ,0xfc ,0xf0 ,0xa5 ,0xcc ,0x99 ,0x95 ,0xc0 , +0xc0 ,0x95 ,0x99 ,0xcc ,0xa5 ,0xf0 ,0xfc ,0xa9 , +0xa9 ,0xfc ,0xf0 ,0xa5 ,0xcc ,0x99 ,0x95 ,0xc0 , +0xc0 ,0x95 ,0x99 ,0xcc ,0xa5 ,0xf0 ,0xfc ,0xa9 , +0x3c ,0x69 ,0x65 ,0x30 ,0x59 ,0x0c ,0x00 ,0x55 , +0x55 ,0x00 ,0x0c ,0x59 ,0x30 ,0x65 ,0x69 ,0x3c , +0x30 ,0x65 ,0x69 ,0x3c ,0x55 ,0x00 ,0x0c ,0x59 , +0x59 ,0x0c ,0x00 ,0x55 ,0x3c ,0x69 ,0x65 ,0x30 , +0xa5 ,0xf0 ,0xfc ,0xa9 ,0xc0 ,0x95 ,0x99 ,0xcc , +0xcc ,0x99 ,0x95 ,0xc0 ,0xa9 ,0xfc ,0xf0 ,0xa5 , +0x0c ,0x59 ,0x55 ,0x00 ,0x69 ,0x3c ,0x30 ,0x65 , +0x65 ,0x30 ,0x3c ,0x69 ,0x00 ,0x55 ,0x59 ,0x0c , +0x99 ,0xcc ,0xc0 ,0x95 ,0xfc ,0xa9 ,0xa5 ,0xf0 , +0xf0 ,0xa5 ,0xa9 ,0xfc ,0x95 ,0xc0 ,0xcc ,0x99 , +0x95 ,0xc0 ,0xcc ,0x99 ,0xf0 ,0xa5 ,0xa9 ,0xfc , +0xfc ,0xa9 ,0xa5 ,0xf0 ,0x99 ,0xcc ,0xc0 ,0x95 , +0x00 ,0x55 ,0x59 ,0x0c ,0x65 ,0x30 ,0x3c ,0x69 , +0x69 ,0x3c ,0x30 ,0x65 ,0x0c ,0x59 ,0x55 ,0x00 , +}; + + +/* Calculate the ECC for a 256-byte block of data */ +void yaffs_ecc_cacl (const unsigned char *data,unsigned char *ecc) +{ +unsigned int i; +unsigned char col_parity =0 ; +unsigned char line_parity =0 ; +unsigned char line_parity_prime =0 ; +unsigned char t; +unsigned char b; + +for (i =0 ; i <256 ; i++) { + b = column_parity_table[*data++]; + col_parity ^= b; + +if (b &0x01 ) {/* odd number of bits in the byte */ + line_parity ^= i; + line_parity_prime ^= ~i; + } + } + + ecc[2 ] = (~col_parity) |0x03 ; + + t =0 ; +if (line_parity &0x80 ) + t |=0x80 ; +if (line_parity_prime &0x80 ) + t |=0x40 ; +if (line_parity &0x40 ) + t |=0x20 ; +if (line_parity_prime &0x40 ) + t |=0x10 ; +if (line_parity &0x20 ) + t |=0x08 ; +if (line_parity_prime &0x20 ) + t |=0x04 ; +if (line_parity &0x10 ) + t |=0x02 ; +if (line_parity_prime &0x10 ) + t |=0x01 ; + ecc[1 ] = ~t; + + t =0 ; +if (line_parity &0x08 ) + t |=0x80 ; +if (line_parity_prime &0x08 ) + t |=0x40 ; +if (line_parity &0x04 ) + t |=0x20 ; +if (line_parity_prime &0x04 ) + t |=0x10 ; +if (line_parity &0x02 ) + t |=0x08 ; +if (line_parity_prime &0x02 ) + t |=0x04 ; +if (line_parity &0x01 ) + t |=0x02 ; +if (line_parity_prime &0x01 ) + t |=0x01 ; + ecc[0 ] = ~t; + +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER +/* Swap the bytes into the wrong order */ + t = ecc[0 ]; + ecc[0 ] = ecc[1 ]; + ecc[1 ] = t; +#endif +} + +/* Correct the ECC on a 256 byte block of data */ + +int yaffs_ecc_correct (unsigned char *data,unsigned char *read_ecc, +const unsigned char *test_ecc) +{ +unsigned char d0, d1, d2;/* deltas */ + + d0 = read_ecc[0 ] ^ test_ecc[0 ]; + d1 = read_ecc[1 ] ^ test_ecc[1 ]; + d2 = read_ecc[2 ] ^ test_ecc[2 ]; + +if ((d0 | d1 | d2) ==0 ) +return 0 ;/* no error */ + +if (((d0 ^ (d0 >>1 )) &0x55 ) ==0x55 && + ((d1 ^ (d1 >>1 )) &0x55 ) ==0x55 && + ((d2 ^ (d2 >>1 )) &0x54 ) ==0x54 ) { +/* Single bit (recoverable) error in data */ + +unsigned byte; +unsigned bit; + +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER +/* swap the bytes to correct for the wrong order */ +unsigned char t; + + t = d0; + d0 = d1; + d1 = t; +#endif + + bit = byte =0 ; + +if (d1 &0x80 ) + byte |=0x80 ; +if (d1 &0x20 ) + byte |=0x40 ; +if (d1 &0x08 ) + byte |=0x20 ; +if (d1 &0x02 ) + byte |=0x10 ; +if (d0 &0x80 ) + byte |=0x08 ; +if (d0 &0x20 ) + byte |=0x04 ; +if (d0 &0x08 ) + byte |=0x02 ; +if (d0 &0x02 ) + byte |=0x01 ; + +if (d2 &0x80 ) + bit |=0x04 ; +if (d2 &0x20 ) + bit |=0x02 ; +if (d2 &0x08 ) + bit |=0x01 ; + + data[byte] ^= (1 << bit); + +return 1 ;/* Corrected the error */ + } + +if ((hweight8 (d0) +hweight8 (d1) +hweight8 (d2)) ==1 ) { +/* Reccoverable error in ecc */ +
fs/yaffs2/yaffs_ecc.c line 213
Quoted 10 lines
fs/yaffs2/yaffs_ecc.c new file +10
-0+ read_ecc[0 ] = test_ecc[0 ]; + read_ecc[1 ] = test_ecc[1 ]; + read_ecc[2 ] = test_ecc[2 ]; + +return 1 ;/* Corrected the error */ + } + +/* Unrecoverable error */ + +return -1 ;
errno value?
Quoted 71 lines
fs/yaffs2/yaffs_ecc.c new file +71
-0+} + +/* +* ECCxxxOther does ECC calcs on arbitrary n bytes of data +*/ +void yaffs_ecc_calc_other (const unsigned char *data,unsigned n_bytes, +struct yaffs_ecc_other *ecc_other) +{ +unsigned int i; +unsigned char col_parity =0 ; +unsigned line_parity =0 ; +unsigned line_parity_prime =0 ; +unsigned char b; + +for (i =0 ; i < n_bytes; i++) { + b = column_parity_table[*data++]; + col_parity ^= b; + +if (b &0x01 ) { +/* odd number of bits in the byte */ + line_parity ^= i; + line_parity_prime ^= ~i; + } + + } + + ecc_other->col_parity = (col_parity >>2 ) &0x3f ; + ecc_other->line_parity = line_parity; + ecc_other->line_parity_prime = line_parity_prime; +} + +int yaffs_ecc_correct_other (unsigned char *data,unsigned n_bytes, +struct yaffs_ecc_other *read_ecc, +const struct yaffs_ecc_other *test_ecc) +{ +unsigned char delta_col;/* column parity delta */ +unsigned delta_line;/* line parity delta */ +unsigned delta_line_prime;/* line parity delta */ +unsigned bit; + + delta_col = read_ecc->col_parity ^ test_ecc->col_parity; + delta_line = read_ecc->line_parity ^ test_ecc->line_parity; + delta_line_prime = + read_ecc->line_parity_prime ^ test_ecc->line_parity_prime; + +if ((delta_col | delta_line | delta_line_prime) ==0 ) +return 0 ;/* no error */ + +if (delta_line == ~delta_line_prime && + (((delta_col ^ (delta_col >>1 )) &0x15 ) ==0x15 )) { +/* Single bit (recoverable) error in data */ + + bit =0 ; + +if (delta_col &0x20 ) + bit |=0x04 ; +if (delta_col &0x08 ) + bit |=0x02 ; +if (delta_col &0x02 ) + bit |=0x01 ; + +if (delta_line >= n_bytes) +return -1 ; + + data[delta_line] ^= (1 << bit); + +return 1 ;/* corrected */ + } + + if ((hweight32(delta_line) + + hweight32(delta_line_prime) +
fs/yaffs2/yaffs_ecc.c line 295
Quoted 10 lines
fs/yaffs2/yaffs_ecc.c new file +10
-0+ hweight8(delta_col)) == 1) { +/* Reccoverable error in ecc */ + + *read_ecc = *test_ecc; +return 1 ;/* corrected */ + } + +/* Unrecoverable error */ + +return -1 ;
errno value?
Quoted 87 lines
fs/yaffs2/yaffs_ecc.c new file +1
-0+}fs/yaffs2/yaffs_ecc.h new file +44
-0@@ -0,0 +1,44 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +/* +* This code implements the ECC algorithm used in SmartMedia. +* +* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. +* The two unused bit are set to 1. +* The ECC can correct single bit errors in a 256-byte page of data. +* Thus, two such ECC blocks are used on a 512-byte NAND page. +* +*/ + +#ifndef __YAFFS_ECC_H__ +#define __YAFFS_ECC_H__ + +struct yaffs_ecc_other { +unsigned char col_parity; +unsigned line_parity; +unsigned line_parity_prime; +}; + +void yaffs_ecc_cacl (const unsigned char *data,unsigned char *ecc); +int yaffs_ecc_correct (unsigned char *data,unsigned char *read_ecc, +const unsigned char *test_ecc); + +void yaffs_ecc_calc_other (const unsigned char *data,unsigned n_bytes, +struct yaffs_ecc_other *ecc); +int yaffs_ecc_correct_other (unsigned char *data,unsigned n_bytes, +struct yaffs_ecc_other *read_ecc, +const struct yaffs_ecc_other *test_ecc); +#endif fs/yaffs2/yaffs_mtdif.c new file +30
-0@@ -0,0 +1,53 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yportenv.h" + +#include "yaffs_mtdif.h" + +#include "linux/mtd/mtd.h" +#include "linux/types.h" +#include "linux/time.h" +#include "linux/mtd/nand.h" + +#include "yaffs_linux.h" + +int nandmtd_erase_block (struct yaffs_dev *dev,int block_no) +{ +struct mtd_info *mtd =yaffs_dev_to_mtd (dev); +u32 addr = + ((loff_t ) block_no) * dev->param.total_bytes_per_chunk + * dev->param.chunks_per_block;
fs/yaffs2/yaffs_mtdif.c line 40
Quoted 10 lines
fs/yaffs2/yaffs_mtdif.c new file +10
-0+struct erase_info ei; +int retval =0 ; + + ei.mtd = mtd; + ei.addr = addr; + ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block; + ei.time =1000 ; + ei.retries =2 ; + ei.callback =NULL ; + ei.priv = (u_long ) dev;
Nitpick: Casts should be written like this:
ei.prov = (u_long)dev;
This applies across the whole patch series.
Quoted 116 lines
fs/yaffs2/yaffs_mtdif.c new file +13
-0+ + retval = mtd->erase (mtd, &ei); + +if (retval ==0 ) +return YAFFS_OK ; +else +return YAFFS_FAIL ; +} + +int nandmtd_initialise (struct yaffs_dev *dev) +{ +return YAFFS_OK ; +}fs/yaffs2/yaffs_mtdif.h new file +23
-0@@ -0,0 +1,23 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_MTDIF_H__ +#define __YAFFS_MTDIF_H__ + +#include "yaffs_guts.h" + +int nandmtd_erase_block (struct yaffs_dev *dev,int block_no); +int nandmtd_initialise (struct yaffs_dev *dev); +#endif fs/yaffs2/yaffs_mtdif1.c new file +68
-0@@ -0,0 +1,329 @@ +/* +* YAFFS: Yet another FFS. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +/* +* This module provides the interface between yaffs_nand.c and the +* MTD API. This version is used when the MTD interface supports the +* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17, +* and we have small-page NAND device. +* +* These functions are invoked via function pointers in yaffs_nand.c. +* This replaces functionality provided by functions in yaffs_mtdif.c +* and the yaffs_tags compatability functions in yaffs_tagscompat.c that are +* called in yaffs_mtdif.c when the function pointers are NULL. +* We assume the MTD layer is performing ECC (use_nand_ecc is true). +*/ + +#include "yportenv.h" +#include "yaffs_trace.h" +#include "yaffs_guts.h" +#include "yaffs_packedtags1.h" +#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */ +#include "yaffs_linux.h" +#include "linux/kernel.h" +#include "linux/version.h" +#include "linux/types.h" +#include "linux/mtd/mtd.h" + +#ifndef CONFIG_YAFFS_9BYTE_TAGS +# define YTAG1_SIZE 8 +#else +# define YTAG1_SIZE 9 +#endif + +/* Write a chunk (page) of data to NAND. +* +* Caller always provides ExtendedTags data which are converted to a more +* compact (packed) form for storage in NAND. A mini-ECC runs over the +* contents of the tags meta-data; used to valid the tags when read. +* +* - Pack ExtendedTags to packed_tags1 form +* - Compute mini-ECC for packed_tags1 +* - Write data and packed tags to NAND. +* +* Note: Due to the use of the packed_tags1 meta-data which does not include +* a full sequence number (as found in the larger packed_tags2 form) it is +* necessary for Yaffs to re-write a chunk/page (just once) to mark it as +* discarded and dirty. This is not ideal: newer NAND parts are supposed +* to be written just once. When Yaffs performs this operation, this +* function is called with a NULL data pointer -- calling MTD write_oob +* without data is valid usage (2.6.17). +* +* Any underlying MTD error results in YAFFS_FAIL. +* Returns YAFFS_OK or YAFFS_FAIL. +*/ +int nandmtd1_write_chunk_tags (struct yaffs_dev *dev, +int nand_chunk,const u8 *data, +const struct yaffs_ext_tags *etags) +{
fs/yaffs2/yaffs_mtdif1.c line 78
Quoted 10 lines
fs/yaffs2/yaffs_mtdif1.c new file +10
-0+struct mtd_info *mtd =yaffs_dev_to_mtd (dev); +int chunk_bytes = dev->data_bytes_per_chunk; +loff_t addr = ((loff_t ) nand_chunk) * chunk_bytes; +struct mtd_oob_ops ops; +struct yaffs_packed_tags1 pt1; +int retval; + +/* we assume that packed_tags1 and struct yaffs_tags are compatible */ +compile_time_assertion (sizeof (struct yaffs_packed_tags1 ) ==12 ); +compile_time_assertion (sizeof (struct yaffs_tags ) ==8 );
Can use one of the BUILD_BUG_ON macros rather than rolling your own?
Quoted 64 lines
fs/yaffs2/yaffs_mtdif1.c new file +64
-0+ +yaffs_pack_tags1 (&pt1, etags); +yaffs_calc_tags_ecc ((struct yaffs_tags *)&pt1); + +/* When deleting a chunk, the upper layer provides only skeletal +* etags, one with is_deleted set. However, we need to update the +* tags, not erase them completely. So we use the NAND write property +* that only zeroed-bits stick and set tag bytes to all-ones and +* zero just the (not) deleted bit. +*/ +#ifndef CONFIG_YAFFS_9BYTE_TAGS +if (etags->is_deleted) { +memset (&pt1,0xff ,8 ); +/* clear delete status bit to indicate deleted */ + pt1.deleted =0 ; + } +#else + ((u8 *) &pt1)[8 ] =0xff ; +if (etags->is_deleted) { +memset (&pt1,0xff ,8 ); +/* zero page_status byte to indicate deleted */ + ((u8 *) &pt1)[8 ] =0 ; + } +#endif + +memset (&ops,0 ,sizeof (ops)); + ops.mode =MTD_OOB_AUTO ; + ops.len = (data) ? chunk_bytes :0 ; + ops.ooblen =YTAG1_SIZE ; + ops.datbuf = (u8 *) data; + ops.oobbuf = (u8 *) &pt1; + + retval = mtd->write_oob (mtd, addr, &ops); +if (retval) { +yaffs_trace (YAFFS_TRACE_MTD , +"write_oob failed, chunk %d, mtd error %d" , + nand_chunk, retval); + } +return retval ?YAFFS_FAIL :YAFFS_OK ; +} + +/* Return with empty ExtendedTags but add ecc_result. +*/ +static int rettags (struct yaffs_ext_tags *etags,int ecc_result,int retval) +{ +if (etags) { +memset (etags,0 ,sizeof (*etags)); + etags->ecc_result = ecc_result; + } +return retval; +} + +/* Read a chunk (page) from NAND. +* +* Caller expects ExtendedTags data to be usable even on error; that is, +* all members except ecc_result and block_bad are zeroed. +* +* - Check ECC results for data (if applicable) +* - Check for blank/erased block (return empty ExtendedTags if blank) +* - Check the packed_tags1 mini-ECC (correct if necessary/possible) +* - Convert packed_tags1 to ExtendedTags +* - Update ecc_result and block_bad members to refect state. +* +* Returns YAFFS_OK or YAFFS_FAIL.
fs/yaffs2/yaffs_mtdif1.c line 152
Quoted 10 lines
fs/yaffs2/yaffs_mtdif1.c new file +10
-0+*/ +int nandmtd1_read_chunk_tags (struct yaffs_dev *dev, +int nand_chunk,u8 *data, +struct yaffs_ext_tags *etags) +{ +struct mtd_info *mtd =yaffs_dev_to_mtd (dev); +int chunk_bytes = dev->data_bytes_per_chunk; +loff_t addr = ((loff_t ) nand_chunk) * chunk_bytes; +int eccres =YAFFS_ECC_RESULT_NO_ERROR ; +struct mtd_oob_ops ops;
Change this to:
struct mtd_oob_ops ops = {0};fs/yaffs2/yaffs_mtdif1.c line 157
Quoted 5 lines
fs/yaffs2/yaffs_mtdif1.c new file +5
-0+struct yaffs_packed_tags1 pt1; +int retval; +int deleted; + +memset (&ops,0 ,sizeof (ops));
and then remove this memset.
Quoted 103 lines
fs/yaffs2/yaffs_mtdif1.c new file +103
-0+ ops.mode =MTD_OOB_AUTO ; + ops.len = (data) ? chunk_bytes :0 ; + ops.ooblen =YTAG1_SIZE ; + ops.datbuf = data; + ops.oobbuf = (u8 *) &pt1; + +/* Read page and oob using MTD. +* Check status and determine ECC result. +*/ + retval = mtd->read_oob (mtd, addr, &ops); +if (retval) { +yaffs_trace (YAFFS_TRACE_MTD , +"read_oob failed, chunk %d, mtd error %d" , + nand_chunk, retval); + } + +switch (retval) { +case 0 : +/* no error */ +break ; + +case -EUCLEAN : +/* MTD's ECC fixed the data */ + eccres =YAFFS_ECC_RESULT_FIXED ; + dev->n_ecc_fixed++; +break ; + +case -EBADMSG : +/* MTD's ECC could not fix the data */ + dev->n_ecc_unfixed++; +/* fall into... */ +default : +rettags (etags,YAFFS_ECC_RESULT_UNFIXED ,0 ); + etags->block_bad = (mtd->block_isbad) (mtd, addr); +return YAFFS_FAIL ; + } + +/* Check for a blank/erased chunk. +*/ +if (yaffs_check_ff ((u8 *) &pt1,8 )) { +/* when blank, upper layers want ecc_result to be <= NO_ERROR */ +return rettags (etags,YAFFS_ECC_RESULT_NO_ERROR ,YAFFS_OK ); + } +#ifndef CONFIG_YAFFS_9BYTE_TAGS +/* Read deleted status (bit) then return it to it's non-deleted +* state before performing tags mini-ECC check. pt1.deleted is +* inverted. +*/ + deleted = !pt1.deleted; + pt1.deleted =1 ; +#else + deleted = (hweight8 (((u8 *) &pt1)[8 ]) <7 ); +#endif + +/* Check the packed tags mini-ECC and correct if necessary/possible. +*/ + retval =yaffs_check_tags_ecc ((struct yaffs_tags *)&pt1); +switch (retval) { +case 0 : +/* no tags error, use MTD result */ +break ; +case 1 : +/* recovered tags-ECC error */ + dev->n_tags_ecc_fixed++; +if (eccres ==YAFFS_ECC_RESULT_NO_ERROR ) + eccres =YAFFS_ECC_RESULT_FIXED ; +break ; +default : +/* unrecovered tags-ECC error */ + dev->n_tags_ecc_unfixed++; +return rettags (etags,YAFFS_ECC_RESULT_UNFIXED ,YAFFS_FAIL ); + } + +/* Unpack the tags to extended form and set ECC result. +* [set should_be_ff just to keep yaffs_unpack_tags1 happy] +*/ + pt1.should_be_ff =0xFFFFFFFF ; +yaffs_unpack_tags1 (etags, &pt1); + etags->ecc_result = eccres; + +/* Set deleted state */ + etags->is_deleted = deleted; +return YAFFS_OK ; +} + +/* Mark a block bad. +* +* This is a persistant state. +* Use of this function should be rare. +* +* Returns YAFFS_OK or YAFFS_FAIL. +*/ +int nandmtd1_mark_block_bad (struct yaffs_dev *dev,int block_no) +{ +struct mtd_info *mtd =yaffs_dev_to_mtd (dev); +int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk; +int retval; + +yaffs_trace (YAFFS_TRACE_BAD_BLOCKS , +"marking block %d bad" , block_no); + + retval = mtd->block_markbad (mtd, (loff_t ) blocksize * block_no); +return (retval) ?YAFFS_FAIL :YAFFS_OK ;
fs/yaffs2/yaffs_mtdif1.c line 270
Quoted 10 lines
fs/yaffs2/yaffs_mtdif1.c new file +10
-0+} + +/* Check any MTD prerequists. +* +* Returns YAFFS_OK or YAFFS_FAIL. +*/ +static int nandmtd1_test_prerequists (struct mtd_info *mtd) +{ +/* 2.6.18 has mtd->ecclayout->oobavail */ +/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
This comment is not applicable for mainline.
Quoted 132 lines
fs/yaffs2/yaffs_mtdif1.c new file +59
-0+int oobavail = mtd->ecclayout->oobavail; + +if (oobavail <YTAG1_SIZE ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"mtd device has only %d bytes for tags, need %d" , + oobavail,YTAG1_SIZE ); +return YAFFS_FAIL ; + } +return YAFFS_OK ; +} + +/* Query for the current state of a specific block. +* +* Examine the tags of the first chunk of the block and return the state: +* - YAFFS_BLOCK_STATE_DEAD, the block is marked bad +* - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use +* - YAFFS_BLOCK_STATE_EMPTY, the block is clean +* +* Always returns YAFFS_OK. +*/ +int nandmtd1_query_block (struct yaffs_dev *dev,int block_no, +enum yaffs_block_state *state_ptr,u32 * seq_ptr) +{ +struct mtd_info *mtd =yaffs_dev_to_mtd (dev); +int chunk_num = block_no * dev->param.chunks_per_block; +loff_t addr = (loff_t ) chunk_num * dev->data_bytes_per_chunk; +struct yaffs_ext_tags etags; +int state =YAFFS_BLOCK_STATE_DEAD ; +int seqnum =0 ; +int retval; + +/* We don't yet have a good place to test for MTD config prerequists. +* Do it here as we are called during the initial scan. +*/ +if (nandmtd1_test_prerequists (mtd) !=YAFFS_OK ) +return YAFFS_FAIL ; + + retval =nandmtd1_read_chunk_tags (dev, chunk_num,NULL , &etags); + etags.block_bad = (mtd->block_isbad) (mtd, addr); +if (etags.block_bad) { +yaffs_trace (YAFFS_TRACE_BAD_BLOCKS , +"block %d is marked bad" , block_no); + state =YAFFS_BLOCK_STATE_DEAD ; + }else if (etags.ecc_result !=YAFFS_ECC_RESULT_NO_ERROR ) { +/* bad tags, need to look more closely */ + state =YAFFS_BLOCK_STATE_NEEDS_SCANNING ; + }else if (etags.chunk_used) { + state =YAFFS_BLOCK_STATE_NEEDS_SCANNING ; + seqnum = etags.seq_number; + }else { + state =YAFFS_BLOCK_STATE_EMPTY ; + } + + *state_ptr = state; + *seq_ptr = seqnum; + +/* query always succeeds */ +return YAFFS_OK ; +}fs/yaffs2/yaffs_mtdif1.h new file +29
-0@@ -0,0 +1,29 @@ +/* +* YAFFS: Yet another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_MTDIF1_H__ +#define __YAFFS_MTDIF1_H__ + +int nandmtd1_write_chunk_tags (struct yaffs_dev *dev,int nand_chunk, +const u8 *data, +const struct yaffs_ext_tags *tags); + +int nandmtd1_read_chunk_tags (struct yaffs_dev *dev,int nand_chunk, +u8 *data,struct yaffs_ext_tags *tags); + +int nandmtd1_mark_block_bad (struct yaffs_dev *dev,int block_no); + +int nandmtd1_query_block (struct yaffs_dev *dev,int block_no, +enum yaffs_block_state *state,u32 *seq_number); + +#endif fs/yaffs2/yaffs_mtdif2.c new file +32
-0@@ -0,0 +1,215 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +/* mtd interface for YAFFS2 */ + +#include "yportenv.h" +#include "yaffs_trace.h" +#include "yaffs_mtdif2.h" +#include "yaffs_packedtags2.h" +#include "yaffs_linux.h" +#include "linux/mtd/mtd.h" +#include "linux/types.h" +#include "linux/time.h" + + +/* NB For use with inband tags.... +* We assume that the data buffer is of size total_bytes_per_chunk so that +* we can also use it to load the tags. +*/ +int nandmtd2_write_chunk_tags (struct yaffs_dev *dev,int nand_chunk, +const u8 *data, +const struct yaffs_ext_tags *tags)
fs/yaffs2/yaffs_mtdif2.c line 42
Quoted 10 lines
fs/yaffs2/yaffs_mtdif2.c new file +10
-0+{ +struct mtd_info *mtd =yaffs_dev_to_mtd (dev); +struct mtd_oob_ops ops; +int retval =0 ; +loff_t addr; +struct yaffs_packed_tags2 pt; +int packed_tags_size = + dev->param.no_tags_ecc ?sizeof (pt.t) :sizeof (pt); +void *packed_tags_ptr = + dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
Shouldn't need void * casts.
Quoted 4 lines
fs/yaffs2/yaffs_mtdif2.c new file +4
-0+ +yaffs_trace (YAFFS_TRACE_MTD , +"nandmtd2_write_chunk_tags chunk %d data %p tags %p" , + nand_chunk, data, tags);
fs/yaffs2/yaffs_mtdif2.c line 56
Quoted 10 lines
fs/yaffs2/yaffs_mtdif2.c new file +10
-0+ + addr = ((loff_t ) nand_chunk) * dev->param.total_bytes_per_chunk; + +/* For yaffs2 writing there must be both data and tags. +* If we're using inband tags, then the tags are stuffed into +* the end of the data buffer. +*/ +if (!data || !tags) +BUG (); +else if (dev->param.inband_tags) {
This should be a separate if statement to the one for BUG. If you don't want fall through when BUG is not enabled, then just have:
if (!data || !tags) {
BUG();
return YAFFS_FAILED;
}Quoted 29 lines
fs/yaffs2/yaffs_mtdif2.c new file +29
-0+struct yaffs_packed_tags2_tags_only *pt2tp; + + pt2tp = + (struct yaffs_packed_tags2_tags_only *)(data + + dev-> + data_bytes_per_chunk); +yaffs_pack_tags2_tags_only (pt2tp, tags); + }else { +yaffs_pack_tags2 (&pt, tags, !dev->param.no_tags_ecc); + } + + ops.mode =MTD_OOB_AUTO ; + ops.ooblen = (dev->param.inband_tags) ?0 : packed_tags_size; + ops.len = dev->param.total_bytes_per_chunk; + ops.ooboffs =0 ; + ops.datbuf = (u8 *) data; + ops.oobbuf = (dev->param.inband_tags) ?NULL : packed_tags_ptr; + retval = mtd->write_oob (mtd, addr, &ops); + +if (retval ==0 ) +return YAFFS_OK ; +else +return YAFFS_FAIL ; +} + +int nandmtd2_read_chunk_tags (struct yaffs_dev *dev,int nand_chunk, +u8 *data,struct yaffs_ext_tags *tags) +{ +struct mtd_info *mtd =yaffs_dev_to_mtd (dev);
fs/yaffs2/yaffs_mtdif2.c line 95
Quoted 10 lines
fs/yaffs2/yaffs_mtdif2.c new file +10
-0+struct mtd_oob_ops ops; +size_t dummy; +int retval =0 ; +int local_data =0 ; +loff_t addr = ((loff_t ) nand_chunk) * dev->param.total_bytes_per_chunk; +struct yaffs_packed_tags2 pt; +int packed_tags_size = + dev->param.no_tags_ecc ?sizeof (pt.t) :sizeof (pt); +void *packed_tags_ptr = + dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
Shouldn't need void * casts.
fs/yaffs2/yaffs_mtdif2.c line 103
Quoted 7 lines
fs/yaffs2/yaffs_mtdif2.c new file +7
-0+yaffs_trace (YAFFS_TRACE_MTD , +"nandmtd2_read_chunk_tags chunk %d data %p tags %p" , + nand_chunk, data, tags); + +if (dev->param.inband_tags) { + +if (!data) {
if (dev->param.inband_tags && !data) ?
Quoted 216 lines
fs/yaffs2/yaffs_mtdif2.c new file +112
-0+ local_data =1 ; + data =yaffs_get_temp_buffer (dev, __LINE__); + } + } + +if (dev->param.inband_tags || (data && !tags)) + retval = mtd->read (mtd, addr, dev->param.total_bytes_per_chunk, + &dummy, data); +else if (tags) { + ops.mode =MTD_OOB_AUTO ; + ops.ooblen = packed_tags_size; + ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size; + ops.ooboffs =0 ; + ops.datbuf = data; + ops.oobbuf =yaffs_dev_to_lc (dev)->spare_buffer; + retval = mtd->read_oob (mtd, addr, &ops); + } + +if (dev->param.inband_tags) { +if (tags) { +struct yaffs_packed_tags2_tags_only *pt2tp; + pt2tp = + (struct yaffs_packed_tags2_tags_only *) + &data[dev->data_bytes_per_chunk]; +yaffs_unpack_tags2_tags_only (tags, pt2tp); + } + }else { +if (tags) { +memcpy (packed_tags_ptr, +yaffs_dev_to_lc (dev)->spare_buffer, + packed_tags_size); +yaffs_unpack_tags2 (tags, &pt, !dev->param.no_tags_ecc); + } + } + +if (local_data) +yaffs_release_temp_buffer (dev, data, __LINE__); + +if (tags && retval == -EBADMSG + && tags->ecc_result ==YAFFS_ECC_RESULT_NO_ERROR ) { + tags->ecc_result =YAFFS_ECC_RESULT_UNFIXED ; + dev->n_ecc_unfixed++; + } +if (tags && retval == -EUCLEAN + && tags->ecc_result ==YAFFS_ECC_RESULT_NO_ERROR ) { + tags->ecc_result =YAFFS_ECC_RESULT_FIXED ; + dev->n_ecc_fixed++; + } +if (retval ==0 ) +return YAFFS_OK ; +else +return YAFFS_FAIL ; +} + +int nandmtd2_mark_block_bad (struct yaffs_dev *dev,int block_no) +{ +struct mtd_info *mtd =yaffs_dev_to_mtd (dev); +int retval; + +yaffs_trace (YAFFS_TRACE_MTD , +"nandmtd2_mark_block_bad %d" , block_no); + + retval = + mtd->block_markbad (mtd, + block_no * dev->param.chunks_per_block * + dev->param.total_bytes_per_chunk); + +if (retval ==0 ) +return YAFFS_OK ; +else +return YAFFS_FAIL ; +} + +int nandmtd2_query_block (struct yaffs_dev *dev,int block_no, +enum yaffs_block_state *state,u32 * seq_number) +{ +struct mtd_info *mtd =yaffs_dev_to_mtd (dev); +int retval; + +yaffs_trace (YAFFS_TRACE_MTD ,"nandmtd2_query_block %d" , block_no); + retval = + mtd->block_isbad (mtd, + block_no * dev->param.chunks_per_block * + dev->param.total_bytes_per_chunk); + +if (retval) { +yaffs_trace (YAFFS_TRACE_MTD ,"block is bad" ); + + *state =YAFFS_BLOCK_STATE_DEAD ; + *seq_number =0 ; + }else { +struct yaffs_ext_tags t; +nandmtd2_read_chunk_tags (dev, block_no * + dev->param.chunks_per_block,NULL , &t); + +if (t.chunk_used) { + *seq_number = t.seq_number; + *state =YAFFS_BLOCK_STATE_NEEDS_SCANNING ; + }else { + *seq_number =0 ; + *state =YAFFS_BLOCK_STATE_EMPTY ; + } + } +yaffs_trace (YAFFS_TRACE_MTD , +"block is bad seq %d state %d" , *seq_number, *state); + +if (retval ==0 ) +return YAFFS_OK ; +else +return YAFFS_FAIL ; +} +fs/yaffs2/yaffs_mtdif2.h new file +29
-0@@ -0,0 +1,29 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_MTDIF2_H__ +#define __YAFFS_MTDIF2_H__ + +#include "yaffs_guts.h" +int nandmtd2_write_chunk_tags (struct yaffs_dev *dev,int nand_chunk, +const u8 *data, +const struct yaffs_ext_tags *tags); +int nandmtd2_read_chunk_tags (struct yaffs_dev *dev,int nand_chunk, +u8 *data,struct yaffs_ext_tags *tags); +int nandmtd2_mark_block_bad (struct yaffs_dev *dev,int block_no); +int nandmtd2_query_block (struct yaffs_dev *dev,int block_no, +enum yaffs_block_state *state,u32 *seq_number); + +#endif fs/yaffs2/yaffs_nand.c new file +63
-0@@ -0,0 +1,120 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_nand.h" +#include "yaffs_tagscompat.h" +#include "yaffs_tagsvalidity.h" + +#include "yaffs_getblockinfo.h" + +int yaffs_rd_chunk_tags_nand (struct yaffs_dev *dev,int nand_chunk, +u8 *buffer,struct yaffs_ext_tags *tags) +{ +int result; +struct yaffs_ext_tags local_tags; +int realigned_chunk = nand_chunk - dev->chunk_offset; + + dev->n_page_reads++; + +/* If there are no tags provided use local tags. */ +if (!tags) + tags = &local_tags; + +if (dev->param.read_chunk_tags_fn) + result = + dev->param.read_chunk_tags_fn (dev, realigned_chunk, buffer, + tags); +else + result =yaffs_tags_compat_rd (dev, + realigned_chunk, buffer, tags); +if (tags && tags->ecc_result >YAFFS_ECC_RESULT_NO_ERROR ) { + +struct yaffs_block_info *bi; + bi =yaffs_get_block_info (dev, + nand_chunk / + dev->param.chunks_per_block); +yaffs_handle_chunk_error (dev, bi); + } +return result; +} + +int yaffs_wr_chunk_tags_nand (struct yaffs_dev *dev, +int nand_chunk, +const u8 *buffer,struct yaffs_ext_tags *tags) +{ + dev->n_page_writes++; + nand_chunk -= dev->chunk_offset; + +if (tags) { + tags->seq_number = dev->seq_number; + tags->chunk_used =1 ; +if (!yaffs_validate_tags (tags)) { +yaffs_trace (YAFFS_TRACE_ERROR , +"Writing uninitialised tags" );
fs/yaffs2/yaffs_nand.c line 73
Quoted 10 lines
fs/yaffs2/yaffs_nand.c new file +10
-0+YBUG (); + } +yaffs_trace (YAFFS_TRACE_WRITE , +"Writing chunk %d tags %d %d" , + nand_chunk, tags->obj_id, tags->chunk_id); + }else { +yaffs_trace (YAFFS_TRACE_ERROR ,"Writing with no tags" ); +YBUG (); +return YAFFS_FAIL ; + }
I would rearrange this to make the BUG case prominent and then drop the indentation for the case where tags is valid, ie:
if (!tags) {
yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
YBUG();
return YAFFS_FAIL;
}
tags->seq_number = dev->seq_number;
...Quoted 29 lines
fs/yaffs2/yaffs_nand.c new file +29
-0+ +if (dev->param.write_chunk_tags_fn) +return dev->param.write_chunk_tags_fn (dev, nand_chunk, buffer, + tags); +else +return yaffs_tags_compat_wr (dev, nand_chunk, buffer, tags); +} + +int yaffs_mark_bad (struct yaffs_dev *dev,int block_no) +{ + block_no -= dev->block_offset; +if (dev->param.bad_block_fn) +return dev->param.bad_block_fn (dev, block_no); +else +return yaffs_tags_compat_mark_bad (dev, block_no); +} + +int yaffs_query_init_block_state (struct yaffs_dev *dev, +int block_no, +enum yaffs_block_state *state, +u32 *seq_number) +{ + block_no -= dev->block_offset; +if (dev->param.query_block_fn) +return dev->param.query_block_fn (dev, block_no, state, + seq_number); +else +return yaffs_tags_compat_query_block (dev, block_no, + state, seq_number);
fs/yaffs2/yaffs_nand.c line 112
Quoted 10 lines
fs/yaffs2/yaffs_nand.c new file +10
-0+} + +int yaffs_erase_block (struct yaffs_dev *dev,int flash_block) +{ +int result; + + flash_block -= dev->block_offset; + dev->n_erasures++; + result = dev->param.erase_fn (dev, flash_block); +return result;
Just:
return dev->param.erase_fn(dev, flash_block);
Quoted 52 lines
fs/yaffs2/yaffs_nand.c new file +8
-0+} + +int yaffs_init_nand (struct yaffs_dev *dev) +{ +if (dev->param.initialise_flash_fn) +return dev->param.initialise_flash_fn (dev); +return YAFFS_OK ; +}fs/yaffs2/yaffs_nand.h new file +38
-0@@ -0,0 +1,38 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_NAND_H__ +#define __YAFFS_NAND_H__ +#include "yaffs_guts.h" + +int yaffs_rd_chunk_tags_nand (struct yaffs_dev *dev,int nand_chunk, +u8 *buffer,struct yaffs_ext_tags *tags); + +int yaffs_wr_chunk_tags_nand (struct yaffs_dev *dev, +int nand_chunk, +const u8 *buffer,struct yaffs_ext_tags *tags); + +int yaffs_mark_bad (struct yaffs_dev *dev,int block_no); + +int yaffs_query_init_block_state (struct yaffs_dev *dev, +int block_no, +enum yaffs_block_state *state, +unsigned *seq_number); + +int yaffs_erase_block (struct yaffs_dev *dev,int flash_block); + +int yaffs_init_nand (struct yaffs_dev *dev); + +#endif
Signature · 7 lines
Bluewater Systems Ltd - ARM Technology Solution Centre Ryan Mallon 5 Amuri Park, 404 Barbadoes St [email protected] PO Box 13 889, Christchurch 8013 http://www.bluewatersys.com New Zealand Phone: +64 3 3779127 Freecall: Australia 1800 148 751 Fax: +64 3 3779135 USA 1800 261 2934
PATCH 5/10 Add yaffs2 file system: Tags processing code
In reply to Charles Manning--- fs/yaffs2/yaffs_packedtags1.c | 53 ++++++ fs/yaffs2/yaffs_packedtags1.h | 39 ++++ fs/yaffs2/yaffs_packedtags2.c | 187 +++++++++++++++++++ fs/yaffs2/yaffs_packedtags2.h | 47 +++++ fs/yaffs2/yaffs_tagscompat.c | 413 +++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_tagscompat.h | 36 ++++ 6 files changed, 775 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_packedtags1.c create mode 100644 fs/yaffs2/yaffs_packedtags1.h create mode 100644 fs/yaffs2/yaffs_packedtags2.c create mode 100644 fs/yaffs2/yaffs_packedtags2.h create mode 100644 fs/yaffs2/yaffs_tagscompat.c create mode 100644 fs/yaffs2/yaffs_tagscompat.h
fs/yaffs2/yaffs_packedtags1.c new file +53 -0
@@ -0,0 +1,53 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_packedtags1.h" +#include "yportenv.h" + +void yaffs_pack_tags1 (struct yaffs_packed_tags1 *pt, +const struct yaffs_ext_tags *t) +{ + pt->chunk_id = t->chunk_id; + pt->serial_number = t->serial_number; + pt->n_bytes = t->n_bytes; + pt->obj_id = t->obj_id; + pt->ecc =0 ; + pt->deleted = (t->is_deleted) ?0 :1 ; + pt->unused_stuff =0 ; + pt->should_be_ff =0xFFFFFFFF ; +} + +void yaffs_unpack_tags1 (struct yaffs_ext_tags *t, +const struct yaffs_packed_tags1 *pt) +{ +static const u8 all_ff[12 ] = { +0xff ,0xff ,0xff ,0xff , +0xff ,0xff ,0xff ,0xff , +0xff ,0xff ,0xff ,0xff + }; + +if (memcmp (all_ff, pt,sizeof (struct yaffs_packed_tags1 ))) { + t->block_bad =0 ; +if (pt->should_be_ff !=0xFFFFFFFF ) + t->block_bad =1 ; + t->chunk_used =1 ; + t->obj_id = pt->obj_id; + t->chunk_id = pt->chunk_id; + t->n_bytes = pt->n_bytes; + t->ecc_result =YAFFS_ECC_RESULT_NO_ERROR ; + t->is_deleted = (pt->deleted) ?0 :1 ; + t->serial_number = pt->serial_number; + }else { +memset (t,0 ,sizeof (struct yaffs_ext_tags )); + } +}
fs/yaffs2/yaffs_packedtags1.h new file +39 -0
@@ -0,0 +1,39 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */ + +#ifndef __YAFFS_PACKEDTAGS1_H__ +#define __YAFFS_PACKEDTAGS1_H__ + +#include "yaffs_guts.h" + +struct yaffs_packed_tags1 { +unsigned chunk_id:20 ; +unsigned serial_number:2 ; +unsigned n_bytes:10 ; +unsigned obj_id:18 ; +unsigned ecc:12 ; +unsigned deleted:1 ; +unsigned unused_stuff:1 ; +unsigned should_be_ff; + +}; + +void yaffs_pack_tags1 (struct yaffs_packed_tags1 *pt, +const struct yaffs_ext_tags *t); +void yaffs_unpack_tags1 (struct yaffs_ext_tags *t, +const struct yaffs_packed_tags1 *pt); +#endif
fs/yaffs2/yaffs_packedtags2.c new file +187 -0
187 lines not on this page · raw message
fs/yaffs2/yaffs_packedtags2.h new file +47 -0
47 lines not on this page · raw message
fs/yaffs2/yaffs_tagscompat.c new file +413 -0
413 lines not on this page · raw message
fs/yaffs2/yaffs_tagscompat.h new file +36 -0
@@ -0,0 +1,36 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_TAGSCOMPAT_H__ +#define __YAFFS_TAGSCOMPAT_H__ + +#include "yaffs_guts.h" +int yaffs_tags_compat_wr (struct yaffs_dev *dev, +int nand_chunk, +const u8 *data,const struct yaffs_ext_tags *tags); +int yaffs_tags_compat_rd (struct yaffs_dev *dev, +int nand_chunk, +u8 *data,struct yaffs_ext_tags *tags); +int yaffs_tags_compat_mark_bad (struct yaffs_dev *dev,int block_no); +int yaffs_tags_compat_query_block (struct yaffs_dev *dev, +int block_no, +enum yaffs_block_state *state, +u32 *seq_number); + +void yaffs_calc_tags_ecc (struct yaffs_tags *tags); +int yaffs_check_tags_ecc (struct yaffs_tags *tags); +int yaffs_count_bits (u8 byte); + +#endif
Signature · 1 line
1.7.1
Re: [PATCH 05/10] Add yaffs2 file system: Tags processing code
Quoted 1 line · Charles Manning
Signed-off-by Charles Manning <[email protected]>
A few comments below.
~Ryan
Quoted 52 lines
--- fs/yaffs2/yaffs_packedtags1.c | 53 ++++++ fs/yaffs2/yaffs_packedtags1.h | 39 ++++ fs/yaffs2/yaffs_packedtags2.c | 187 +++++++++++++++++++ fs/yaffs2/yaffs_packedtags2.h | 47 +++++ fs/yaffs2/yaffs_tagscompat.c | 413 +++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_tagscompat.h | 36 ++++ 6 files changed, 775 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_packedtags1.c create mode 100644 fs/yaffs2/yaffs_packedtags1.h create mode 100644 fs/yaffs2/yaffs_packedtags2.c create mode 100644 fs/yaffs2/yaffs_packedtags2.h create mode 100644 fs/yaffs2/yaffs_tagscompat.c create mode 100644 fs/yaffs2/yaffs_tagscompat.hfs/yaffs2/yaffs_packedtags1.c new file +31
-0@@ -0,0 +1,53 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_packedtags1.h" +#include "yportenv.h" + +void yaffs_pack_tags1 (struct yaffs_packed_tags1 *pt, +const struct yaffs_ext_tags *t) +{ + pt->chunk_id = t->chunk_id; + pt->serial_number = t->serial_number; + pt->n_bytes = t->n_bytes; + pt->obj_id = t->obj_id; + pt->ecc =0 ; + pt->deleted = (t->is_deleted) ?0 :1 ; + pt->unused_stuff =0 ; + pt->should_be_ff =0xFFFFFFFF ; +} + +void yaffs_unpack_tags1 (struct yaffs_ext_tags *t, +const struct yaffs_packed_tags1 *pt)
fs/yaffs2/yaffs_packedtags1.c line 41
Quoted 10 lines
fs/yaffs2/yaffs_packedtags1.c new file +10
-0+{ +static const u8 all_ff[12 ] = { +0xff ,0xff ,0xff ,0xff , +0xff ,0xff ,0xff ,0xff , +0xff ,0xff ,0xff ,0xff + }; + +if (memcmp (all_ff, pt,sizeof (struct yaffs_packed_tags1 ))) { + t->block_bad =0 ; +if (pt->should_be_ff !=0xFFFFFFFF )
You have a combination of upper and lower letters for hex constants. You should pick one and be consistent.
Quoted 372 lines
fs/yaffs2/yaffs_packedtags1.c new file +12
-0+ t->block_bad =1 ; + t->chunk_used =1 ; + t->obj_id = pt->obj_id; + t->chunk_id = pt->chunk_id; + t->n_bytes = pt->n_bytes; + t->ecc_result =YAFFS_ECC_RESULT_NO_ERROR ; + t->is_deleted = (pt->deleted) ?0 :1 ; + t->serial_number = pt->serial_number; + }else { +memset (t,0 ,sizeof (struct yaffs_ext_tags )); + } +}fs/yaffs2/yaffs_packedtags1.h new file +39
-0@@ -0,0 +1,39 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */ + +#ifndef __YAFFS_PACKEDTAGS1_H__ +#define __YAFFS_PACKEDTAGS1_H__ + +#include "yaffs_guts.h" + +struct yaffs_packed_tags1 { +unsigned chunk_id:20 ; +unsigned serial_number:2 ; +unsigned n_bytes:10 ; +unsigned obj_id:18 ; +unsigned ecc:12 ; +unsigned deleted:1 ; +unsigned unused_stuff:1 ; +unsigned should_be_ff; + +}; + +void yaffs_pack_tags1 (struct yaffs_packed_tags1 *pt, +const struct yaffs_ext_tags *t); +void yaffs_unpack_tags1 (struct yaffs_ext_tags *t, +const struct yaffs_packed_tags1 *pt); +#endif fs/yaffs2/yaffs_packedtags2.c new file +187
-0@@ -0,0 +1,187 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_packedtags2.h" +#include "yportenv.h" +#include "yaffs_trace.h" +#include "yaffs_tagsvalidity.h" + +/* This code packs a set of extended tags into a binary structure for +* NAND storage +*/ + +/* Some of the information is "extra" struff which can be packed in to +* speed scanning +* This is defined by having the EXTRA_HEADER_INFO_FLAG set. +*/ + +/* Extra flags applied to chunk_id */ + +#define EXTRA_HEADER_INFO_FLAG 0x80000000 +#define EXTRA_SHRINK_FLAG 0x40000000 +#define EXTRA_SHADOWS_FLAG 0x20000000 +#define EXTRA_SPARE_FLAGS 0x10000000 + +#define ALL_EXTRA_FLAGS 0xF0000000 + +/* Also, the top 4 bits of the object Id are set to the object type. */ +#define EXTRA_OBJECT_TYPE_SHIFT (28) +#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) + +static void yaffs_dump_packed_tags2_tags_only ( +const struct yaffs_packed_tags2_tags_only *ptt) +{ +yaffs_trace (YAFFS_TRACE_MTD , +"packed tags obj %d chunk %d byte %d seq %d" , + ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number); +} + +static void yaffs_dump_packed_tags2 (const struct yaffs_packed_tags2 *pt) +{ +yaffs_dump_packed_tags2_tags_only (&pt->t); +} + +static void yaffs_dump_tags2 (const struct yaffs_ext_tags *t) +{ +yaffs_trace (YAFFS_TRACE_MTD , +"ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d" , + t->ecc_result, t->block_bad, t->chunk_used, t->obj_id, + t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number, + t->seq_number); + +} + +void yaffs_pack_tags2_tags_only (struct yaffs_packed_tags2_tags_only *ptt, +const struct yaffs_ext_tags *t) +{ + ptt->chunk_id = t->chunk_id; + ptt->seq_number = t->seq_number; + ptt->n_bytes = t->n_bytes; + ptt->obj_id = t->obj_id; + +if (t->chunk_id ==0 && t->extra_available) { +/* Store the extra header info instead */ +/* We save the parent object in the chunk_id */ + ptt->chunk_id =EXTRA_HEADER_INFO_FLAG | t->extra_parent_id; +if (t->extra_is_shrink) + ptt->chunk_id |=EXTRA_SHRINK_FLAG ; +if (t->extra_shadows) + ptt->chunk_id |=EXTRA_SHADOWS_FLAG ; + + ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK ; + ptt->obj_id |= (t->extra_obj_type <<EXTRA_OBJECT_TYPE_SHIFT ); + +if (t->extra_obj_type ==YAFFS_OBJECT_TYPE_HARDLINK ) + ptt->n_bytes = t->extra_equiv_id; +else if (t->extra_obj_type ==YAFFS_OBJECT_TYPE_FILE ) + ptt->n_bytes = t->extra_length; +else + ptt->n_bytes =0 ; + } + +yaffs_dump_packed_tags2_tags_only (ptt); +yaffs_dump_tags2 (t); +} + +void yaffs_pack_tags2 (struct yaffs_packed_tags2 *pt, +const struct yaffs_ext_tags *t,int tags_ecc) +{ +yaffs_pack_tags2_tags_only (&pt->t, t); + +if (tags_ecc) +yaffs_ecc_calc_other ((unsigned char *)&pt->t, +sizeof (struct +yaffs_packed_tags2_tags_only ), + &pt->ecc); +} + +void yaffs_unpack_tags2_tags_only (struct yaffs_ext_tags *t, +struct yaffs_packed_tags2_tags_only *ptt) +{ +memset (t,0 ,sizeof (struct yaffs_ext_tags )); +yaffs_init_tags (t); + +if (ptt->seq_number !=0xFFFFFFFF ) { + t->block_bad =0 ; + t->chunk_used =1 ; + t->obj_id = ptt->obj_id; + t->chunk_id = ptt->chunk_id; + t->n_bytes = ptt->n_bytes; + t->is_deleted =0 ; + t->serial_number =0 ; + t->seq_number = ptt->seq_number; + +/* Do extra header info stuff */ +if (ptt->chunk_id &EXTRA_HEADER_INFO_FLAG ) { + t->chunk_id =0 ; + t->n_bytes =0 ; + + t->extra_available =1 ; + t->extra_parent_id = + ptt->chunk_id & (~(ALL_EXTRA_FLAGS )); + t->extra_is_shrink = + (ptt->chunk_id &EXTRA_SHRINK_FLAG ) ?1 :0 ; + t->extra_shadows = + (ptt->chunk_id &EXTRA_SHADOWS_FLAG ) ?1 :0 ; + t->extra_obj_type = + ptt->obj_id >>EXTRA_OBJECT_TYPE_SHIFT ; + t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK ; + +if (t->extra_obj_type ==YAFFS_OBJECT_TYPE_HARDLINK ) + t->extra_equiv_id = ptt->n_bytes; +else + t->extra_length = ptt->n_bytes; + } + } +yaffs_dump_packed_tags2_tags_only (ptt); +yaffs_dump_tags2 (t); +} + +void yaffs_unpack_tags2 (struct yaffs_ext_tags *t,struct yaffs_packed_tags2 *pt, +int tags_ecc) +{ +enum yaffs_ecc_result ecc_result =YAFFS_ECC_RESULT_NO_ERROR ; + +if (pt->t.seq_number !=0xFFFFFFFF && tags_ecc) { +/* Chunk is in use and we need to do ECC */ + +struct yaffs_ecc_other ecc; +int result; +yaffs_ecc_calc_other ((unsigned char *)&pt->t, +sizeof (struct yaffs_packed_tags2_tags_only ), + &ecc); + result = +yaffs_ecc_correct_other ((unsigned char *)&pt->t, +sizeof (struct yaffs_packed_tags2_tags_only ), + &pt->ecc, &ecc); +switch (result) { +case 0 : + ecc_result =YAFFS_ECC_RESULT_NO_ERROR ; +break ; +case 1 : + ecc_result =YAFFS_ECC_RESULT_FIXED ; +break ; +case -1 : + ecc_result =YAFFS_ECC_RESULT_UNFIXED ; +break ; +default : + ecc_result =YAFFS_ECC_RESULT_UNKNOWN ; + } + } +yaffs_unpack_tags2_tags_only (t, &pt->t); + + t->ecc_result = ecc_result; + +yaffs_dump_packed_tags2 (pt); +yaffs_dump_tags2 (t); +}fs/yaffs2/yaffs_packedtags2.h new file +47
-0@@ -0,0 +1,47 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +/* This is used to pack YAFFS2 tags, not YAFFS1tags. */ + +#ifndef __YAFFS_PACKEDTAGS2_H__ +#define __YAFFS_PACKEDTAGS2_H__ + +#include "yaffs_guts.h" +#include "yaffs_ecc.h" + +struct yaffs_packed_tags2_tags_only { +unsigned seq_number; +unsigned obj_id; +unsigned chunk_id; +unsigned n_bytes; +}; + +struct yaffs_packed_tags2 { +struct yaffs_packed_tags2_tags_only t; +struct yaffs_ecc_other ecc; +}; + +/* Full packed tags with ECC, used for oob tags */ +void yaffs_pack_tags2 (struct yaffs_packed_tags2 *pt, +const struct yaffs_ext_tags *t,int tags_ecc); +void yaffs_unpack_tags2 (struct yaffs_ext_tags *t,struct yaffs_packed_tags2 *pt, +int tags_ecc); + +/* Only the tags part (no ECC for use with inband tags */ +void yaffs_pack_tags2_tags_only (struct yaffs_packed_tags2_tags_only *pt, +const struct yaffs_ext_tags *t); +void yaffs_unpack_tags2_tags_only (struct yaffs_ext_tags *t, +struct yaffs_packed_tags2_tags_only *pt); +#endif fs/yaffs2/yaffs_tagscompat.c new file +63
-0@@ -0,0 +1,413 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_guts.h" +#include "yaffs_tagscompat.h" +#include "yaffs_ecc.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_trace.h" + +static void yaffs_handle_rd_data_error (struct yaffs_dev *dev,int nand_chunk); + + +/********** Tags ECC calculations *********/ + +void yaffs_calc_ecc (const u8 *data,struct yaffs_spare *spare) +{ +yaffs_ecc_cacl (data, spare->ecc1); +yaffs_ecc_cacl (&data[256 ], spare->ecc2); +} + +void yaffs_calc_tags_ecc (struct yaffs_tags *tags) +{ +/* Calculate an ecc */ +unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; +unsigned i, j; +unsigned ecc =0 ; +unsigned bit =0 ; + + tags->ecc =0 ; + +for (i =0 ; i <8 ; i++) { +for (j =1 ; j &0xff ; j <<=1 ) { + bit++; +if (b[i] & j) + ecc ^= bit; + } + } + tags->ecc = ecc; +} + +int yaffs_check_tags_ecc (struct yaffs_tags *tags) +{ +unsigned ecc = tags->ecc; + +yaffs_calc_tags_ecc (tags); + + ecc ^= tags->ecc; + +if (ecc && ecc <=64 ) { +/* TODO: Handle the failure better. Retire? */ +unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; + + ecc--;
fs/yaffs2/yaffs_tagscompat.c line 73
Quoted 10 lines
fs/yaffs2/yaffs_tagscompat.c new file +10
-0+ + b[ecc /8 ] ^= (1 << (ecc &7 )); + +/* Now recvalc the ecc */ +yaffs_calc_tags_ecc (tags); + +return 1 ;/* recovered error */ + }else if (ecc) { +/* Wierd ecc failure value */ +/* TODO Need to do somethiong here */
Maybe print a warning at least?
Quoted 41 lines
fs/yaffs2/yaffs_tagscompat.c new file +41
-0+return -1 ;/* unrecovered error */ + } +return 0 ; +} + +/********** Tags **********/ + +static void yaffs_load_tags_to_spare (struct yaffs_spare *spare_ptr, +struct yaffs_tags *tags_ptr) +{ +union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; + +yaffs_calc_tags_ecc (tags_ptr); + + spare_ptr->tb0 = tu->as_bytes[0 ]; + spare_ptr->tb1 = tu->as_bytes[1 ]; + spare_ptr->tb2 = tu->as_bytes[2 ]; + spare_ptr->tb3 = tu->as_bytes[3 ]; + spare_ptr->tb4 = tu->as_bytes[4 ]; + spare_ptr->tb5 = tu->as_bytes[5 ]; + spare_ptr->tb6 = tu->as_bytes[6 ]; + spare_ptr->tb7 = tu->as_bytes[7 ]; +} + +static void yaffs_get_tags_from_spare (struct yaffs_dev *dev, +struct yaffs_spare *spare_ptr, +struct yaffs_tags *tags_ptr) +{ +union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; +int result; + + tu->as_bytes[0 ] = spare_ptr->tb0; + tu->as_bytes[1 ] = spare_ptr->tb1; + tu->as_bytes[2 ] = spare_ptr->tb2; + tu->as_bytes[3 ] = spare_ptr->tb3; + tu->as_bytes[4 ] = spare_ptr->tb4; + tu->as_bytes[5 ] = spare_ptr->tb5; + tu->as_bytes[6 ] = spare_ptr->tb6; + tu->as_bytes[7 ] = spare_ptr->tb7; + + result =yaffs_check_tags_ecc (tags_ptr);
fs/yaffs2/yaffs_tagscompat.c line 124
Quoted 10 lines
fs/yaffs2/yaffs_tagscompat.c new file +10
-0+if (result >0 ) + dev->n_tags_ecc_fixed++; +else if (result <0 ) + dev->n_tags_ecc_unfixed++; +} + +static void yaffs_spare_init (struct yaffs_spare *spare) +{ +memset (spare,0xFF ,sizeof (struct yaffs_spare )); +}
This could be replaced by having a global:
static const struct yaffs_spare_ff = {
.tb0 = 0xff;
.tb1 = 0xff;
...
};Quoted 19 lines
fs/yaffs2/yaffs_tagscompat.c new file +19
-0+ +static int yaffs_wr_nand (struct yaffs_dev *dev, +int nand_chunk,const u8 *data, +struct yaffs_spare *spare) +{ +if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>> yaffs chunk %d is not valid" , + nand_chunk); +return YAFFS_FAIL ; + } + +return dev->param.write_chunk_fn (dev, nand_chunk, data, spare); +} + +static int yaffs_rd_chunk_nand(struct yaffs_dev *dev, + int nand_chunk, + u8 *data, + struct yaffs_spare *spare,
fs/yaffs2/yaffs_tagscompat.c line 153
Quoted 10 lines
fs/yaffs2/yaffs_tagscompat.c new file +10
-0+enum yaffs_ecc_result *ecc_result, + int correct_errors) +{ + int ret_val; +struct yaffs_spare local_spare; + +if (!spare) { +/* If we don't have a real spare, then we use a local one. */ +/* Need this for the calculation of the ecc */ + spare = &local_spare;
Is this safe? Can we get left pointing at something which isn't there anymore?
Quoted 163 lines
fs/yaffs2/yaffs_tagscompat.c new file +163
-0+ } + +if (!dev->param.use_nand_ecc) { + ret_val = + dev->param.read_chunk_fn (dev, nand_chunk, data, spare); +if (data && correct_errors) { +/* Do ECC correction */ +/* Todo handle any errors */ +int ecc_result1, ecc_result2; +u8 calc_ecc[3 ]; + +yaffs_ecc_cacl (data, calc_ecc); + ecc_result1 = +yaffs_ecc_correct (data, spare->ecc1, calc_ecc); +yaffs_ecc_cacl (&data[256 ], calc_ecc); + ecc_result2 = +yaffs_ecc_correct (&data[256 ], spare->ecc2, + calc_ecc); + +if (ecc_result1 >0 ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>>yaffs ecc error fix performed on chunk %d:0" , + nand_chunk); + dev->n_ecc_fixed++; + }else if (ecc_result1 <0 ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>>yaffs ecc error unfixed on chunk %d:0" , + nand_chunk); + dev->n_ecc_unfixed++; + } + +if (ecc_result2 >0 ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>>yaffs ecc error fix performed on chunk %d:1" , + nand_chunk); + dev->n_ecc_fixed++; + }else if (ecc_result2 <0 ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>>yaffs ecc error unfixed on chunk %d:1" , + nand_chunk); + dev->n_ecc_unfixed++; + } + +if (ecc_result1 || ecc_result2) { +/* We had a data problem on this page */ +yaffs_handle_rd_data_error (dev, nand_chunk); + } + +if (ecc_result1 <0 || ecc_result2 <0 ) + *ecc_result =YAFFS_ECC_RESULT_UNFIXED ; +else if (ecc_result1 >0 || ecc_result2 >0 ) + *ecc_result =YAFFS_ECC_RESULT_FIXED ; +else + *ecc_result =YAFFS_ECC_RESULT_NO_ERROR ; + } + }else { +/* Must allocate enough memory for spare+2*sizeof(int) */ +/* for ecc results from device. */ +struct yaffs_nand_spare nspare; + +memset (&nspare,0 ,sizeof (nspare)); + + ret_val = dev->param.read_chunk_fn (dev, nand_chunk, data, + (struct yaffs_spare *) + &nspare); +memcpy (spare, &nspare,sizeof (struct yaffs_spare )); +if (data && correct_errors) { +if (nspare.eccres1 >0 ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>>mtd ecc error fix performed on chunk %d:0" , + nand_chunk); + }else if (nspare.eccres1 <0 ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>>mtd ecc error unfixed on chunk %d:0" , + nand_chunk); + } + +if (nspare.eccres2 >0 ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>>mtd ecc error fix performed on chunk %d:1" , + nand_chunk); + }else if (nspare.eccres2 <0 ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>>mtd ecc error unfixed on chunk %d:1" , + nand_chunk); + } + +if (nspare.eccres1 || nspare.eccres2) { +/* We had a data problem on this page */ +yaffs_handle_rd_data_error (dev, nand_chunk); + } + +if (nspare.eccres1 <0 || nspare.eccres2 <0 ) + *ecc_result =YAFFS_ECC_RESULT_UNFIXED ; +else if (nspare.eccres1 >0 || nspare.eccres2 >0 ) + *ecc_result =YAFFS_ECC_RESULT_FIXED ; +else + *ecc_result =YAFFS_ECC_RESULT_NO_ERROR ; + + } + } +return ret_val; +} + +/* +* Functions for robustisizing +*/ + +static void yaffs_handle_rd_data_error (struct yaffs_dev *dev,int nand_chunk) +{ +int flash_block = nand_chunk / dev->param.chunks_per_block; + +/* Mark the block for retirement */ +yaffs_get_block_info (dev, flash_block + dev->block_offset)-> + needs_retiring =1 ; +yaffs_trace (YAFFS_TRACE_ERROR |YAFFS_TRACE_BAD_BLOCKS , +"**>>Block %d marked for retirement" , + flash_block); + +/* TODO: +* Just do a garbage collection on the affected block +* then retire the block +* NB recursion +*/ +} + +int yaffs_tags_compat_wr (struct yaffs_dev *dev, +int nand_chunk, +const u8 *data,const struct yaffs_ext_tags *ext_tags) +{ +struct yaffs_spare spare; +struct yaffs_tags tags; + +yaffs_spare_init (&spare); + +if (ext_tags->is_deleted) + spare.page_status =0 ; +else { + tags.obj_id = ext_tags->obj_id; + tags.chunk_id = ext_tags->chunk_id; + + tags.n_bytes_lsb = ext_tags->n_bytes &0x3ff ; + +if (dev->data_bytes_per_chunk >=1024 ) + tags.n_bytes_msb = (ext_tags->n_bytes >>10 ) &3 ; +else + tags.n_bytes_msb =3 ; + + tags.serial_number = ext_tags->serial_number; + +if (!dev->param.use_nand_ecc && data) +yaffs_calc_ecc (data, &spare); + +yaffs_load_tags_to_spare (&spare, &tags); + + } + +return yaffs_wr_nand (dev, nand_chunk, data, &spare); +} + +int yaffs_tags_compat_rd (struct yaffs_dev *dev, +int nand_chunk, +u8 *data,struct yaffs_ext_tags *ext_tags)
fs/yaffs2/yaffs_tagscompat.c line 326
Quoted 10 lines
fs/yaffs2/yaffs_tagscompat.c new file +10
-0+{ +struct yaffs_spare spare; +struct yaffs_tags tags; +enum yaffs_ecc_result ecc_result =YAFFS_ECC_RESULT_UNKNOWN ; +static struct yaffs_spare spare_ff; +static int init; + +if (!init) { +memset (&spare_ff,0xFF ,sizeof (spare_ff)); + init =1 ;
Don't do this. Just have a const initialised struct.
Quoted 129 lines
fs/yaffs2/yaffs_tagscompat.c new file +87
-0+ } + +if (yaffs_rd_chunk_nand (dev, nand_chunk, + data, &spare, &ecc_result,1 )) { +/* ext_tags may be NULL */ +if (ext_tags) { + +int deleted = + (hweight8 (spare.page_status) <7 ) ?1 :0 ; + + ext_tags->is_deleted = deleted; + ext_tags->ecc_result = ecc_result; + ext_tags->block_bad =0 ;/* We're reading it */ +/* therefore it is not a bad block */ + ext_tags->chunk_used = + (memcmp (&spare_ff, &spare,sizeof (spare_ff)) != +0 ) ?1 :0 ; + +if (ext_tags->chunk_used) { +yaffs_get_tags_from_spare (dev, &spare, &tags); + + ext_tags->obj_id = tags.obj_id; + ext_tags->chunk_id = tags.chunk_id; + ext_tags->n_bytes = tags.n_bytes_lsb; + +if (dev->data_bytes_per_chunk >=1024 ) + ext_tags->n_bytes |= + (((unsigned )tags. + n_bytes_msb) <<10 ); + + ext_tags->serial_number = tags.serial_number; + } + } + +return YAFFS_OK ; + }else { +return YAFFS_FAIL ; + } +} + +int yaffs_tags_compat_mark_bad (struct yaffs_dev *dev,int flash_block) +{ +struct yaffs_spare spare; + +memset (&spare,0xff ,sizeof (struct yaffs_spare )); + + spare.block_status ='Y' ; + +yaffs_wr_nand (dev, flash_block * dev->param.chunks_per_block,NULL , + &spare); +yaffs_wr_nand (dev, flash_block * dev->param.chunks_per_block +1 , +NULL , &spare); + +return YAFFS_OK ; +} + +int yaffs_tags_compat_query_block (struct yaffs_dev *dev, +int block_no, +enum yaffs_block_state *state, +u32 *seq_number) +{ +struct yaffs_spare spare0, spare1; +static struct yaffs_spare spare_ff; +static int init; +enum yaffs_ecc_result dummy; + +if (!init) { +memset (&spare_ff,0xFF ,sizeof (spare_ff)); + init =1 ; + } + + *seq_number =0 ; + +yaffs_rd_chunk_nand (dev, block_no * dev->param.chunks_per_block,NULL , + &spare0, &dummy,1 ); +yaffs_rd_chunk_nand (dev, block_no * dev->param.chunks_per_block +1 , +NULL , &spare1, &dummy,1 ); + +if (hweight8 (spare0.block_status & spare1.block_status) <7 ) + *state =YAFFS_BLOCK_STATE_DEAD ; +else if (memcmp (&spare_ff, &spare0,sizeof (spare_ff)) ==0 ) + *state =YAFFS_BLOCK_STATE_EMPTY ; +else + *state =YAFFS_BLOCK_STATE_NEEDS_SCANNING ; + +return YAFFS_OK ; +}fs/yaffs2/yaffs_tagscompat.h new file +36
-0@@ -0,0 +1,36 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_TAGSCOMPAT_H__ +#define __YAFFS_TAGSCOMPAT_H__ + +#include "yaffs_guts.h" +int yaffs_tags_compat_wr (struct yaffs_dev *dev, +int nand_chunk, +const u8 *data,const struct yaffs_ext_tags *tags); +int yaffs_tags_compat_rd (struct yaffs_dev *dev, +int nand_chunk, +u8 *data,struct yaffs_ext_tags *tags); +int yaffs_tags_compat_mark_bad (struct yaffs_dev *dev,int block_no); +int yaffs_tags_compat_query_block (struct yaffs_dev *dev, +int block_no, +enum yaffs_block_state *state, +u32 *seq_number); + +void yaffs_calc_tags_ecc (struct yaffs_tags *tags); +int yaffs_check_tags_ecc (struct yaffs_tags *tags); +int yaffs_count_bits (u8 byte); + +#endif
Signature · 7 lines
Bluewater Systems Ltd - ARM Technology Solution Centre Ryan Mallon 5 Amuri Park, 404 Barbadoes St [email protected] PO Box 13 889, Christchurch 8013 http://www.bluewatersys.com New Zealand Phone: +64 3 3779127 Freecall: Australia 1800 148 751 Fax: +64 3 3779135 USA 1800 261 2934
PATCH 6/10 Add yaffs2 file system: Tracing and verification code
In reply to Charles Manning--- fs/yaffs2/yaffs_tagsvalidity.c | 26 ++ fs/yaffs2/yaffs_tagsvalidity.h | 23 ++ fs/yaffs2/yaffs_trace.h | 57 +++++ fs/yaffs2/yaffs_verify.c | 524 ++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_verify.h | 43 ++++ 5 files changed, 673 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_tagsvalidity.c create mode 100644 fs/yaffs2/yaffs_tagsvalidity.h create mode 100644 fs/yaffs2/yaffs_trace.h create mode 100644 fs/yaffs2/yaffs_verify.c create mode 100644 fs/yaffs2/yaffs_verify.h
fs/yaffs2/yaffs_tagsvalidity.c new file +26 -0
@@ -0,0 +1,26 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_tagsvalidity.h" + +void yaffs_init_tags (struct yaffs_ext_tags *tags) +{ +memset (tags,0 ,sizeof (struct yaffs_ext_tags )); + tags->validity0 =0xAAAAAAAA ; + tags->validity1 =0x55555555 ; +} + +int yaffs_validate_tags (struct yaffs_ext_tags *tags) +{ +return (tags->validity0 ==0xAAAAAAAA && tags->validity1 ==0x55555555 ); +}
fs/yaffs2/yaffs_tagsvalidity.h new file +23 -0
@@ -0,0 +1,23 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_TAGS_VALIDITY_H__ +#define __YAFFS_TAGS_VALIDITY_H__ + +#include "yaffs_guts.h" + +void yaffs_init_tags (struct yaffs_ext_tags *tags); +int yaffs_validate_tags (struct yaffs_ext_tags *tags); +#endif
fs/yaffs2/yaffs_trace.h new file +57 -0
57 lines not on this page · raw message
fs/yaffs2/yaffs_verify.c new file +524 -0
524 lines not on this page · raw message
fs/yaffs2/yaffs_verify.h new file +43 -0
43 lines not on this page · raw message
Signature · 1 line
1.7.1
Re: [PATCH 06/10] Add yaffs2 file system: Tracing and verification code
Quoted 1 line · Charles Manning
Signed-off-by Charles Manning <[email protected]>
Some comments below.
~Ryan
Quoted 35 lines
--- fs/yaffs2/yaffs_tagsvalidity.c | 26 ++ fs/yaffs2/yaffs_tagsvalidity.h | 23 ++ fs/yaffs2/yaffs_trace.h | 57 +++++ fs/yaffs2/yaffs_verify.c | 524 ++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_verify.h | 43 ++++ 5 files changed, 673 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_tagsvalidity.c create mode 100644 fs/yaffs2/yaffs_tagsvalidity.h create mode 100644 fs/yaffs2/yaffs_trace.h create mode 100644 fs/yaffs2/yaffs_verify.c create mode 100644 fs/yaffs2/yaffs_verify.hfs/yaffs2/yaffs_tagsvalidity.c new file +16
-0@@ -0,0 +1,26 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_tagsvalidity.h" + +void yaffs_init_tags (struct yaffs_ext_tags *tags)
fs/yaffs2/yaffs_tagsvalidity.c line 26
Quoted 10 lines
fs/yaffs2/yaffs_tagsvalidity.c new file +10
-0+{ +memset (tags,0 ,sizeof (struct yaffs_ext_tags )); + tags->validity0 =0xAAAAAAAA ; + tags->validity1 =0x55555555 ; +} + +int yaffs_validate_tags (struct yaffs_ext_tags *tags) +{ +return (tags->validity0 ==0xAAAAAAAA && tags->validity1 ==0x55555555 ); +}
These are simple enough that they could be made static inline in the yaffs_tagsvalidity.h header file and drop the c file altogether. You could further reduce the file count by merging it all with yaffs_tagscompat.[ch]
Quoted 110 lines
fs/yaffs2/yaffs_tagsvalidity.h new file +23
-0@@ -0,0 +1,23 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_TAGS_VALIDITY_H__ +#define __YAFFS_TAGS_VALIDITY_H__ + +#include "yaffs_guts.h" + +void yaffs_init_tags (struct yaffs_ext_tags *tags); +int yaffs_validate_tags (struct yaffs_ext_tags *tags); +#endif fs/yaffs2/yaffs_trace.h new file +57
-0@@ -0,0 +1,57 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YTRACE_H__ +#define __YTRACE_H__ + +extern unsigned int yaffs_trace_mask; +extern unsigned int yaffs_wr_attempts; + +/* +* Tracing flags. +* The flags masked in YAFFS_TRACE_ALWAYS are always traced. +*/ + +#define YAFFS_TRACE_OS 0x00000002 +#define YAFFS_TRACE_ALLOCATE 0x00000004 +#define YAFFS_TRACE_SCAN 0x00000008 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 +#define YAFFS_TRACE_ERASE 0x00000020 +#define YAFFS_TRACE_GC 0x00000040 +#define YAFFS_TRACE_WRITE 0x00000080 +#define YAFFS_TRACE_TRACING 0x00000100 +#define YAFFS_TRACE_DELETION 0x00000200 +#define YAFFS_TRACE_BUFFERS 0x00000400 +#define YAFFS_TRACE_NANDACCESS 0x00000800 +#define YAFFS_TRACE_GC_DETAIL 0x00001000 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 +#define YAFFS_TRACE_MTD 0x00004000 +#define YAFFS_TRACE_CHECKPOINT 0x00008000 + +#define YAFFS_TRACE_VERIFY 0x00010000 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000 +#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 + +#define YAFFS_TRACE_SYNC 0x00100000 +#define YAFFS_TRACE_BACKGROUND 0x00200000 +#define YAFFS_TRACE_LOCK 0x00400000 +#define YAFFS_TRACE_MOUNT 0x00800000 + +#define YAFFS_TRACE_ERROR 0x40000000 +#define YAFFS_TRACE_BUG 0x80000000 +#define YAFFS_TRACE_ALWAYS 0xF0000000 + +#endif fs/yaffs2/yaffs_verify.c new file +12
-0@@ -0,0 +1,524 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/
fs/yaffs2/yaffs_verify.c line 22
Quoted 10 lines
fs/yaffs2/yaffs_verify.c new file +10
-0+ +#include "yaffs_verify.h" +#include "yaffs_trace.h" +#include "yaffs_bitmap.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_nand.h" + +int yaffs_skip_verification (struct yaffs_dev *dev) +{ + dev = dev;
Mark dev as __always_unused if this causes a build warning. Same in other functions.
Quoted 237 lines
fs/yaffs2/yaffs_verify.c new file +237
-0+return !(yaffs_trace_mask & + (YAFFS_TRACE_VERIFY |YAFFS_TRACE_VERIFY_FULL )); +} + +static int yaffs_skip_full_verification (struct yaffs_dev *dev) +{ + dev = dev; +return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL )); +} + +static int yaffs_skip_nand_verification (struct yaffs_dev *dev) +{ + dev = dev; +return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND )); +} + +static const char *const block_state_name[] = { +"Unknown" , +"Needs scanning" , +"Scanning" , +"Empty" , +"Allocating" , +"Full" , +"Dirty" , +"Checkpoint" , +"Collecting" , +"Dead" +}; + +void yaffs_verify_blk (struct yaffs_dev *dev,struct yaffs_block_info *bi,int n) +{ +int actually_used; +int in_use; + +if (yaffs_skip_verification (dev)) +return ; + +/* Report illegal runtime states */ +if (bi->block_state >=YAFFS_NUMBER_OF_BLOCK_STATES ) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Block %d has undefined state %d" , + n, bi->block_state); + +switch (bi->block_state) { +case YAFFS_BLOCK_STATE_UNKNOWN : +case YAFFS_BLOCK_STATE_SCANNING : +case YAFFS_BLOCK_STATE_NEEDS_SCANNING : +yaffs_trace (YAFFS_TRACE_VERIFY , +"Block %d has bad run-state %s" , + n, block_state_name[bi->block_state]); + } + +/* Check pages in use and soft deletions are legal */ + + actually_used = bi->pages_in_use - bi->soft_del_pages; + +if (bi->pages_in_use <0 + || bi->pages_in_use > dev->param.chunks_per_block + || bi->soft_del_pages <0 + || bi->soft_del_pages > dev->param.chunks_per_block + || actually_used <0 || actually_used > dev->param.chunks_per_block) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Block %d has illegal values pages_in_used %d soft_del_pages %d" , + n, bi->pages_in_use, bi->soft_del_pages); + +/* Check chunk bitmap legal */ + in_use =yaffs_count_chunk_bits (dev, n); +if (in_use != bi->pages_in_use) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Block %d has inconsistent values pages_in_use %d counted chunk bits %d" , + n, bi->pages_in_use, in_use); +} + +void yaffs_verify_collected_blk (struct yaffs_dev *dev, +struct yaffs_block_info *bi,int n) +{ +yaffs_verify_blk (dev, bi, n); + +/* After collection the block should be in the erased state */ + +if (bi->block_state !=YAFFS_BLOCK_STATE_COLLECTING && + bi->block_state !=YAFFS_BLOCK_STATE_EMPTY ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"Block %d is in state %d after gc, should be erased" , + n, bi->block_state); + } +} + +void yaffs_verify_blocks (struct yaffs_dev *dev) +{ +int i; +int state_count[YAFFS_NUMBER_OF_BLOCK_STATES ]; +int illegal_states =0 ; + +if (yaffs_skip_verification (dev)) +return ; + +memset (state_count,0 ,sizeof (state_count)); + +for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { +struct yaffs_block_info *bi =yaffs_get_block_info (dev, i); +yaffs_verify_blk (dev, bi, i); + +if (bi->block_state <YAFFS_NUMBER_OF_BLOCK_STATES ) + state_count[bi->block_state]++; +else + illegal_states++; + } + +yaffs_trace (YAFFS_TRACE_VERIFY ,"Block summary" ); + +yaffs_trace (YAFFS_TRACE_VERIFY , +"%d blocks have illegal states" , + illegal_states); +if (state_count[YAFFS_BLOCK_STATE_ALLOCATING ] >1 ) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Too many allocating blocks" ); + +for (i =0 ; i <YAFFS_NUMBER_OF_BLOCK_STATES ; i++) +yaffs_trace (YAFFS_TRACE_VERIFY , +"%s %d blocks" , + block_state_name[i], state_count[i]); + +if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT ]) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Checkpoint block count wrong dev %d count %d" , + dev->blocks_in_checkpt, + state_count[YAFFS_BLOCK_STATE_CHECKPOINT ]); + +if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY ]) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Erased block count wrong dev %d count %d" , + dev->n_erased_blocks, + state_count[YAFFS_BLOCK_STATE_EMPTY ]); + +if (state_count[YAFFS_BLOCK_STATE_COLLECTING ] >1 ) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Too many collecting blocks %d (max is 1)" , + state_count[YAFFS_BLOCK_STATE_COLLECTING ]); +} + +/* +* Verify the object header. oh must be valid, but obj and tags may be NULL in +* which case those tests will not be performed. +*/ +void yaffs_verify_oh (struct yaffs_obj *obj,struct yaffs_obj_hdr *oh, +struct yaffs_ext_tags *tags,int parent_check) +{ +if (obj &&yaffs_skip_verification (obj->my_dev)) +return ; + +if (!(tags && obj && oh)) { +yaffs_trace (YAFFS_TRACE_VERIFY , +"Verifying object header tags %p obj %p oh %p" , + tags, obj, oh); +return ; + } + +if (oh->type <=YAFFS_OBJECT_TYPE_UNKNOWN || + oh->type >YAFFS_OBJECT_TYPE_MAX ) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Obj %d header type is illegal value 0x%x" , + tags->obj_id, oh->type); + +if (tags->obj_id != obj->obj_id) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Obj %d header mismatch obj_id %d" , + tags->obj_id, obj->obj_id); + +/* +* Check that the object's parent ids match if parent_check requested. +* +* Tests do not apply to the root object. +*/ + +if (parent_check && tags->obj_id >1 && !obj->parent) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Obj %d header mismatch parent_id %d obj->parent is NULL" , + tags->obj_id, oh->parent_obj_id); + +if (parent_check && obj->parent && + oh->parent_obj_id != obj->parent->obj_id && + (oh->parent_obj_id !=YAFFS_OBJECTID_UNLINKED || + obj->parent->obj_id !=YAFFS_OBJECTID_DELETED )) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Obj %d header mismatch parent_id %d parent_obj_id %d" , + tags->obj_id, oh->parent_obj_id, + obj->parent->obj_id); + +if (tags->obj_id >1 && oh->name[0 ] ==0 )/* Null name */ +yaffs_trace (YAFFS_TRACE_VERIFY , +"Obj %d header name is NULL" , + obj->obj_id); + +if (tags->obj_id >1 && ((u8) (oh->name[0 ])) ==0xff )/* Junk name */ +yaffs_trace (YAFFS_TRACE_VERIFY , +"Obj %d header name is 0xFF" , + obj->obj_id); +} + +void yaffs_verify_file (struct yaffs_obj *obj) +{ +int required_depth; +int actual_depth; +u32 last_chunk; +u32 x; +u32 i; +struct yaffs_dev *dev; +struct yaffs_ext_tags tags; +struct yaffs_tnode *tn; +u32 obj_id; + +if (!obj) +return ; + +if (yaffs_skip_verification (obj->my_dev)) +return ; + + dev = obj->my_dev; + obj_id = obj->obj_id; + +/* Check file size is consistent with tnode depth */ + last_chunk = + obj->variant.file_variant.file_size / dev->data_bytes_per_chunk +1 ; + x = last_chunk >>YAFFS_TNODES_LEVEL0_BITS ; + required_depth =0 ; +while (x >0 ) { + x >>=YAFFS_TNODES_INTERNAL_BITS ; + required_depth++; + } + + actual_depth = obj->variant.file_variant.top_level; + +/* Check that the chunks in the tnode tree are all correct. +* We do this by scanning through the tnode tree and +* checking the tags for every chunk match. +*/
fs/yaffs2/yaffs_verify.c line 269
Quoted 10 lines
fs/yaffs2/yaffs_verify.c new file +10
-0+ +if (yaffs_skip_nand_verification (dev)) +return ; + +for (i =1 ; i <= last_chunk; i++) { + tn =yaffs_find_tnode_0 (dev, &obj->variant.file_variant, i); + +if (tn) { +u32 the_chunk =yaffs_get_group_base (dev, tn, i); +if (the_chunk >0 ) {
You can reduce the indentation level by doing:
if (!tn) continue; the_chunk = yaffs_get_group_base(dev, tn, i); if (!the_chunk) continue;
Quoted 7 lines
fs/yaffs2/yaffs_verify.c new file +7
-0+yaffs_rd_chunk_tags_nand (dev, the_chunk,NULL , + &tags); +if (tags.obj_id != obj_id || tags.chunk_id != i) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)" , + obj_id, i, the_chunk, + tags.obj_id, tags.chunk_id);
fs/yaffs2/yaffs_verify.c line 286
Quoted 10 lines
fs/yaffs2/yaffs_verify.c new file +10
-0+ } + } + } +} + +void yaffs_verify_link (struct yaffs_obj *obj) +{ +if (obj &&yaffs_skip_verification (obj->my_dev)) +return ; +
This (and the functions below) doesn't do anything. What's it for?
Quoted 95 lines
fs/yaffs2/yaffs_verify.c new file +95
-0+/* Verify sane equivalent object */ +} + +void yaffs_verify_symlink (struct yaffs_obj *obj) +{ +if (obj &&yaffs_skip_verification (obj->my_dev)) +return ; + +/* Verify symlink string */ +} + +void yaffs_verify_special (struct yaffs_obj *obj) +{ +if (obj &&yaffs_skip_verification (obj->my_dev)) +return ; +} + +void yaffs_verify_obj (struct yaffs_obj *obj) +{ +struct yaffs_dev *dev; +u32 chunk_min; +u32 chunk_max; +u32 chunk_id_ok; +u32 chunk_in_range; +u32 chunk_wrongly_deleted; +u32 chunk_valid; + +if (!obj) +return ; + +if (obj->being_created) +return ; + + dev = obj->my_dev; + +if (yaffs_skip_verification (dev)) +return ; + +/* Check sane object header chunk */ + + chunk_min = dev->internal_start_block * dev->param.chunks_per_block; + chunk_max = + (dev->internal_end_block +1 ) * dev->param.chunks_per_block -1 ; + + chunk_in_range = (((unsigned )(obj->hdr_chunk)) >= chunk_min && + ((unsigned )(obj->hdr_chunk)) <= chunk_max); + chunk_id_ok = chunk_in_range || (obj->hdr_chunk ==0 ); + chunk_valid = chunk_in_range && +yaffs_check_chunk_bit (dev, + obj->hdr_chunk / dev->param.chunks_per_block, + obj->hdr_chunk % dev->param.chunks_per_block); + chunk_wrongly_deleted = chunk_in_range && !chunk_valid; + +if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted)) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Obj %d has chunk_id %d %s %s" , + obj->obj_id, obj->hdr_chunk, + chunk_id_ok ?"" :",out of range" , + chunk_wrongly_deleted ?",marked as deleted" :"" ); + +if (chunk_valid && !yaffs_skip_nand_verification (dev)) { +struct yaffs_ext_tags tags; +struct yaffs_obj_hdr *oh; +u8 *buffer =yaffs_get_temp_buffer (dev, __LINE__); + + oh = (struct yaffs_obj_hdr *)buffer; + +yaffs_rd_chunk_tags_nand (dev, obj->hdr_chunk, buffer, &tags); + +yaffs_verify_oh (obj, oh, &tags,1 ); + +yaffs_release_temp_buffer (dev, buffer, __LINE__); + } + +/* Verify it has a parent */ +if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) { +yaffs_trace (YAFFS_TRACE_VERIFY , +"Obj %d has parent pointer %p which does not look like an object" , + obj->obj_id, obj->parent); + } + +/* Verify parent is a directory */ +if (obj->parent + && obj->parent->variant_type !=YAFFS_OBJECT_TYPE_DIRECTORY ) { +yaffs_trace (YAFFS_TRACE_VERIFY , +"Obj %d's parent is not a directory (type %d)" , + obj->obj_id, obj->parent->variant_type); + } + +switch (obj->variant_type) { +case YAFFS_OBJECT_TYPE_FILE : +yaffs_verify_file (obj); +break ; +case YAFFS_OBJECT_TYPE_SYMLINK : +yaffs_verify_symlink (obj);
fs/yaffs2/yaffs_verify.c line 391
Quoted 10 lines
fs/yaffs2/yaffs_verify.c new file +10
-0+break ; +case YAFFS_OBJECT_TYPE_DIRECTORY : +yaffs_verify_dir (obj); +break ; +case YAFFS_OBJECT_TYPE_HARDLINK : +yaffs_verify_link (obj); +break ; +case YAFFS_OBJECT_TYPE_SPECIAL : +yaffs_verify_special (obj); +break ;
Print a warning/do nothing for the verifications which have empty functions?
Quoted 13 lines
fs/yaffs2/yaffs_verify.c new file +13
-0+case YAFFS_OBJECT_TYPE_UNKNOWN : +default : +yaffs_trace (YAFFS_TRACE_VERIFY , +"Obj %d has illegaltype %d" , + obj->obj_id, obj->variant_type); +break ; + } +} + +void yaffs_verify_objects (struct yaffs_dev *dev) +{ +struct yaffs_obj *obj; +int i;
fs/yaffs2/yaffs_verify.c line 414
Quoted 10 lines
fs/yaffs2/yaffs_verify.c new file +10
-0+struct list_head *lh; + +if (yaffs_skip_verification (dev)) +return ; + +/* Iterate through the objects in each hash entry */ + +for (i =0 ; i <YAFFS_NOBJECT_BUCKETS ; i++) { +list_for_each (lh, &dev->obj_bucket[i].list) { + obj = list_entry(lh, struct yaffs_obj, hash_link);
list_for_each_entry(lh, &dev->obj_bucket[i].list, hash_link)
Quoted 25 lines
fs/yaffs2/yaffs_verify.c new file +25
-0+yaffs_verify_obj (obj); + } + } +} + +void yaffs_verify_obj_in_dir (struct yaffs_obj *obj) +{ +struct list_head *lh; +struct yaffs_obj *list_obj; +int count =0 ; + +if (!obj) { +yaffs_trace (YAFFS_TRACE_ALWAYS ,"No object to verify" ); +YBUG (); +return ; + } + +if (yaffs_skip_verification (obj->my_dev)) +return ; + +if (!obj->parent) { +yaffs_trace (YAFFS_TRACE_ALWAYS ,"Object does not have parent" ); +YBUG (); +return ; + }
fs/yaffs2/yaffs_verify.c line 449
Quoted 10 lines
fs/yaffs2/yaffs_verify.c new file +10
-0+ +if (obj->parent->variant_type !=YAFFS_OBJECT_TYPE_DIRECTORY ) { +yaffs_trace (YAFFS_TRACE_ALWAYS ,"Parent is not directory" ); +YBUG (); + } + +/* Iterate through the objects in each hash entry */ + +list_for_each (lh, &obj->parent->variant.dir_variant.children) { + list_obj = list_entry(lh, struct yaffs_obj, siblings);
list_for_each_entry(lh,
&obj->parent->variant.dir_variant.children, siblings) {Quoted 27 lines
fs/yaffs2/yaffs_verify.c new file +27
-0+yaffs_verify_obj (list_obj); +if (obj == list_obj) + count++; + } + +if (count !=1 ) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"Object in directory %d times" , + count); +YBUG (); + } +} + +void yaffs_verify_dir (struct yaffs_obj *directory) +{ +struct list_head *lh; +struct yaffs_obj *list_obj; + +if (!directory) { +YBUG (); +return ; + } + +if (yaffs_skip_full_verification (directory->my_dev)) +return ; + +if (directory->variant_type !=YAFFS_OBJECT_TYPE_DIRECTORY ) {
fs/yaffs2/yaffs_verify.c line 486
Quoted 10 lines
fs/yaffs2/yaffs_verify.c new file +10
-0+yaffs_trace (YAFFS_TRACE_ALWAYS , +"Directory has wrong type: %d" , + directory->variant_type); +YBUG (); + } + +/* Iterate through the objects in each hash entry */ + +list_for_each (lh, &directory->variant.dir_variant.children) { + list_obj = list_entry(lh, struct yaffs_obj, siblings);
list_for_each_entry(lh, &directory->variant.dir_variant.children, siblings)
Quoted 27 lines
fs/yaffs2/yaffs_verify.c new file +27
-0+if (list_obj->parent != directory) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"Object in directory list has wrong parent %p" , + list_obj->parent); +YBUG (); + } +yaffs_verify_obj_in_dir (list_obj); + } +} + +static int yaffs_free_verification_failures; + +void yaffs_verify_free_chunks (struct yaffs_dev *dev) +{ +int counted; +int difference; + +if (yaffs_skip_verification (dev)) +return ; + + counted =yaffs_count_free_chunks (dev); + + difference = dev->n_free_chunks - counted; + +if (difference) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Freechunks verification failure %d %d %d",
fs/yaffs2/yaffs_verify.c line 523
Quoted 10 lines
fs/yaffs2/yaffs_verify.c new file +10
-0+ dev->n_free_chunks, counted, difference); + yaffs_free_verification_failures++; + } +} + +int yaffs_verify_file_sane (struct yaffs_obj *in) +{ + in = in; +return YAFFS_OK ; +}
Useless function.
Quoted 50 lines
fs/yaffs2/yaffs_verify.c new file +1
-0+fs/yaffs2/yaffs_verify.h new file +43
-0@@ -0,0 +1,43 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_VERIFY_H__ +#define __YAFFS_VERIFY_H__ + +#include "yaffs_guts.h" + +void yaffs_verify_blk (struct yaffs_dev *dev,struct yaffs_block_info *bi, +int n); +void yaffs_verify_collected_blk (struct yaffs_dev *dev, +struct yaffs_block_info *bi,int n); +void yaffs_verify_blocks (struct yaffs_dev *dev); + +void yaffs_verify_oh (struct yaffs_obj *obj,struct yaffs_obj_hdr *oh, +struct yaffs_ext_tags *tags,int parent_check); +void yaffs_verify_file (struct yaffs_obj *obj); +void yaffs_verify_link (struct yaffs_obj *obj); +void yaffs_verify_symlink (struct yaffs_obj *obj); +void yaffs_verify_special (struct yaffs_obj *obj); +void yaffs_verify_obj (struct yaffs_obj *obj); +void yaffs_verify_objects (struct yaffs_dev *dev); +void yaffs_verify_obj_in_dir (struct yaffs_obj *obj); +void yaffs_verify_dir (struct yaffs_obj *directory); +void yaffs_verify_free_chunks (struct yaffs_dev *dev); + +int yaffs_verify_file_sane (struct yaffs_obj *obj); + +int yaffs_skip_verification (struct yaffs_dev *dev); + +#endif
Signature · 7 lines
Bluewater Systems Ltd - ARM Technology Solution Centre Ryan Mallon 5 Amuri Park, 404 Barbadoes St [email protected] PO Box 13 889, Christchurch 8013 http://www.bluewatersys.com New Zealand Phone: +64 3 3779127 Freecall: Australia 1800 148 751 Fax: +64 3 3779135 USA 1800 261 2934
PATCH 7/10 Add yaffs2 file system: yaffs1 and yaffs2 mode specific code
In reply to Charles Manning--- fs/yaffs2/yaffs_yaffs1.c | 423 +++++++++++++ fs/yaffs2/yaffs_yaffs1.h | 22 + fs/yaffs2/yaffs_yaffs2.c | 1516 ++++++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_yaffs2.h | 39 ++ 4 files changed, 2000 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_yaffs1.c create mode 100644 fs/yaffs2/yaffs_yaffs1.h create mode 100644 fs/yaffs2/yaffs_yaffs2.c create mode 100644 fs/yaffs2/yaffs_yaffs2.h
fs/yaffs2/yaffs_yaffs1.c new file +423 -0
@@ -0,0 +1,423 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_yaffs1.h" +#include "yportenv.h" +#include "yaffs_trace.h" +#include "yaffs_bitmap.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_nand.h" +#include "yaffs_attribs.h" + +int yaffs1_scan (struct yaffs_dev *dev) +{ +struct yaffs_ext_tags tags; +int blk; +int result; +int chunk; +int c; +int deleted; +enum yaffs_block_state state; +struct yaffs_obj *hard_list =NULL ; +struct yaffs_block_info *bi; +u32 seq_number; +struct yaffs_obj_hdr *oh; +struct yaffs_obj *in; +struct yaffs_obj *parent; +int alloc_failed =0 ; +struct yaffs_shadow_fixer *shadow_fixers =NULL ; +u8 *chunk_data; + +yaffs_trace (YAFFS_TRACE_SCAN , +"yaffs1_scan starts intstartblk %d intendblk %d..." , + dev->internal_start_block, dev->internal_end_block); + + chunk_data =yaffs_get_temp_buffer (dev, __LINE__); + + dev->seq_number =YAFFS_LOWEST_SEQUENCE_NUMBER ; + +/* Scan all the blocks to determine their state */ + bi = dev->block_info; +for (blk = dev->internal_start_block; blk <= dev->internal_end_block; + blk++) { +yaffs_clear_chunk_bits (dev, blk); + bi->pages_in_use =0 ; + bi->soft_del_pages =0 ; + +yaffs_query_init_block_state (dev, blk, &state, &seq_number); + + bi->block_state = state; + bi->seq_number = seq_number; + +if (bi->seq_number ==YAFFS_SEQUENCE_BAD_BLOCK ) + bi->block_state = state =YAFFS_BLOCK_STATE_DEAD ; + +yaffs_trace (YAFFS_TRACE_SCAN_DEBUG , +"Block scanning block %d state %d seq %d" , + blk, state, seq_number); + +if (state ==YAFFS_BLOCK_STATE_DEAD ) { +yaffs_trace (YAFFS_TRACE_BAD_BLOCKS , +"block %d is bad" , blk); + }else if (state ==YAFFS_BLOCK_STATE_EMPTY ) { +yaffs_trace (YAFFS_TRACE_SCAN_DEBUG ,"Block empty " ); + dev->n_erased_blocks++; + dev->n_free_chunks += dev->param.chunks_per_block; + } + bi++; + } + +/* For each block.... */ +for (blk = dev->internal_start_block; + !alloc_failed && blk <= dev->internal_end_block; blk++) { + +cond_resched (); + + bi =yaffs_get_block_info (dev, blk); + state = bi->block_state; + + deleted =0 ; + +/* For each chunk in each block that needs scanning.... */ +for (c =0 ; !alloc_failed && c < dev->param.chunks_per_block && + state ==YAFFS_BLOCK_STATE_NEEDS_SCANNING ; c++) { +/* Read the tags and decide what to do */ + chunk = blk * dev->param.chunks_per_block + c; + + result =yaffs_rd_chunk_tags_nand (dev, chunk,NULL , + &tags); + +/* Let's have a good look at this chunk... */ + +if (tags.ecc_result ==YAFFS_ECC_RESULT_UNFIXED + || tags.is_deleted) { +/* YAFFS1 only... +* A deleted chunk +*/ + deleted++; + dev->n_free_chunks++; + }else if (!tags.chunk_used) { +/* An unassigned chunk in the block +* This means that either the block is empty or +* this is the one being allocated from +*/ + +if (c ==0 ) { +/* We're looking at the first chunk in +*the block so the block is unused */ + state =YAFFS_BLOCK_STATE_EMPTY ; + dev->n_erased_blocks++; + }else { +/* this is the block being allocated */ +yaffs_trace (YAFFS_TRACE_SCAN , +" Allocating from %d %d" , + blk, c); + state =YAFFS_BLOCK_STATE_ALLOCATING ; + dev->alloc_block = blk; + dev->alloc_page = c; + dev->alloc_block_finder = blk; + + } + + dev->n_free_chunks += + (dev->param.chunks_per_block - c); + }else if (tags.chunk_id >0 ) { +/* chunk_id > 0 so it is a data chunk... */ +unsigned int endpos; + +yaffs_set_chunk_bit (dev, blk, c); + bi->pages_in_use++; + + in =yaffs_find_or_create_by_number (dev, + tags.obj_id, +YAFFS_OBJECT_TYPE_FILE ); +/* PutChunkIntoFile checks for a clash +* (two data chunks with the same chunk_id). +*/ + +if (!in) + alloc_failed =1 ; + +if (in) { +if (!yaffs_put_chunk_in_file + (in, tags.chunk_id, chunk,1 )) + alloc_failed =1 ; + } + + endpos = + (tags.chunk_id -1 ) * + dev->data_bytes_per_chunk + + tags.n_bytes; +if (in && + in->variant_type == +YAFFS_OBJECT_TYPE_FILE && + in->variant.file_variant.scanned_size < + endpos) { + in->variant.file_variant.scanned_size = + endpos; +if (!dev->param.use_header_file_size) { + in->variant. + file_variant.file_size = + in->variant. + file_variant.scanned_size; + } + + } + }else { +/* chunk_id == 0, so it is an ObjectHeader. +* Make the object +*/ +yaffs_set_chunk_bit (dev, blk, c); + bi->pages_in_use++; + + result =yaffs_rd_chunk_tags_nand (dev, chunk, + chunk_data, +NULL ); + + oh = (struct yaffs_obj_hdr *)chunk_data; + + in =yaffs_find_by_number (dev, tags.obj_id); +if (in && in->variant_type != oh->type) { +/* This should not happen, but somehow +* Wev'e ended up with an obj_id that +* has been reused but not yet deleted, +* and worse still it has changed type. +* Delete the old object. +*/ + +yaffs_del_obj (in); + in =NULL ; + } + + in =yaffs_find_or_create_by_number (dev, + tags.obj_id, + oh->type); + +if (!in) + alloc_failed =1 ; + +if (in && oh->shadows_obj >0 ) { + +struct yaffs_shadow_fixer *fixer; + fixer = +kmalloc (sizeof + (struct yaffs_shadow_fixer ), +GFP_NOFS ); +if (fixer) { + fixer->next = shadow_fixers; + shadow_fixers = fixer; + fixer->obj_id = tags.obj_id; + fixer->shadowed_id = + oh->shadows_obj; +yaffs_trace (YAFFS_TRACE_SCAN , +" Shadow fixer: %d shadows %d" , + fixer->obj_id, + fixer->shadowed_id); + + } + + } + +if (in && in->valid) { +/* We have already filled this one. +* We have a duplicate and need to +* resolve it. */ + +unsigned existing_serial = in->serial; +unsigned new_serial = + tags.serial_number; + +if (((existing_serial +1 ) &3 ) == + new_serial) { +/* Use new one - destroy the +* exisiting one */ +yaffs_chunk_del (dev, + in->hdr_chunk, +1 , __LINE__); + in->valid =0 ; + }else { +/* Use existing - destroy +* this one. */ +yaffs_chunk_del (dev, chunk,1 , + __LINE__); + } + } + +if (in && !in->valid && + (tags.obj_id ==YAFFS_OBJECTID_ROOT || + tags.obj_id == +YAFFS_OBJECTID_LOSTNFOUND )) { +/* We only load some info, don't fiddle +* with directory structure */ + in->valid =1 ; + in->variant_type = oh->type; + + in->yst_mode = oh->yst_mode; +yaffs_load_attribs (in, oh); + in->hdr_chunk = chunk; + in->serial = tags.serial_number; + + }else if (in && !in->valid) { +/* we need to load this info */ + + in->valid =1 ; + in->variant_type = oh->type; + + in->yst_mode = oh->yst_mode; +yaffs_load_attribs (in, oh); + in->hdr_chunk = chunk; + in->serial = tags.serial_number; + +yaffs_set_obj_name_from_oh (in, oh); + in->dirty =0 ; + +/* directory stuff... +* hook up to parent +*/ + + parent = +yaffs_find_or_create_by_number + (dev, oh->parent_obj_id, +YAFFS_OBJECT_TYPE_DIRECTORY ); +if (!parent) + alloc_failed =1 ; +if (parent && parent->variant_type == +YAFFS_OBJECT_TYPE_UNKNOWN ) { +/* Set up as a directory */ + parent->variant_type = +YAFFS_OBJECT_TYPE_DIRECTORY ; +INIT_LIST_HEAD (&parent-> + variant.dir_variant. + children); + }else if (!parent || + parent->variant_type != +YAFFS_OBJECT_TYPE_DIRECTORY ) { +/* Hoosterman, a problem.... +* We're trying to use a +* non-directory as a directory +*/ + +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." + ); + parent = dev->lost_n_found; + } + +yaffs_add_obj_to_dir (parent, in); + +switch (in->variant_type) { +case YAFFS_OBJECT_TYPE_UNKNOWN : +/* Todo got a problem */ +break ; +case YAFFS_OBJECT_TYPE_FILE : +if (dev->param. + use_header_file_size) + + in->variant. + file_variant.file_size + = oh->file_size; + +break ; +case YAFFS_OBJECT_TYPE_HARDLINK : + in->variant. + hardlink_variant.equiv_id = + oh->equiv_id; + in->hard_links.next = + (struct list_head *) + hard_list; + hard_list = in; +break ; +case YAFFS_OBJECT_TYPE_DIRECTORY : +/* Do nothing */ +break ; +case YAFFS_OBJECT_TYPE_SPECIAL : +/* Do nothing */ +break ; +case YAFFS_OBJECT_TYPE_SYMLINK : + in->variant.symlink_variant. + alias = +yaffs_clone_str (oh->alias); +if (!in->variant. + symlink_variant.alias) + alloc_failed =1 ; +break ; + } + } + } + } + +if (state ==YAFFS_BLOCK_STATE_NEEDS_SCANNING ) { +/* If we got this far while scanning, +* then the block is fully allocated. */ + state =YAFFS_BLOCK_STATE_FULL ; + } + +if (state ==YAFFS_BLOCK_STATE_ALLOCATING ) { +/* If the block was partially allocated then +* treat it as fully allocated. */ + state =YAFFS_BLOCK_STATE_FULL ; + dev->alloc_block =-1 ; + } + + bi->block_state = state; + +/* Now let's see if it was dirty */ +if (bi->pages_in_use ==0 && + !bi->has_shrink_hdr && + bi->block_state ==YAFFS_BLOCK_STATE_FULL ) { +yaffs_block_became_dirty (dev, blk); + } + } + +/* Ok, we've done all the scanning. +* Fix up the hard link chains. +* We should now have scanned all the objects, now it's time to add +* these hardlinks. +*/ + +yaffs_link_fixup (dev, hard_list); + +/* Fix up any shadowed objects */ + { +struct yaffs_shadow_fixer *fixer; +struct yaffs_obj *obj; + +while (shadow_fixers) { + fixer = shadow_fixers; + shadow_fixers = fixer->next; +/* Complete the rename transaction by deleting the +* shadowed object then setting the object header +to unshadowed. +*/ + obj =yaffs_find_by_number (dev, fixer->shadowed_id); +if (obj) +yaffs_del_obj (obj); + + obj =yaffs_find_by_number (dev, fixer->obj_id); + +if (obj) +yaffs_update_oh (obj,NULL ,1 ,0 ,0 ,NULL ); + +kfree (fixer); + } + } + +yaffs_release_temp_buffer (dev, chunk_data, __LINE__); + +if (alloc_failed) +return YAFFS_FAIL ; + +yaffs_trace (YAFFS_TRACE_SCAN ,"yaffs1_scan ends" ); + +return YAFFS_OK ; +}
fs/yaffs2/yaffs_yaffs1.h new file +22 -0
@@ -0,0 +1,22 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_YAFFS1_H__ +#define __YAFFS_YAFFS1_H__ + +#include "yaffs_guts.h" +int yaffs1_scan (struct yaffs_dev *dev); + +#endif
fs/yaffs2/yaffs_yaffs2.c new file +1516 -0
1,516 lines not on this page · raw message
fs/yaffs2/yaffs_yaffs2.h new file +39 -0
@@ -0,0 +1,39 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_YAFFS2_H__ +#define __YAFFS_YAFFS2_H__ + +#include "yaffs_guts.h" + +void yaffs_calc_oldest_dirty_seq (struct yaffs_dev *dev); +void yaffs2_find_oldest_dirty_seq (struct yaffs_dev *dev); +void yaffs2_clear_oldest_dirty_seq (struct yaffs_dev *dev, +struct yaffs_block_info *bi); +void yaffs2_update_oldest_dirty_seq (struct yaffs_dev *dev,unsigned block_no, +struct yaffs_block_info *bi); +int yaffs_block_ok_for_gc (struct yaffs_dev *dev,struct yaffs_block_info *bi); +u32 yaffs2_find_refresh_block (struct yaffs_dev *dev); +int yaffs2_checkpt_required (struct yaffs_dev *dev); +int yaffs_calc_checkpt_blocks_required (struct yaffs_dev *dev); + +void yaffs2_checkpt_invalidate (struct yaffs_dev *dev); +int yaffs2_checkpt_save (struct yaffs_dev *dev); +int yaffs2_checkpt_restore (struct yaffs_dev *dev); + +int yaffs2_handle_hole (struct yaffs_obj *obj,loff_t new_size); +int yaffs2_scan_backwards (struct yaffs_dev *dev); + +#endif
Signature · 1 line
1.7.1
Re: [PATCH 07/10] Add yaffs2 file system: yaffs1 and yaffs2 mode specific code
Quoted 1 line · Charles Manning
Signed-off-by Charles Manning <[email protected]>
More comments below.
~Ryan
Quoted 36 lines
--- fs/yaffs2/yaffs_yaffs1.c | 423 +++++++++++++ fs/yaffs2/yaffs_yaffs1.h | 22 + fs/yaffs2/yaffs_yaffs2.c | 1516 ++++++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_yaffs2.h | 39 ++ 4 files changed, 2000 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_yaffs1.c create mode 100644 fs/yaffs2/yaffs_yaffs1.h create mode 100644 fs/yaffs2/yaffs_yaffs2.c create mode 100644 fs/yaffs2/yaffs_yaffs2.hfs/yaffs2/yaffs_yaffs1.c new file +19
-0@@ -0,0 +1,423 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_yaffs1.h" +#include "yportenv.h" +#include "yaffs_trace.h" +#include "yaffs_bitmap.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_nand.h"
fs/yaffs2/yaffs_yaffs1.c line 29
Quoted 10 lines
fs/yaffs2/yaffs_yaffs1.c new file +10
-0+#include "yaffs_attribs.h" + +int yaffs1_scan (struct yaffs_dev *dev) +{ +struct yaffs_ext_tags tags; +int blk; +int result; +int chunk; +int c; +int deleted;
int blk, result, chunk, c, deleted;
etc, will save some lines.
Quoted 54 lines
fs/yaffs2/yaffs_yaffs1.c new file +54
-0+enum yaffs_block_state state; +struct yaffs_obj *hard_list =NULL ; +struct yaffs_block_info *bi; +u32 seq_number; +struct yaffs_obj_hdr *oh; +struct yaffs_obj *in; +struct yaffs_obj *parent; +int alloc_failed =0 ; +struct yaffs_shadow_fixer *shadow_fixers =NULL ; +u8 *chunk_data; + +yaffs_trace (YAFFS_TRACE_SCAN , +"yaffs1_scan starts intstartblk %d intendblk %d..." , + dev->internal_start_block, dev->internal_end_block); + + chunk_data =yaffs_get_temp_buffer (dev, __LINE__); + + dev->seq_number =YAFFS_LOWEST_SEQUENCE_NUMBER ; + +/* Scan all the blocks to determine their state */ + bi = dev->block_info; +for (blk = dev->internal_start_block; blk <= dev->internal_end_block; + blk++) { +yaffs_clear_chunk_bits (dev, blk); + bi->pages_in_use =0 ; + bi->soft_del_pages =0 ; + +yaffs_query_init_block_state (dev, blk, &state, &seq_number); + + bi->block_state = state; + bi->seq_number = seq_number; + +if (bi->seq_number ==YAFFS_SEQUENCE_BAD_BLOCK ) + bi->block_state = state =YAFFS_BLOCK_STATE_DEAD ; + +yaffs_trace (YAFFS_TRACE_SCAN_DEBUG , +"Block scanning block %d state %d seq %d" , + blk, state, seq_number); + +if (state ==YAFFS_BLOCK_STATE_DEAD ) { +yaffs_trace (YAFFS_TRACE_BAD_BLOCKS , +"block %d is bad" , blk); + }else if (state ==YAFFS_BLOCK_STATE_EMPTY ) { +yaffs_trace (YAFFS_TRACE_SCAN_DEBUG ,"Block empty " ); + dev->n_erased_blocks++; + dev->n_free_chunks += dev->param.chunks_per_block; + } + bi++; + } + +/* For each block.... */ +for (blk = dev->internal_start_block; + !alloc_failed && blk <= dev->internal_end_block; blk++) { +
fs/yaffs2/yaffs_yaffs1.c line 93
Quoted 10 lines
fs/yaffs2/yaffs_yaffs1.c new file +10
-0+cond_resched (); + + bi =yaffs_get_block_info (dev, blk); + state = bi->block_state; + + deleted =0 ; + +/* For each chunk in each block that needs scanning.... */ +for (c =0 ; !alloc_failed && c < dev->param.chunks_per_block && + state ==YAFFS_BLOCK_STATE_NEEDS_SCANNING ; c++) {
Maybe worth breaking parts of the body of this loop into sub functions to reduce the indentation level and make everything a bit more readable.
Quoted 52 lines
fs/yaffs2/yaffs_yaffs1.c new file +52
-0+/* Read the tags and decide what to do */ + chunk = blk * dev->param.chunks_per_block + c; + + result =yaffs_rd_chunk_tags_nand (dev, chunk,NULL , + &tags); + +/* Let's have a good look at this chunk... */ + +if (tags.ecc_result ==YAFFS_ECC_RESULT_UNFIXED + || tags.is_deleted) { +/* YAFFS1 only... +* A deleted chunk +*/ + deleted++; + dev->n_free_chunks++; + }else if (!tags.chunk_used) { +/* An unassigned chunk in the block +* This means that either the block is empty or +* this is the one being allocated from +*/ + +if (c ==0 ) { +/* We're looking at the first chunk in +*the block so the block is unused */ + state =YAFFS_BLOCK_STATE_EMPTY ; + dev->n_erased_blocks++; + }else { +/* this is the block being allocated */ +yaffs_trace (YAFFS_TRACE_SCAN , +" Allocating from %d %d" , + blk, c); + state =YAFFS_BLOCK_STATE_ALLOCATING ; + dev->alloc_block = blk; + dev->alloc_page = c; + dev->alloc_block_finder = blk; + + } + + dev->n_free_chunks += + (dev->param.chunks_per_block - c); + }else if (tags.chunk_id >0 ) { +/* chunk_id > 0 so it is a data chunk... */ +unsigned int endpos; + +yaffs_set_chunk_bit (dev, blk, c); + bi->pages_in_use++; + + in =yaffs_find_or_create_by_number (dev, + tags.obj_id, +YAFFS_OBJECT_TYPE_FILE ); +/* PutChunkIntoFile checks for a clash +* (two data chunks with the same chunk_id).
fs/yaffs2/yaffs_yaffs1.c line 155
Quoted 10 lines
fs/yaffs2/yaffs_yaffs1.c new file +10
-0+*/ + +if (!in) + alloc_failed =1 ; + +if (in) { +if (!yaffs_put_chunk_in_file + (in, tags.chunk_id, chunk,1 )) + alloc_failed =1 ; + }
This looks like it could be simplified a little by replacing 'alloc_failed = 1' statement with a 'goto alloc_failed'. It means that you don't have keep checking to make sure in is valid.
Quoted 34 lines
fs/yaffs2/yaffs_yaffs1.c new file +34
-0+ + endpos = + (tags.chunk_id -1 ) * + dev->data_bytes_per_chunk + + tags.n_bytes; +if (in && + in->variant_type == +YAFFS_OBJECT_TYPE_FILE && + in->variant.file_variant.scanned_size < + endpos) { + in->variant.file_variant.scanned_size = + endpos; +if (!dev->param.use_header_file_size) { + in->variant. + file_variant.file_size = + in->variant. + file_variant.scanned_size; + } + + } + }else { +/* chunk_id == 0, so it is an ObjectHeader. +* Make the object +*/ +yaffs_set_chunk_bit (dev, blk, c); + bi->pages_in_use++; + + result =yaffs_rd_chunk_tags_nand (dev, chunk, + chunk_data, +NULL ); + + oh = (struct yaffs_obj_hdr *)chunk_data; + + in =yaffs_find_by_number (dev, tags.obj_id);
fs/yaffs2/yaffs_yaffs1.c line 199
Quoted 10 lines
fs/yaffs2/yaffs_yaffs1.c new file +10
-0+if (in && in->variant_type != oh->type) { +/* This should not happen, but somehow +* Wev'e ended up with an obj_id that +* has been reused but not yet deleted, +* and worse still it has changed type. +* Delete the old object. +*/ + +yaffs_del_obj (in); + in =NULL ;
You don't need the assignment to NULL here.
Quoted 6 lines
fs/yaffs2/yaffs_yaffs1.c new file +6
-0+ } + + in =yaffs_find_or_create_by_number (dev, + tags.obj_id, + oh->type); +
fs/yaffs2/yaffs_yaffs1.c line 215
Quoted 10 lines
fs/yaffs2/yaffs_yaffs1.c new file +10
-0+if (!in) + alloc_failed =1 ; + +if (in && oh->shadows_obj >0 ) { + +struct yaffs_shadow_fixer *fixer; + fixer = +kmalloc (sizeof + (struct yaffs_shadow_fixer ), +GFP_NOFS );
if (!fixer)? Do we want a warning?
Fixers could also use struct list_head rather than their own (albeit simple) linked list implementation.
Quoted 68 lines
fs/yaffs2/yaffs_yaffs1.c new file +68
-0+if (fixer) { + fixer->next = shadow_fixers; + shadow_fixers = fixer; + fixer->obj_id = tags.obj_id; + fixer->shadowed_id = + oh->shadows_obj; +yaffs_trace (YAFFS_TRACE_SCAN , +" Shadow fixer: %d shadows %d" , + fixer->obj_id, + fixer->shadowed_id); + + } + + } + +if (in && in->valid) { +/* We have already filled this one. +* We have a duplicate and need to +* resolve it. */ + +unsigned existing_serial = in->serial; +unsigned new_serial = + tags.serial_number; + +if (((existing_serial +1 ) &3 ) == + new_serial) { +/* Use new one - destroy the +* exisiting one */ +yaffs_chunk_del (dev, + in->hdr_chunk, +1 , __LINE__); + in->valid =0 ; + }else { +/* Use existing - destroy +* this one. */ +yaffs_chunk_del (dev, chunk,1 , + __LINE__); + } + } + +if (in && !in->valid && + (tags.obj_id ==YAFFS_OBJECTID_ROOT || + tags.obj_id == +YAFFS_OBJECTID_LOSTNFOUND )) { +/* We only load some info, don't fiddle +* with directory structure */ + in->valid =1 ; + in->variant_type = oh->type; + + in->yst_mode = oh->yst_mode; +yaffs_load_attribs (in, oh); + in->hdr_chunk = chunk; + in->serial = tags.serial_number; + + }else if (in && !in->valid) { +/* we need to load this info */ + + in->valid =1 ; + in->variant_type = oh->type; + + in->yst_mode = oh->yst_mode; +yaffs_load_attribs (in, oh); + in->hdr_chunk = chunk; + in->serial = tags.serial_number; + +yaffs_set_obj_name_from_oh (in, oh); + in->dirty =0 ; +
fs/yaffs2/yaffs_yaffs1.c line 293
Quoted 10 lines
fs/yaffs2/yaffs_yaffs1.c new file +10
-0+/* directory stuff... +* hook up to parent +*/ + + parent = +yaffs_find_or_create_by_number + (dev, oh->parent_obj_id, +YAFFS_OBJECT_TYPE_DIRECTORY ); +if (!parent) + alloc_failed =1 ;
Again, using a goto to get out of the loop here will simplify the if statements below.
Quoted 5 lines
fs/yaffs2/yaffs_yaffs1.c new file +5
-0+if (parent && parent->variant_type == +YAFFS_OBJECT_TYPE_UNKNOWN ) { +/* Set up as a directory */ + parent->variant_type = +YAFFS_OBJECT_TYPE_DIRECTORY ;
fs/yaffs2/yaffs_yaffs1.c line 308
Quoted 10 lines
fs/yaffs2/yaffs_yaffs1.c new file +10
-0+INIT_LIST_HEAD (&parent-> + variant.dir_variant. + children); + }else if (!parent || + parent->variant_type != +YAFFS_OBJECT_TYPE_DIRECTORY ) { +/* Hoosterman, a problem.... +* We're trying to use a +* non-directory as a directory +*/
You can drop this comment, the yaffs_trace has the same information.
fs/yaffs2/yaffs_yaffs1.c line 320
Quoted 12 lines
fs/yaffs2/yaffs_yaffs1.c new file +12
-0+ +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." + ); + parent = dev->lost_n_found; + } + +yaffs_add_obj_to_dir (parent, in); + +switch (in->variant_type) { +case YAFFS_OBJECT_TYPE_UNKNOWN : +/* Todo got a problem */
Warning?
Quoted 7 lines
fs/yaffs2/yaffs_yaffs1.c new file +7
-0+break ; +case YAFFS_OBJECT_TYPE_FILE : +if (dev->param. + use_header_file_size) + + in->variant. + file_variant.file_size
fs/yaffs2/yaffs_yaffs1.c line 337
Quoted 10 lines
fs/yaffs2/yaffs_yaffs1.c new file +10
-0+ = oh->file_size; + +break ; +case YAFFS_OBJECT_TYPE_HARDLINK : + in->variant. + hardlink_variant.equiv_id = + oh->equiv_id; + in->hard_links.next = + (struct list_head *) + hard_list;
More linked list casting weirdness?
Quoted 46 lines
fs/yaffs2/yaffs_yaffs1.c new file +46
-0+ hard_list = in; +break ; +case YAFFS_OBJECT_TYPE_DIRECTORY : +/* Do nothing */ +break ; +case YAFFS_OBJECT_TYPE_SPECIAL : +/* Do nothing */ +break ; +case YAFFS_OBJECT_TYPE_SYMLINK : + in->variant.symlink_variant. + alias = +yaffs_clone_str (oh->alias); +if (!in->variant. + symlink_variant.alias) + alloc_failed =1 ; +break ; + } + } + } + } + +if (state ==YAFFS_BLOCK_STATE_NEEDS_SCANNING ) { +/* If we got this far while scanning, +* then the block is fully allocated. */ + state =YAFFS_BLOCK_STATE_FULL ; + } + +if (state ==YAFFS_BLOCK_STATE_ALLOCATING ) { +/* If the block was partially allocated then +* treat it as fully allocated. */ + state =YAFFS_BLOCK_STATE_FULL ; + dev->alloc_block =-1 ; + } + + bi->block_state = state; + +/* Now let's see if it was dirty */ +if (bi->pages_in_use ==0 && + !bi->has_shrink_hdr && + bi->block_state ==YAFFS_BLOCK_STATE_FULL ) { +yaffs_block_became_dirty (dev, blk); + } + } + +/* Ok, we've done all the scanning. +* Fix up the hard link chains.
fs/yaffs2/yaffs_yaffs1.c line 393
Quoted 10 lines
fs/yaffs2/yaffs_yaffs1.c new file +10
-0+* We should now have scanned all the objects, now it's time to add +* these hardlinks. +*/ + +yaffs_link_fixup (dev, hard_list); + +/* Fix up any shadowed objects */ + { +struct yaffs_shadow_fixer *fixer; +struct yaffs_obj *obj;
Move these to the top of the function (or reuse existing ones) and remove a level of indentation :-)
Quoted 130 lines
fs/yaffs2/yaffs_yaffs1.c new file +30
-0+ +while (shadow_fixers) { + fixer = shadow_fixers; + shadow_fixers = fixer->next; +/* Complete the rename transaction by deleting the +* shadowed object then setting the object header +to unshadowed. +*/ + obj =yaffs_find_by_number (dev, fixer->shadowed_id); +if (obj) +yaffs_del_obj (obj); + + obj =yaffs_find_by_number (dev, fixer->obj_id); + +if (obj) +yaffs_update_oh (obj,NULL ,1 ,0 ,0 ,NULL ); + +kfree (fixer); + } + } + +yaffs_release_temp_buffer (dev, chunk_data, __LINE__); + +if (alloc_failed) +return YAFFS_FAIL ; + +yaffs_trace (YAFFS_TRACE_SCAN ,"yaffs1_scan ends" ); + +return YAFFS_OK ; +}fs/yaffs2/yaffs_yaffs1.h new file +22
-0@@ -0,0 +1,22 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_YAFFS1_H__ +#define __YAFFS_YAFFS1_H__ + +#include "yaffs_guts.h" +int yaffs1_scan (struct yaffs_dev *dev); + +#endif fs/yaffs2/yaffs_yaffs2.c new file +66
-0@@ -0,0 +1,1516 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yaffs_guts.h" +#include "yaffs_trace.h" +#include "yaffs_yaffs2.h" +#include "yaffs_checkptrw.h" +#include "yaffs_bitmap.h" +#include "yaffs_nand.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_verify.h" +#include "yaffs_attribs.h" + +/* +* Checkpoints are really no benefit on very small partitions. +* +* To save space on small partitions don't bother with checkpoints unless +* the partition is at least this big. +*/ +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60 +#define YAFFS_SMALL_HOLE_THRESHOLD 4 + +/* +* Oldest Dirty Sequence Number handling. +*/ + +/* yaffs_calc_oldest_dirty_seq() +* yaffs2_find_oldest_dirty_seq() +* Calculate the oldest dirty sequence number if we don't know it. +*/ +void yaffs_calc_oldest_dirty_seq (struct yaffs_dev *dev) +{ +int i; +unsigned seq; +unsigned block_no =0 ; +struct yaffs_block_info *b; + +if (!dev->param.is_yaffs2) +return ; + +/* Find the oldest dirty sequence number. */ + seq = dev->seq_number +1 ; + b = dev->block_info; +for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { +if (b->block_state ==YAFFS_BLOCK_STATE_FULL && + (b->pages_in_use - b->soft_del_pages) < + dev->param.chunks_per_block && b->seq_number < seq) { + seq = b->seq_number; + block_no = i; + } + b++; + } + +if (block_no) { + dev->oldest_dirty_seq = seq; + dev->oldest_dirty_block = block_no;
fs/yaffs2/yaffs_yaffs2.c line 76
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+ } +} + +void yaffs2_find_oldest_dirty_seq (struct yaffs_dev *dev) +{ +if (!dev->param.is_yaffs2) +return ; + +if (!dev->oldest_dirty_seq) +yaffs_calc_oldest_dirty_seq (dev);
if (dev->param.is_yaffs2 && !dev->oldest_dirty_seq)
yaffs_calc_oldest_dirty_seq(dev);
Similar reductions are possible for other functions. Also, can we actually end up here if dev->param.is_yaffs2 is not set?
Quoted 168 lines
fs/yaffs2/yaffs_yaffs2.c new file +168
-0+} + +/* +* yaffs_clear_oldest_dirty_seq() +* Called when a block is erased or marked bad. (ie. when its seq_number +* becomes invalid). If the value matches the oldest then we clear +* dev->oldest_dirty_seq to force its recomputation. +*/ +void yaffs2_clear_oldest_dirty_seq (struct yaffs_dev *dev, +struct yaffs_block_info *bi) +{ + +if (!dev->param.is_yaffs2) +return ; + +if (!bi || bi->seq_number == dev->oldest_dirty_seq) { + dev->oldest_dirty_seq =0 ; + dev->oldest_dirty_block =0 ; + } +} + +/* +* yaffs2_update_oldest_dirty_seq() +* Update the oldest dirty sequence number whenever we dirty a block. +* Only do this if the oldest_dirty_seq is actually being tracked. +*/ +void yaffs2_update_oldest_dirty_seq (struct yaffs_dev *dev,unsigned block_no, +struct yaffs_block_info *bi) +{ +if (!dev->param.is_yaffs2) +return ; + +if (dev->oldest_dirty_seq) { +if (dev->oldest_dirty_seq > bi->seq_number) { + dev->oldest_dirty_seq = bi->seq_number; + dev->oldest_dirty_block = block_no; + } + } +} + +int yaffs_block_ok_for_gc (struct yaffs_dev *dev,struct yaffs_block_info *bi) +{ + +if (!dev->param.is_yaffs2) +return 1 ;/* disqualification only applies to yaffs2. */ + +if (!bi->has_shrink_hdr) +return 1 ;/* can gc */ + +yaffs2_find_oldest_dirty_seq (dev); + +/* Can't do gc of this block if there are any blocks older than this +* one that have discarded pages. +*/ +return (bi->seq_number <= dev->oldest_dirty_seq); +} + +/* +* yaffs2_find_refresh_block() +* periodically finds the oldest full block by sequence number for refreshing. +* Only for yaffs2. +*/ +u32 yaffs2_find_refresh_block (struct yaffs_dev *dev) +{ +u32 b; +u32 oldest =0 ; +u32 oldest_seq =0 ; +struct yaffs_block_info *bi; + +if (!dev->param.is_yaffs2) +return oldest; + +/* +* If refresh period < 10 then refreshing is disabled. +*/ +if (dev->param.refresh_period <10 ) +return oldest; + +/* +* Fix broken values. +*/ +if (dev->refresh_skip > dev->param.refresh_period) + dev->refresh_skip = dev->param.refresh_period; + +if (dev->refresh_skip >0 ) +return oldest; + +/* +* Refresh skip is now zero. +* We'll do a refresh this time around.... +* Update the refresh skip and find the oldest block. +*/ + dev->refresh_skip = dev->param.refresh_period; + dev->refresh_count++; + bi = dev->block_info; +for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { + +if (bi->block_state ==YAFFS_BLOCK_STATE_FULL ) { + +if (oldest <1 || bi->seq_number < oldest_seq) { + oldest = b; + oldest_seq = bi->seq_number; + } + } + bi++; + } + +if (oldest >0 ) { +yaffs_trace (YAFFS_TRACE_GC , +"GC refresh count %d selected block %d with seq_number %d" , + dev->refresh_count, oldest, oldest_seq); + } + +return oldest; +} + +int yaffs2_checkpt_required (struct yaffs_dev *dev) +{ +int nblocks; + +if (!dev->param.is_yaffs2) +return 0 ; + + nblocks = dev->internal_end_block - dev->internal_start_block +1 ; + +return !dev->param.skip_checkpt_wr && + !dev->read_only && (nblocks >=YAFFS_CHECKPOINT_MIN_BLOCKS ); +} + +int yaffs_calc_checkpt_blocks_required (struct yaffs_dev *dev) +{ +int retval; + +if (!dev->param.is_yaffs2) +return 0 ; + +if (!dev->checkpoint_blocks_required &&yaffs2_checkpt_required (dev)) { +/* Not a valid value so recalculate */ +int n_bytes =0 ; +int n_blocks; +int dev_blocks = + (dev->param.end_block - dev->param.start_block +1 ); + + n_bytes +=sizeof (struct yaffs_checkpt_validity ); + n_bytes +=sizeof (struct yaffs_checkpt_dev ); + n_bytes += dev_blocks *sizeof (struct yaffs_block_info ); + n_bytes += dev_blocks * dev->chunk_bit_stride; + n_bytes += + (sizeof (struct yaffs_checkpt_obj ) +sizeof (u32)) * + dev->n_obj; + n_bytes += (dev->tnode_size +sizeof (u32)) * dev->n_tnodes; + n_bytes +=sizeof (struct yaffs_checkpt_validity ); + n_bytes +=sizeof (u32);/* checksum */ + +/* Round up and add 2 blocks to allow for some bad blocks, +* so add 3 */ + + n_blocks = + (n_bytes / + (dev->data_bytes_per_chunk * + dev->param.chunks_per_block)) +3 ; + + dev->checkpoint_blocks_required = n_blocks; + } + + retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt; +if (retval <0 ) + retval =0 ;
fs/yaffs2/yaffs_yaffs2.c line 254
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+return retval; +} + +/*--------------------- Checkpointing --------------------*/ + +static int yaffs2_wr_checkpt_validity_marker (struct yaffs_dev *dev,int head) +{ +struct yaffs_checkpt_validity cp; + +memset (&cp,0 ,sizeof (cp));
Just initialise cp = {0} and drop the memset.
fs/yaffs2/yaffs_yaffs2.c line 259
Quoted 4 lines
fs/yaffs2/yaffs_yaffs2.c new file +4
-0+ cp.struct_type =sizeof (cp); + cp.magic =YAFFS_MAGIC ; + cp.version =YAFFS_CHECKPOINT_VERSION ; + cp.head = (head) ?1 :0 ;
Don't need parens around head. Can also do:
cp.head = !!head;
Quoted 6 lines
fs/yaffs2/yaffs_yaffs2.c new file +6
-0+ +return (yaffs2_checkpt_wr (dev, &cp,sizeof (cp)) ==sizeof (cp)) ?1 :0 ; +} + +static int yaffs2_rd_checkpt_validity_marker (struct yaffs_dev *dev,int head) +{
fs/yaffs2/yaffs_yaffs2.c line 275
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+struct yaffs_checkpt_validity cp; +int ok; + + ok = (yaffs2_checkpt_rd (dev, &cp,sizeof (cp)) ==sizeof (cp)); + +if (ok) + ok = (cp.struct_type ==sizeof (cp)) && + (cp.magic ==YAFFS_MAGIC ) && + (cp.version ==YAFFS_CHECKPOINT_VERSION ) && + (cp.head == ((head) ?1 :0 ));
just cp.head == head should suffice.
Quoted 50 lines
fs/yaffs2/yaffs_yaffs2.c new file +50
-0+return ok ?1 :0 ; +} + +static void yaffs2_dev_to_checkpt_dev (struct yaffs_checkpt_dev *cp, +struct yaffs_dev *dev) +{ + cp->n_erased_blocks = dev->n_erased_blocks; + cp->alloc_block = dev->alloc_block; + cp->alloc_page = dev->alloc_page; + cp->n_free_chunks = dev->n_free_chunks; + + cp->n_deleted_files = dev->n_deleted_files; + cp->n_unlinked_files = dev->n_unlinked_files; + cp->n_bg_deletions = dev->n_bg_deletions; + cp->seq_number = dev->seq_number; + +} + +static void yaffs_checkpt_dev_to_dev (struct yaffs_dev *dev, +struct yaffs_checkpt_dev *cp) +{ + dev->n_erased_blocks = cp->n_erased_blocks; + dev->alloc_block = cp->alloc_block; + dev->alloc_page = cp->alloc_page; + dev->n_free_chunks = cp->n_free_chunks; + + dev->n_deleted_files = cp->n_deleted_files; + dev->n_unlinked_files = cp->n_unlinked_files; + dev->n_bg_deletions = cp->n_bg_deletions; + dev->seq_number = cp->seq_number; +} + +static int yaffs2_wr_checkpt_dev (struct yaffs_dev *dev) +{ +struct yaffs_checkpt_dev cp; +u32 n_bytes; +u32 n_blocks = + (dev->internal_end_block - dev->internal_start_block +1 ); +int ok; + +/* Write device runtime values */ +yaffs2_dev_to_checkpt_dev (&cp, dev); + cp.struct_type =sizeof (cp); + + ok = (yaffs2_checkpt_wr (dev, &cp,sizeof (cp)) ==sizeof (cp)); + +/* Write block info */ +if (ok) { + n_bytes = n_blocks *sizeof (struct yaffs_block_info ); + ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) ==
fs/yaffs2/yaffs_yaffs2.c line 335
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+ n_bytes); + } + +/* Write chunk bits */ +if (ok) { + n_bytes = n_blocks * dev->chunk_bit_stride; + ok = (yaffs2_checkpt_wr (dev, dev->chunk_bits, n_bytes) == + n_bytes); + } +return ok ?1 :0 ;
Just return ok. You shouldn't need ? 1 : 0 everywhere.
Quoted 108 lines
fs/yaffs2/yaffs_yaffs2.c new file +108
-0+} + +static int yaffs2_rd_checkpt_dev (struct yaffs_dev *dev) +{ +struct yaffs_checkpt_dev cp; +u32 n_bytes; +u32 n_blocks = + (dev->internal_end_block - dev->internal_start_block +1 ); +int ok; + + ok = (yaffs2_checkpt_rd (dev, &cp,sizeof (cp)) ==sizeof (cp)); +if (!ok) +return 0 ; + +if (cp.struct_type !=sizeof (cp)) +return 0 ; + +yaffs_checkpt_dev_to_dev (dev, &cp); + + n_bytes = n_blocks *sizeof (struct yaffs_block_info ); + + ok = (yaffs2_checkpt_rd (dev, dev->block_info, n_bytes) == n_bytes); + +if (!ok) +return 0 ; + n_bytes = n_blocks * dev->chunk_bit_stride; + + ok = (yaffs2_checkpt_rd (dev, dev->chunk_bits, n_bytes) == n_bytes); + +return ok ?1 :0 ; +} + +static void yaffs2_obj_checkpt_obj (struct yaffs_checkpt_obj *cp, +struct yaffs_obj *obj) +{ + cp->obj_id = obj->obj_id; + cp->parent_id = (obj->parent) ? obj->parent->obj_id :0 ; + cp->hdr_chunk = obj->hdr_chunk; + cp->variant_type = obj->variant_type; + cp->deleted = obj->deleted; + cp->soft_del = obj->soft_del; + cp->unlinked = obj->unlinked; + cp->fake = obj->fake; + cp->rename_allowed = obj->rename_allowed; + cp->unlink_allowed = obj->unlink_allowed; + cp->serial = obj->serial; + cp->n_data_chunks = obj->n_data_chunks; + +if (obj->variant_type ==YAFFS_OBJECT_TYPE_FILE ) + cp->size_or_equiv_obj = obj->variant.file_variant.file_size; +else if (obj->variant_type ==YAFFS_OBJECT_TYPE_HARDLINK ) + cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id; +} + +static int taffs2_checkpt_obj_to_obj (struct yaffs_obj *obj, +struct yaffs_checkpt_obj *cp) +{ +struct yaffs_obj *parent; + +if (obj->variant_type != cp->variant_type) { +yaffs_trace (YAFFS_TRACE_ERROR , +"Checkpoint read object %d type %d chunk %d does not match existing object type %d" , + cp->obj_id, cp->variant_type, cp->hdr_chunk, + obj->variant_type); +return 0 ; + } + + obj->obj_id = cp->obj_id; + +if (cp->parent_id) + parent =yaffs_find_or_create_by_number (obj->my_dev, + cp->parent_id, +YAFFS_OBJECT_TYPE_DIRECTORY ); +else + parent =NULL ; + +if (parent) { +if (parent->variant_type !=YAFFS_OBJECT_TYPE_DIRECTORY ) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory" , + cp->obj_id, cp->parent_id, + cp->variant_type, cp->hdr_chunk, + parent->variant_type); +return 0 ; + } +yaffs_add_obj_to_dir (parent, obj); + } + + obj->hdr_chunk = cp->hdr_chunk; + obj->variant_type = cp->variant_type; + obj->deleted = cp->deleted; + obj->soft_del = cp->soft_del; + obj->unlinked = cp->unlinked; + obj->fake = cp->fake; + obj->rename_allowed = cp->rename_allowed; + obj->unlink_allowed = cp->unlink_allowed; + obj->serial = cp->serial; + obj->n_data_chunks = cp->n_data_chunks; + +if (obj->variant_type ==YAFFS_OBJECT_TYPE_FILE ) + obj->variant.file_variant.file_size = cp->size_or_equiv_obj; +else if (obj->variant_type ==YAFFS_OBJECT_TYPE_HARDLINK ) + obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj; + +if (obj->hdr_chunk >0 ) + obj->lazy_loaded =1 ; +return 1 ; +}
fs/yaffs2/yaffs_yaffs2.c line 453
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+ +static int yaffs2_checkpt_tnode_worker (struct yaffs_obj *in, +struct yaffs_tnode *tn,u32 level, +int chunk_offset) +{ +int i; +struct yaffs_dev *dev = in->my_dev; +int ok =1 ; + +if (tn) {
if (!tn) return 1;
Then reduce the indentation :-).
Quoted 24 lines
fs/yaffs2/yaffs_yaffs2.c new file +24
-0+if (level >0 ) { + +for (i =0 ; i <YAFFS_NTNODES_INTERNAL && ok; i++) { +if (tn->internal[i]) { + ok =yaffs2_checkpt_tnode_worker (in, + tn->internal[i], + level -1 , + (chunk_offset << +YAFFS_TNODES_INTERNAL_BITS ) + + i); + } + } + }else if (level ==0 ) { +u32 base_offset = + chunk_offset <<YAFFS_TNODES_LEVEL0_BITS ; + ok = (yaffs2_checkpt_wr + (dev, &base_offset, +sizeof (base_offset)) ==sizeof (base_offset)); +if (ok) + ok = (yaffs2_checkpt_wr + (dev, tn, + dev->tnode_size) == dev->tnode_size); + } + }
fs/yaffs2/yaffs_yaffs2.c line 487
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+ +return ok; +} + +static int yaffs2_wr_checkpt_tnodes (struct yaffs_obj *obj) +{ +u32 end_marker = ~0 ; +int ok =1 ; + +if (obj->variant_type ==YAFFS_OBJECT_TYPE_FILE ) {
Same here, reverse the if statement and reduce the indentation.
Quoted 59 lines
fs/yaffs2/yaffs_yaffs2.c new file +59
-0+ ok =yaffs2_checkpt_tnode_worker (obj, + obj->variant.file_variant.top, + obj->variant.file_variant. + top_level,0 ); +if (ok) + ok = (yaffs2_checkpt_wr + (obj->my_dev, &end_marker, +sizeof (end_marker)) ==sizeof (end_marker)); + } + +return ok ?1 :0 ; +} + +static int yaffs2_rd_checkpt_tnodes (struct yaffs_obj *obj) +{ +u32 base_chunk; +int ok =1 ; +struct yaffs_dev *dev = obj->my_dev; +struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant; +struct yaffs_tnode *tn; +int nread =0 ; + + ok = (yaffs2_checkpt_rd (dev, &base_chunk,sizeof (base_chunk)) == +sizeof (base_chunk)); + +while (ok && (~base_chunk)) { + nread++; +/* Read level 0 tnode */ + + tn =yaffs_get_tnode (dev); +if (tn) + ok = (yaffs2_checkpt_rd (dev, tn, dev->tnode_size) == + dev->tnode_size); +else + ok =0 ; + +if (tn && ok) + ok =yaffs_add_find_tnode_0 (dev, + file_stuct_ptr, + base_chunk, tn) ?1 :0 ; + +if (ok) + ok = (yaffs2_checkpt_rd + (dev, &base_chunk, +sizeof (base_chunk)) ==sizeof (base_chunk)); + } + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"Checkpoint read tnodes %d records, last %d. ok %d" , + nread, base_chunk, ok); + +return ok ?1 :0 ; +} + +static int yaffs2_wr_checkpt_objs (struct yaffs_dev *dev) +{ +struct yaffs_obj *obj; +struct yaffs_checkpt_obj cp; +int i;
fs/yaffs2/yaffs_yaffs2.c line 556
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+int ok =1 ; +struct list_head *lh; + +/* Iterate through the objects in each hash entry, +* dumping them to the checkpointing stream. +*/ + +for (i =0 ; ok && i <YAFFS_NOBJECT_BUCKETS ; i++) { +list_for_each (lh, &dev->obj_bucket[i].list) { + obj = list_entry(lh, struct yaffs_obj, hash_link);
list_for_each_entry(lh, &dev->obj_bucket[i].list, hash_link)
Quoted 87 lines
fs/yaffs2/yaffs_yaffs2.c new file +87
-0+if (!obj->defered_free) { +yaffs2_obj_checkpt_obj (&cp, obj); + cp.struct_type =sizeof (cp); + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"Checkpoint write object %d parent %d type %d chunk %d obj addr %p" , + cp.obj_id, cp.parent_id, + cp.variant_type, cp.hdr_chunk, obj); + + ok = (yaffs2_checkpt_wr (dev, &cp, +sizeof (cp)) ==sizeof (cp)); + +if (ok && + obj->variant_type == +YAFFS_OBJECT_TYPE_FILE ) + ok =yaffs2_wr_checkpt_tnodes (obj); + } + } + } + +/* Dump end of list */ +memset (&cp,0xFF ,sizeof (struct yaffs_checkpt_obj )); + cp.struct_type =sizeof (cp); + +if (ok) + ok = (yaffs2_checkpt_wr (dev, &cp,sizeof (cp)) ==sizeof (cp)); + +return ok ?1 :0 ; +} + +static int yaffs2_rd_checkpt_objs (struct yaffs_dev *dev) +{ +struct yaffs_obj *obj; +struct yaffs_checkpt_obj cp; +int ok =1 ; +int done =0 ; +struct yaffs_obj *hard_list =NULL ; + +while (ok && !done) { + ok = (yaffs2_checkpt_rd (dev, &cp,sizeof (cp)) ==sizeof (cp)); +if (cp.struct_type !=sizeof (cp)) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"struct size %d instead of %d ok %d" , + cp.struct_type, (int )sizeof (cp), ok); + ok =0 ; + } + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"Checkpoint read object %d parent %d type %d chunk %d " , + cp.obj_id, cp.parent_id, cp.variant_type, + cp.hdr_chunk); + +if (ok && cp.obj_id == ~0 ) { + done =1 ; + }else if (ok) { + obj = +yaffs_find_or_create_by_number (dev, cp.obj_id, + cp.variant_type); +if (obj) { + ok =taffs2_checkpt_obj_to_obj (obj, &cp); +if (!ok) +break ; +if (obj->variant_type == +YAFFS_OBJECT_TYPE_FILE ) { + ok =yaffs2_rd_checkpt_tnodes (obj); + }else if (obj->variant_type == +YAFFS_OBJECT_TYPE_HARDLINK ) { + obj->hard_links.next = + (struct list_head *)hard_list; + hard_list = obj; + } + }else { + ok =0 ; + } + } + } + +if (ok) +yaffs_link_fixup (dev, hard_list); + +return ok ?1 :0 ; +} + +static int yaffs2_wr_checkpt_sum (struct yaffs_dev *dev) +{ +u32 checkpt_sum; +int ok;
fs/yaffs2/yaffs_yaffs2.c line 653
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+ +yaffs2_get_checkpt_sum (dev, &checkpt_sum); + + ok = (yaffs2_checkpt_wr (dev, &checkpt_sum,sizeof (checkpt_sum)) == +sizeof (checkpt_sum)); + +if (!ok) +return 0 ; + +return 1 ;
return ok; ?
Quoted 56 lines
fs/yaffs2/yaffs_yaffs2.c new file +56
-0+} + +static int yaffs2_rd_checkpt_sum (struct yaffs_dev *dev) +{ +u32 checkpt_sum0; +u32 checkpt_sum1; +int ok; + +yaffs2_get_checkpt_sum (dev, &checkpt_sum0); + + ok = (yaffs2_checkpt_rd (dev, &checkpt_sum1,sizeof (checkpt_sum1)) == +sizeof (checkpt_sum1)); + +if (!ok) +return 0 ; + +if (checkpt_sum0 != checkpt_sum1) +return 0 ; + +return 1 ; +} + +static int yaffs2_wr_checkpt_data (struct yaffs_dev *dev) +{ +int ok =1 ; + +if (!yaffs2_checkpt_required (dev)) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"skipping checkpoint write" ); + ok =0 ; + } + +if (ok) + ok =yaffs2_checkpt_open (dev,1 ); + +if (ok) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"write checkpoint validity" ); + ok =yaffs2_wr_checkpt_validity_marker (dev,1 ); + } +if (ok) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"write checkpoint device" ); + ok =yaffs2_wr_checkpt_dev (dev); + } +if (ok) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"write checkpoint objects" ); + ok =yaffs2_wr_checkpt_objs (dev); + } +if (ok) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"write checkpoint validity" ); + ok =yaffs2_wr_checkpt_validity_marker (dev,0 ); + } +
fs/yaffs2/yaffs_yaffs2.c line 719
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+if (ok) + ok =yaffs2_wr_checkpt_sum (dev); + +if (!yaffs_checkpt_close (dev)) + ok =0 ; + +if (ok) + dev->is_checkpointed =1 ; +else + dev->is_checkpointed =0 ;
dev->is_checkpointed = ok;
Quoted 44 lines
fs/yaffs2/yaffs_yaffs2.c new file +44
-0+ +return dev->is_checkpointed; +} + +static int yaffs2_rd_checkpt_data (struct yaffs_dev *dev) +{ +int ok =1 ; + +if (!dev->param.is_yaffs2) + ok =0 ; + +if (ok && dev->param.skip_checkpt_rd) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"skipping checkpoint read" ); + ok =0 ; + } + +if (ok) + ok =yaffs2_checkpt_open (dev,0 );/* open for read */ + +if (ok) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"read checkpoint validity" ); + ok =yaffs2_rd_checkpt_validity_marker (dev,1 ); + } +if (ok) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"read checkpoint device" ); + ok =yaffs2_rd_checkpt_dev (dev); + } +if (ok) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"read checkpoint objects" ); + ok =yaffs2_rd_checkpt_objs (dev); + } +if (ok) { +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"read checkpoint validity" ); + ok =yaffs2_rd_checkpt_validity_marker (dev,0 ); + } + +if (ok) { + ok =yaffs2_rd_checkpt_sum (dev); + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
fs/yaffs2/yaffs_yaffs2.c line 773
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+ "read checkpoint checksum %d", ok); + } + +if (!yaffs_checkpt_close (dev)) + ok =0 ; + +if (ok) + dev->is_checkpointed =1 ; +else + dev->is_checkpointed =0 ;
dev->is_checkpointed = ok;
Quoted 91 lines
fs/yaffs2/yaffs_yaffs2.c new file +91
-0+ +return ok ?1 :0 ; +} + +void yaffs2_checkpt_invalidate (struct yaffs_dev *dev) +{ +if (dev->is_checkpointed || dev->blocks_in_checkpt >0 ) { + dev->is_checkpointed =0 ; +yaffs2_checkpt_invalidate_stream (dev); + } +if (dev->param.sb_dirty_fn) + dev->param.sb_dirty_fn (dev); +} + +int yaffs_checkpoint_save (struct yaffs_dev *dev) +{ +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"save entry: is_checkpointed %d" , + dev->is_checkpointed); + +yaffs_verify_objects (dev); +yaffs_verify_blocks (dev); +yaffs_verify_free_chunks (dev); + +if (!dev->is_checkpointed) { +yaffs2_checkpt_invalidate (dev); +yaffs2_wr_checkpt_data (dev); + } + +yaffs_trace (YAFFS_TRACE_CHECKPOINT |YAFFS_TRACE_MOUNT , +"save exit: is_checkpointed %d" , + dev->is_checkpointed); + +return dev->is_checkpointed; +} + +int yaffs2_checkpt_restore (struct yaffs_dev *dev) +{ +int retval; + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"restore entry: is_checkpointed %d" , + dev->is_checkpointed); + + retval =yaffs2_rd_checkpt_data (dev); + +if (dev->is_checkpointed) { +yaffs_verify_objects (dev); +yaffs_verify_blocks (dev); +yaffs_verify_free_chunks (dev); + } + +yaffs_trace (YAFFS_TRACE_CHECKPOINT , +"restore exit: is_checkpointed %d" , + dev->is_checkpointed); + +return retval; +} + +int yaffs2_handle_hole (struct yaffs_obj *obj,loff_t new_size) +{ +/* if new_size > old_file_size. +* We're going to be writing a hole. +* If the hole is small then write zeros otherwise write a start +* of hole marker. +*/ +loff_t old_file_size; +int increase; +int small_hole; +int result =YAFFS_OK ; +struct yaffs_dev *dev =NULL ; +u8 *local_buffer =NULL ; +int small_increase_ok =0 ; + +if (!obj) +return YAFFS_FAIL ; + +if (obj->variant_type !=YAFFS_OBJECT_TYPE_FILE ) +return YAFFS_FAIL ; + + dev = obj->my_dev; + +/* Bail out if not yaffs2 mode */ +if (!dev->param.is_yaffs2) +return YAFFS_OK ; + + old_file_size = obj->variant.file_variant.file_size; + +if (new_size <= old_file_size) +return YAFFS_OK ; +
fs/yaffs2/yaffs_yaffs2.c line 874
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+ increase = new_size - old_file_size; + +if (increase <YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk && +yaffs_check_alloc_available (dev,YAFFS_SMALL_HOLE_THRESHOLD +1 )) + small_hole =1 ; +else + small_hole =0 ; + +if (small_hole) + local_buffer =yaffs_get_temp_buffer (dev, __LINE__);
small_hole only gets used for this test? Remove the small_hole variable and make the if happen directly.
Quoted 157 lines
fs/yaffs2/yaffs_yaffs2.c new file +157
-0+ +if (local_buffer) { +/* fill hole with zero bytes */ +int pos = old_file_size; +int this_write; +int written; +memset (local_buffer,0 , dev->data_bytes_per_chunk); + small_increase_ok =1 ; + +while (increase >0 && small_increase_ok) { + this_write = increase; +if (this_write > dev->data_bytes_per_chunk) + this_write = dev->data_bytes_per_chunk; + written = +yaffs_do_file_wr (obj, local_buffer, pos, this_write, +0 ); +if (written == this_write) { + pos += this_write; + increase -= this_write; + }else { + small_increase_ok =0 ; + } + } + +yaffs_release_temp_buffer (dev, local_buffer, __LINE__); + +/* If out of space then reverse any chunks we've added */ +if (!small_increase_ok) +yaffs_resize_file_down (obj, old_file_size); + } + +if (!small_increase_ok && + obj->parent && + obj->parent->obj_id !=YAFFS_OBJECTID_UNLINKED && + obj->parent->obj_id !=YAFFS_OBJECTID_DELETED ) { +/* Write a hole start header with the old file size */ +yaffs_update_oh (obj,NULL ,0 ,1 ,0 ,NULL ); + } + +return result; +} + +struct yaffs_block_index { +int seq; +int block; +}; + +static int yaffs2_ybicmp (const void *a,const void *b) +{ +int aseq = ((struct yaffs_block_index *)a)->seq; +int bseq = ((struct yaffs_block_index *)b)->seq; +int ablock = ((struct yaffs_block_index *)a)->block; +int bblock = ((struct yaffs_block_index *)b)->block; + +if (aseq == bseq) +return ablock - bblock; +else +return aseq - bseq; +} + +static inline int yaffs2_scan_chunk (struct yaffs_dev *dev, +struct yaffs_block_info *bi, +int blk,int chunk_in_block, +int *found_chunks, +u8 *chunk_data, +struct yaffs_obj **hard_list) +{ +struct yaffs_obj_hdr *oh; +struct yaffs_obj *in; +struct yaffs_obj *parent; +int equiv_id; +int file_size; +int is_shrink; +int is_unlinked; +struct yaffs_ext_tags tags; +int result; +int alloc_failed =0 ; +int chunk = blk * dev->param.chunks_per_block + chunk_in_block; +struct yaffs_file_var *file_var; +struct yaffs_hardlink_var *hl_var; +struct yaffs_symlink_var *sl_var; + + result =yaffs_rd_chunk_tags_nand (dev, chunk,NULL , &tags); + +/* Let's have a good look at this chunk... */ + +if (!tags.chunk_used) { +/* An unassigned chunk in the block. +* If there are used chunks after this one, then +* it is a chunk that was skipped due to failing +* the erased check. Just skip it so that it can +* be deleted. +* But, more typically, We get here when this is +* an unallocated chunk and his means that +* either the block is empty or this is the one +* being allocated from +*/ + +if (*found_chunks) { +/* This is a chunk that was skipped due +* to failing the erased check */ + }else if (chunk_in_block ==0 ) { +/* We're looking at the first chunk in +* the block so the block is unused */ + bi->block_state =YAFFS_BLOCK_STATE_EMPTY ; + dev->n_erased_blocks++; + }else { +if (bi->block_state ==YAFFS_BLOCK_STATE_NEEDS_SCANNING + || bi->block_state ==YAFFS_BLOCK_STATE_ALLOCATING ) { +if (dev->seq_number == bi->seq_number) { +/* Allocating from this block*/ +yaffs_trace (YAFFS_TRACE_SCAN , +" Allocating from %d %d" , + blk, chunk_in_block); + + bi->block_state = +YAFFS_BLOCK_STATE_ALLOCATING ; + dev->alloc_block = blk; + dev->alloc_page = chunk_in_block; + dev->alloc_block_finder = blk; + }else { +/* This is a partially written block +* that is not the current +* allocation block. +*/ +yaffs_trace (YAFFS_TRACE_SCAN , +"Partially written block %d detected. gc will fix this." , + blk); + } + } + } + + dev->n_free_chunks++; + + }else if (tags.ecc_result == +YAFFS_ECC_RESULT_UNFIXED ) { +yaffs_trace (YAFFS_TRACE_SCAN , +" Unfixed ECC in chunk(%d:%d), chunk ignored" , + blk, chunk_in_block); + dev->n_free_chunks++; + }else if (tags.obj_id >YAFFS_MAX_OBJECT_ID || + tags.chunk_id >YAFFS_MAX_CHUNK_ID || + (tags.chunk_id >0 && + tags.n_bytes > dev->data_bytes_per_chunk) || + tags.seq_number != bi->seq_number) { +yaffs_trace (YAFFS_TRACE_SCAN , +"Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored" , + blk, chunk_in_block, tags.obj_id, + tags.chunk_id, tags.n_bytes); + dev->n_free_chunks++; + }else if (tags.chunk_id >0 ) { +/* chunk_id > 0 so it is a data chunk... */ +unsigned int endpos; +u32 chunk_base = (tags.chunk_id -1 ) * + dev->data_bytes_per_chunk; + + *found_chunks =1 ;
fs/yaffs2/yaffs_yaffs2.c line 1041
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+ +yaffs_set_chunk_bit (dev, blk, chunk_in_block); + bi->pages_in_use++; + + in =yaffs_find_or_create_by_number (dev, + tags.obj_id, +YAFFS_OBJECT_TYPE_FILE ); +if (!in) +/* Out of memory */ + alloc_failed =1 ;
Bail: goto alloc_failed;
Quoted 49 lines
fs/yaffs2/yaffs_yaffs2.c new file +49
-0+ +if (in && + in->variant_type ==YAFFS_OBJECT_TYPE_FILE && + chunk_base < in->variant.file_variant.shrink_size) { +/* This has not been invalidated by +* a resize */ +if (!yaffs_put_chunk_in_file (in, tags.chunk_id, + chunk,-1 )) + alloc_failed =1 ; + +/* File size is calculated by looking at +* the data chunks if we have not +* seen an object header yet. +* Stop this practice once we find an +* object header. +*/ + endpos = chunk_base + tags.n_bytes; + +if (!in->valid && + in->variant.file_variant.scanned_size < endpos) { + in->variant.file_variant. + scanned_size = endpos; + in->variant.file_variant. + file_size = endpos; + } + }else if (in) { +/* This chunk has been invalidated by a +* resize, or a past file deletion +* so delete the chunk*/ +yaffs_chunk_del (dev, chunk,1 , __LINE__); + } + }else { +/* chunk_id == 0, so it is an ObjectHeader. +* Thus, we read in the object header and make +* the object +*/ + *found_chunks =1 ; + +yaffs_set_chunk_bit (dev, blk, chunk_in_block); + bi->pages_in_use++; + + oh =NULL ; + in =NULL ; + +if (tags.extra_available) { + in =yaffs_find_or_create_by_number (dev, + tags.obj_id, + tags.extra_obj_type); +if (!in)
fs/yaffs2/yaffs_yaffs2.c line 1100
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+ alloc_failed =1 ; + } + +if (!in || + (!in->valid && dev->param.disable_lazy_load) + || tags.extra_shadows || + (!in->valid && (tags.obj_id == +YAFFS_OBJECTID_ROOT + || tags.obj_id == +YAFFS_OBJECTID_LOSTNFOUND ))) {
My brain hurts :-).
Quoted 202 lines
fs/yaffs2/yaffs_yaffs2.c new file +202
-0+ +/* If we don't have valid info then we +* need to read the chunk +* TODO In future we can probably defer +* reading the chunk and living with +* invalid data until needed. +*/ + + result =yaffs_rd_chunk_tags_nand (dev, + chunk, + chunk_data, +NULL ); + + oh = (struct yaffs_obj_hdr *)chunk_data; + +if (dev->param.inband_tags) { +/* Fix up the header if they got +* corrupted by inband tags */ + oh->shadows_obj = + oh->inband_shadowed_obj_id; + oh->is_shrink = + oh->inband_is_shrink; + } + +if (!in) { + in =yaffs_find_or_create_by_number (dev, + tags.obj_id, oh->type); +if (!in) + alloc_failed =1 ; + } + } + +if (!in) { +/* TODO Hoosterman we have a problem! */ +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs tragedy: Could not make object for object %d at chunk %d during scan" , + tags.obj_id, chunk); +return YAFFS_FAIL ; + } + +if (in->valid) { +/* We have already filled this one. +* We have a duplicate that will be +* discarded, but we first have to suck +* out resize info if it is a file. +*/ +if ((in->variant_type ==YAFFS_OBJECT_TYPE_FILE ) && + ((oh && oh->type ==YAFFS_OBJECT_TYPE_FILE ) || + (tags.extra_available && + tags.extra_obj_type ==YAFFS_OBJECT_TYPE_FILE ) + )) { +u32 this_size = (oh) ? + oh->file_size : + tags.extra_length; +u32 parent_obj_id = (oh) ? + oh->parent_obj_id : + tags.extra_parent_id; + + is_shrink = (oh) ? + oh->is_shrink : + tags.extra_is_shrink; + +/* If it is deleted (unlinked +* at start also means deleted) +* we treat the file size as +* being zeroed at this point. +*/ +if (parent_obj_id ==YAFFS_OBJECTID_DELETED || + parent_obj_id ==YAFFS_OBJECTID_UNLINKED ) { + this_size =0 ; + is_shrink =1 ; + } + +if (is_shrink && + in->variant.file_variant.shrink_size > + this_size) + in->variant.file_variant.shrink_size = + this_size; + +if (is_shrink) + bi->has_shrink_hdr =1 ; + } +/* Use existing - destroy this one. */ +yaffs_chunk_del (dev, chunk,1 , __LINE__); + } + +if (!in->valid && in->variant_type != + (oh ? oh->type : tags.extra_obj_type)) +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs tragedy: Bad object type, %d != %d, for object %d at chunk %d during scan" , + oh ? oh->type : tags.extra_obj_type, + in->variant_type, tags.obj_id, + chunk); + +if (!in->valid && + (tags.obj_id ==YAFFS_OBJECTID_ROOT || + tags.obj_id ==YAFFS_OBJECTID_LOSTNFOUND )) { +/* We only load some info, don't fiddle +* with directory structure */ + in->valid =1 ; + +if (oh) { + in->yst_mode = oh->yst_mode; +yaffs_load_attribs (in, oh); + in->lazy_loaded =0 ; + }else { + in->lazy_loaded =1 ; + } + in->hdr_chunk = chunk; + + }else if (!in->valid) { +/* we need to load this info */ + in->valid =1 ; + in->hdr_chunk = chunk; +if (oh) { + in->variant_type = oh->type; + in->yst_mode = oh->yst_mode; +yaffs_load_attribs (in, oh); + +if (oh->shadows_obj >0 ) +yaffs_handle_shadowed_obj (dev, + oh->shadows_obj,1 ); + +yaffs_set_obj_name_from_oh (in, oh); + parent =yaffs_find_or_create_by_number (dev, + oh->parent_obj_id, +YAFFS_OBJECT_TYPE_DIRECTORY ); + file_size = oh->file_size; + is_shrink = oh->is_shrink; + equiv_id = oh->equiv_id; + }else { + in->variant_type = tags.extra_obj_type; + parent =yaffs_find_or_create_by_number (dev, + tags.extra_parent_id, +YAFFS_OBJECT_TYPE_DIRECTORY ); + file_size = tags.extra_length; + is_shrink = tags.extra_is_shrink; + equiv_id = tags.extra_equiv_id; + in->lazy_loaded =1 ; + } + in->dirty =0 ; + +if (!parent) + alloc_failed =1 ; + +/* directory stuff... +* hook up to parent +*/ + +if (parent && + parent->variant_type ==YAFFS_OBJECT_TYPE_UNKNOWN ) { +/* Set up as a directory */ + parent->variant_type = +YAFFS_OBJECT_TYPE_DIRECTORY ; +INIT_LIST_HEAD (&parent-> + variant.dir_variant.children); + }else if (!parent || + parent->variant_type != +YAFFS_OBJECT_TYPE_DIRECTORY ) { +/* Hoosterman, another problem.... +* Trying to use a non-directory as a directory +*/ + +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." + ); + parent = dev->lost_n_found; + } +yaffs_add_obj_to_dir (parent, in); + + is_unlinked = (parent == dev->del_dir) || + (parent == dev->unlinked_dir); + +if (is_shrink) +/* Mark the block */ + bi->has_shrink_hdr =1 ; + +/* Note re hardlinks. +* Since we might scan a hardlink before its equivalent +* object is scanned we put them all in a list. +* After scanning is complete, we should have all the +* objects, so we run through this list and fix up all +* the chains. +*/ + +switch (in->variant_type) { +case YAFFS_OBJECT_TYPE_UNKNOWN : +/* Todo got a problem */ +break ; +case YAFFS_OBJECT_TYPE_FILE : + file_var = &in->variant.file_variant; +if (file_var->scanned_size < file_size) { +/* This covers the case where the file +* size is greater than the data held. +* This will happen if the file is +* resized to be larger than its +* current data extents. +*/ + file_var->file_size = file_size; + file_var->scanned_size = file_size; + } +
fs/yaffs2/yaffs_yaffs2.c line 1312
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+if (file_var->shrink_size > file_size) + file_var->shrink_size = file_size; + +break ; +case YAFFS_OBJECT_TYPE_HARDLINK : + hl_var = &in->variant.hardlink_variant; +if (!is_unlinked) { + hl_var->equiv_id = equiv_id; + in->hard_links.next = + (struct list_head *) *hard_list;
List trickery?
Quoted 47 lines
fs/yaffs2/yaffs_yaffs2.c new file +47
-0+ *hard_list = in; + } +break ; +case YAFFS_OBJECT_TYPE_DIRECTORY : +/* Do nothing */ +break ; +case YAFFS_OBJECT_TYPE_SPECIAL : +/* Do nothing */ +break ; +case YAFFS_OBJECT_TYPE_SYMLINK : + sl_var = &in->variant.symlink_variant; +if (oh) { + sl_var->alias = +yaffs_clone_str (oh->alias); +if (!sl_var->alias) + alloc_failed =1 ; + } +break ; + } + } + } +return alloc_failed ?YAFFS_FAIL :YAFFS_OK ; +} + +int yaffs2_scan_backwards (struct yaffs_dev *dev) +{ +int blk; +int block_iter; +int start_iter; +int end_iter; +int n_to_scan =0 ; +enum yaffs_block_state state; +int c; +int deleted; +struct yaffs_obj *hard_list =NULL ; +struct yaffs_block_info *bi; +u32 seq_number; +int n_blocks = dev->internal_end_block - dev->internal_start_block +1 ; +u8 *chunk_data; +int found_chunks; +int alloc_failed =0 ; +struct yaffs_block_index *block_index =NULL ; +int alt_block_index =0 ; + +yaffs_trace (YAFFS_TRACE_SCAN , +"yaffs2_scan_backwards starts intstartblk %d intendblk %d..." , + dev->internal_start_block, dev->internal_end_block);
fs/yaffs2/yaffs_yaffs2.c line 1369
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+ + dev->seq_number =YAFFS_LOWEST_SEQUENCE_NUMBER ; + + block_index =kmalloc (n_blocks *sizeof (struct yaffs_block_index ), +GFP_NOFS ); + +if (!block_index) { + block_index = +vmalloc (n_blocks *sizeof (struct yaffs_block_index )); + alt_block_index =1 ;
How big is this alloc? Does it make more sense to just always use vmalloc and simplify the code?
Quoted 78 lines
fs/yaffs2/yaffs_yaffs2.c new file +78
-0+ } + +if (!block_index) { +yaffs_trace (YAFFS_TRACE_SCAN , +"yaffs2_scan_backwards() could not allocate block index!" + ); +return YAFFS_FAIL ; + } + + dev->blocks_in_checkpt =0 ; + + chunk_data =yaffs_get_temp_buffer (dev, __LINE__); + +/* Scan all the blocks to determine their state */ + bi = dev->block_info; +for (blk = dev->internal_start_block; blk <= dev->internal_end_block; + blk++) { +yaffs_clear_chunk_bits (dev, blk); + bi->pages_in_use =0 ; + bi->soft_del_pages =0 ; + +yaffs_query_init_block_state (dev, blk, &state, &seq_number); + + bi->block_state = state; + bi->seq_number = seq_number; + +if (bi->seq_number ==YAFFS_SEQUENCE_CHECKPOINT_DATA ) + bi->block_state =YAFFS_BLOCK_STATE_CHECKPOINT ; +if (bi->seq_number ==YAFFS_SEQUENCE_BAD_BLOCK ) + bi->block_state =YAFFS_BLOCK_STATE_DEAD ; + +yaffs_trace (YAFFS_TRACE_SCAN_DEBUG , +"Block scanning block %d state %d seq %d" , + blk, bi->block_state, seq_number); + +if (bi->block_state ==YAFFS_BLOCK_STATE_CHECKPOINT ) { + dev->blocks_in_checkpt++; + + }else if (bi->block_state ==YAFFS_BLOCK_STATE_DEAD ) { +yaffs_trace (YAFFS_TRACE_BAD_BLOCKS , +"block %d is bad" , blk); + }else if (bi->block_state ==YAFFS_BLOCK_STATE_EMPTY ) { +yaffs_trace (YAFFS_TRACE_SCAN_DEBUG ,"Block empty " ); + dev->n_erased_blocks++; + dev->n_free_chunks += dev->param.chunks_per_block; + }else if (bi->block_state == +YAFFS_BLOCK_STATE_NEEDS_SCANNING ) { +/* Determine the highest sequence number */ +if (seq_number >=YAFFS_LOWEST_SEQUENCE_NUMBER && + seq_number <YAFFS_HIGHEST_SEQUENCE_NUMBER ) { + block_index[n_to_scan].seq = seq_number; + block_index[n_to_scan].block = blk; + n_to_scan++; +if (seq_number >= dev->seq_number) + dev->seq_number = seq_number; + }else { +/* TODO: Nasty sequence number! */ +yaffs_trace (YAFFS_TRACE_SCAN , +"Block scanning block %d has bad sequence number %d" , + blk, seq_number); + } + } + bi++; + } + +yaffs_trace (YAFFS_TRACE_SCAN ,"%d blocks to be sorted..." , n_to_scan); + +cond_resched (); + +/* Sort the blocks by sequence number */ +sort (block_index, n_to_scan,sizeof (struct yaffs_block_index ), + yaffs2_ybicmp,NULL ); + +cond_resched (); + +yaffs_trace (YAFFS_TRACE_SCAN ,"...done" ); + +/* Now scan the blocks looking at the data. */
fs/yaffs2/yaffs_yaffs2.c line 1457
Quoted 10 lines
fs/yaffs2/yaffs_yaffs2.c new file +10
-0+ start_iter =0 ; + end_iter = n_to_scan -1 ; +yaffs_trace (YAFFS_TRACE_SCAN_DEBUG ,"%d blocks to scan" , n_to_scan); + +/* For each block.... backwards */ +for (block_iter = end_iter; !alloc_failed && block_iter >= start_iter; + block_iter--) { +/* Cooperative multitasking! This loop can run for so +long that watchdog timers expire. */ +cond_resched ();
Can parts of it be moved to a tasklet, kernel thread, etc?
Quoted 104 lines
fs/yaffs2/yaffs_yaffs2.c new file +59
-0+ +/* get the block to scan in the correct order */ + blk = block_index[block_iter].block; + bi =yaffs_get_block_info (dev, blk); + deleted =0 ; + +/* For each chunk in each block that needs scanning.... */ + found_chunks =0 ; +for (c = dev->param.chunks_per_block -1 ; + !alloc_failed && c >=0 && + (bi->block_state ==YAFFS_BLOCK_STATE_NEEDS_SCANNING || + bi->block_state ==YAFFS_BLOCK_STATE_ALLOCATING ); c--) { +/* Scan backwards... +* Read the tags and decide what to do +*/ +if (yaffs2_scan_chunk (dev, bi, blk, c, + &found_chunks, chunk_data, + &hard_list) == +YAFFS_FAIL ) + alloc_failed =1 ; + } + +if (bi->block_state ==YAFFS_BLOCK_STATE_NEEDS_SCANNING ) { +/* If we got this far while scanning, then the block +* is fully allocated. */ + bi->block_state =YAFFS_BLOCK_STATE_FULL ; + } + +/* Now let's see if it was dirty */ +if (bi->pages_in_use ==0 && + !bi->has_shrink_hdr && + bi->block_state ==YAFFS_BLOCK_STATE_FULL ) { +yaffs_block_became_dirty (dev, blk); + } + } + +yaffs_skip_rest_of_block (dev); + +if (alt_block_index) +vfree (block_index); +else +kfree (block_index); + +/* Ok, we've done all the scanning. +* Fix up the hard link chains. +* We have scanned all the objects, now it's time to add these +* hardlinks. +*/ +yaffs_link_fixup (dev, hard_list); + +yaffs_release_temp_buffer (dev, chunk_data, __LINE__); + +if (alloc_failed) +return YAFFS_FAIL ; + +yaffs_trace (YAFFS_TRACE_SCAN ,"yaffs2_scan_backwards ends" ); + +return YAFFS_OK ; +}fs/yaffs2/yaffs_yaffs2.h new file +39
-0@@ -0,0 +1,39 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_YAFFS2_H__ +#define __YAFFS_YAFFS2_H__ + +#include "yaffs_guts.h" + +void yaffs_calc_oldest_dirty_seq (struct yaffs_dev *dev); +void yaffs2_find_oldest_dirty_seq (struct yaffs_dev *dev); +void yaffs2_clear_oldest_dirty_seq (struct yaffs_dev *dev, +struct yaffs_block_info *bi); +void yaffs2_update_oldest_dirty_seq (struct yaffs_dev *dev,unsigned block_no, +struct yaffs_block_info *bi); +int yaffs_block_ok_for_gc (struct yaffs_dev *dev,struct yaffs_block_info *bi); +u32 yaffs2_find_refresh_block (struct yaffs_dev *dev); +int yaffs2_checkpt_required (struct yaffs_dev *dev); +int yaffs_calc_checkpt_blocks_required (struct yaffs_dev *dev); + +void yaffs2_checkpt_invalidate (struct yaffs_dev *dev); +int yaffs2_checkpt_save (struct yaffs_dev *dev); +int yaffs2_checkpt_restore (struct yaffs_dev *dev); + +int yaffs2_handle_hole (struct yaffs_obj *obj,loff_t new_size); +int yaffs2_scan_backwards (struct yaffs_dev *dev); + +#endif
Signature · 7 lines
Bluewater Systems Ltd - ARM Technology Solution Centre Ryan Mallon 5 Amuri Park, 404 Barbadoes St [email protected] PO Box 13 889, Christchurch 8013 http://www.bluewatersys.com New Zealand Phone: +64 3 3779127 Freecall: Australia 1800 148 751 Fax: +64 3 3779135 USA 1800 261 2934
PATCH 8/10 Add yaffs2 file system: Core guts code
In reply to Charles Manning--- fs/yaffs2/yaffs_guts.c | 5028 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yaffs_guts.h | 938 +++++++++ 2 files changed, 5966 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_guts.c create mode 100644 fs/yaffs2/yaffs_guts.h
fs/yaffs2/yaffs_guts.c new file +5028 -0
@@ -0,0 +1,5028 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +#include "yportenv.h" +#include "yaffs_trace.h" + +#include "yaffs_guts.h" +#include "yaffs_tagsvalidity.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_tagscompat.h" +#include "yaffs_nand.h" +#include "yaffs_yaffs1.h" +#include "yaffs_yaffs2.h" +#include "yaffs_bitmap.h" +#include "yaffs_verify.h" +#include "yaffs_nand.h" +#include "yaffs_packedtags2.h" +#include "yaffs_nameval.h" +#include "yaffs_allocator.h" +#include "yaffs_attribs.h" + +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ +#define YAFFS_GC_GOOD_ENOUGH 2 +#define YAFFS_GC_PASSIVE_THRESHOLD 4 + +#include "yaffs_ecc.h" + +/* Forward declarations */ + +static int yaffs_wr_data_obj (struct yaffs_obj *in,int inode_chunk, +const u8 *buffer,int n_bytes,int use_reserve); + + + +/* Function to calculate chunk and offset */ + +static void yaffs_addr_to_chunk (struct yaffs_dev *dev,loff_t addr, +int *chunk_out,u32 *offset_out) +{ +int chunk; +u32 offset; + + chunk = (u32) (addr >> dev->chunk_shift); + +if (dev->chunk_div ==1 ) { +/* easy power of 2 case */ + offset = (u32) (addr & dev->chunk_mask); + }else { +/* Non power-of-2 case */ + +loff_t chunk_base; + + chunk /= dev->chunk_div; + + chunk_base = ((loff_t ) chunk) * dev->data_bytes_per_chunk; + offset = (u32) (addr - chunk_base); + } + + *chunk_out = chunk; + *offset_out = offset; +} + +/* Function to return the number of shifts for a power of 2 greater than or +* equal to the given number +* Note we don't try to cater for all possible numbers and this does not have to +* be hellishly efficient. +*/ + +static u32 calc_shifts_ceiling (u32 x) +{ +int extra_bits; +int shifts; + + shifts = extra_bits =0 ; + +while (x >1 ) { +if (x &1 ) + extra_bits++; + x >>=1 ; + shifts++; + } + +if (extra_bits) + shifts++; + +return shifts; +} + +/* Function to return the number of shifts to get a 1 in bit 0 +*/ + +static u32 calc_shifts (u32 x) +{ +u32 shifts; + + shifts =0 ; + +if (!x) +return 0 ; + +while (!(x &1 )) { + x >>=1 ; + shifts++; + } + +return shifts; +} + +/* +* Temporary buffer manipulations. +*/ + +static int yaffs_init_tmp_buffers (struct yaffs_dev *dev) +{ +int i; +u8 *buf = (u8 *)1 ; + +memset (dev->temp_buffer,0 ,sizeof (dev->temp_buffer)); + +for (i =0 ; buf && i <YAFFS_N_TEMP_BUFFERS ; i++) { + dev->temp_buffer[i].line =0 ;/* not in use */ + dev->temp_buffer[i].buffer = buf = +kmalloc (dev->param.total_bytes_per_chunk,GFP_NOFS ); + } + +return buf ?YAFFS_OK :YAFFS_FAIL ; +} + +u8 *yaffs_get_temp_buffer (struct yaffs_dev * dev,int line_no) +{ +int i; +int j; + + dev->temp_in_use++; +if (dev->temp_in_use > dev->max_temp) + dev->max_temp = dev->temp_in_use; + +for (i =0 ; i <YAFFS_N_TEMP_BUFFERS ; i++) { +if (dev->temp_buffer[i].line ==0 ) { + dev->temp_buffer[i].line = line_no; +if ((i +1 ) > dev->max_temp) { + dev->max_temp = i +1 ; +for (j =0 ; j <= i; j++) + dev->temp_buffer[j].max_line = + dev->temp_buffer[j].line; + } + +return dev->temp_buffer[i].buffer; + } + } + +yaffs_trace (YAFFS_TRACE_BUFFERS , +"Out of temp buffers at line %d, other held by lines:" , + line_no); +for (i =0 ; i <YAFFS_N_TEMP_BUFFERS ; i++) +yaffs_trace (YAFFS_TRACE_BUFFERS , +" %d" , dev->temp_buffer[i].line); + +/* +* If we got here then we have to allocate an unmanaged one +* This is not good. +*/ + + dev->unmanaged_buffer_allocs++; +return kmalloc (dev->data_bytes_per_chunk,GFP_NOFS ); + +} + +void yaffs_release_temp_buffer (struct yaffs_dev *dev,u8 *buffer,int line_no) +{ +int i; + + dev->temp_in_use--; + +for (i =0 ; i <YAFFS_N_TEMP_BUFFERS ; i++) { +if (dev->temp_buffer[i].buffer == buffer) { + dev->temp_buffer[i].line =0 ; +return ; + } + } + +if (buffer) { +/* assume it is an unmanaged one. */ +yaffs_trace (YAFFS_TRACE_BUFFERS , +"Releasing unmanaged temp buffer in line %d" , + line_no); +kfree (buffer); + dev->unmanaged_buffer_deallocs++; + } + +} + +/* +* Determine if we have a managed buffer. +*/ +int yaffs_is_managed_tmp_buffer (struct yaffs_dev *dev,const u8 *buffer) +{ +int i; + +for (i =0 ; i <YAFFS_N_TEMP_BUFFERS ; i++) { +if (dev->temp_buffer[i].buffer == buffer) +return 1 ; + } + +for (i =0 ; i < dev->param.n_caches; i++) { +if (dev->cache[i].data == buffer) +return 1 ; + } + +if (buffer == dev->checkpt_buffer) +return 1 ; + +yaffs_trace (YAFFS_TRACE_ALWAYS , +"yaffs: unmaged buffer detected." ); +return 0 ; +} + +/* +* Functions for robustisizing TODO +* +*/ + +static void yaffs_handle_chunk_wr_ok (struct yaffs_dev *dev,int nand_chunk, +const u8 *data, +const struct yaffs_ext_tags *tags) +{ + dev = dev; + nand_chunk = nand_chunk; + data = data; + tags = tags; +} + +static void yaffs_handle_chunk_update (struct yaffs_dev *dev,int nand_chunk, +const struct yaffs_ext_tags *tags) +{ + dev = dev; + nand_chunk = nand_chunk; + tags = tags; +} + +void yaffs_handle_chunk_error (struct yaffs_dev *dev, +struct yaffs_block_info *bi) +{ +if (!bi->gc_prioritise) { + bi->gc_prioritise =1 ; + dev->has_pending_prioritised_gc =1 ; + bi->chunk_error_strikes++; + +if (bi->chunk_error_strikes >3 ) { + bi->needs_retiring =1 ;/* Too many stikes, so retire */ +yaffs_trace (YAFFS_TRACE_ALWAYS , +"yaffs: Block struck out" ); + + } + } +} + +static void yaffs_handle_chunk_wr_error (struct yaffs_dev *dev,int nand_chunk, +int erased_ok) +{ +int flash_block = nand_chunk / dev->param.chunks_per_block; +struct yaffs_block_info *bi =yaffs_get_block_info (dev, flash_block); + +yaffs_handle_chunk_error (dev, bi); + +if (erased_ok) { +/* Was an actual write failure, +* so mark the block for retirement.*/ + bi->needs_retiring =1 ; +yaffs_trace (YAFFS_TRACE_ERROR |YAFFS_TRACE_BAD_BLOCKS , +"**>> Block %d needs retiring" , flash_block); + } + +/* Delete the chunk */ +yaffs_chunk_del (dev, nand_chunk,1 , __LINE__); +yaffs_skip_rest_of_block (dev); +} + +/* +* Verification code +*/ + +/* +* Simple hash function. Needs to have a reasonable spread +*/ + +static inline int yaffs_hash_fn (int n) +{ + n =abs (n); +return n %YAFFS_NOBJECT_BUCKETS ; +} + +/* +* Access functions to useful fake objects. +* Note that root might have a presence in NAND if permissions are set. +*/ + +struct yaffs_obj *yaffs_root (struct yaffs_dev *dev) +{ +return dev->root_dir; +} + +struct yaffs_obj *yaffs_lost_n_found (struct yaffs_dev *dev) +{ +return dev->lost_n_found; +} + +/* +* Erased NAND checking functions +*/ + +int yaffs_check_ff (u8 *buffer,int n_bytes) +{ +/* Horrible, slow implementation */ +while (n_bytes--) { +if (*buffer !=0xFF ) +return 0 ; + buffer++; + } +return 1 ; +} + +static int yaffs_check_chunk_erased (struct yaffs_dev *dev,int nand_chunk) +{ +int retval =YAFFS_OK ; +u8 *data =yaffs_get_temp_buffer (dev, __LINE__); +struct yaffs_ext_tags tags; +int result; + + result =yaffs_rd_chunk_tags_nand (dev, nand_chunk, data, &tags); + +if (tags.ecc_result >YAFFS_ECC_RESULT_NO_ERROR ) + retval =YAFFS_FAIL ; + +if (!yaffs_check_ff (data, dev->data_bytes_per_chunk) || + tags.chunk_used) { +yaffs_trace (YAFFS_TRACE_NANDACCESS , +"Chunk %d not erased" , nand_chunk); + retval =YAFFS_FAIL ; + } + +yaffs_release_temp_buffer (dev, data, __LINE__); + +return retval; + +} + +static int yaffs_verify_chunk_written (struct yaffs_dev *dev, +int nand_chunk, +const u8 *data, +struct yaffs_ext_tags *tags) +{ +int retval =YAFFS_OK ; +struct yaffs_ext_tags temp_tags; +u8 *buffer =yaffs_get_temp_buffer (dev, __LINE__); +int result; + + result =yaffs_rd_chunk_tags_nand (dev, nand_chunk, buffer, &temp_tags); +if (memcmp (buffer, data, dev->data_bytes_per_chunk) || + temp_tags.obj_id != tags->obj_id || + temp_tags.chunk_id != tags->chunk_id || + temp_tags.n_bytes != tags->n_bytes) + retval =YAFFS_FAIL ; + +yaffs_release_temp_buffer (dev, buffer, __LINE__); + +return retval; +} + + +int yaffs_check_alloc_available (struct yaffs_dev *dev,int n_chunks) +{ +int reserved_chunks; +int reserved_blocks = dev->param.n_reserved_blocks; +int checkpt_blocks; + + checkpt_blocks =yaffs_calc_checkpt_blocks_required (dev); + + reserved_chunks = + ((reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block); + +return (dev->n_free_chunks > (reserved_chunks + n_chunks)); +} + +static int yaffs_find_alloc_block (struct yaffs_dev *dev) +{ +int i; +struct yaffs_block_info *bi; + +if (dev->n_erased_blocks <1 ) { +/* Hoosterman we've got a problem. +* Can't get space to gc +*/ +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs tragedy: no more erased blocks" ); + +return -1 ; + } + +/* Find an empty block. */ + +for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + dev->alloc_block_finder++; +if (dev->alloc_block_finder < dev->internal_start_block + || dev->alloc_block_finder > dev->internal_end_block) { + dev->alloc_block_finder = dev->internal_start_block; + } + + bi =yaffs_get_block_info (dev, dev->alloc_block_finder); + +if (bi->block_state ==YAFFS_BLOCK_STATE_EMPTY ) { + bi->block_state =YAFFS_BLOCK_STATE_ALLOCATING ; + dev->seq_number++; + bi->seq_number = dev->seq_number; + dev->n_erased_blocks--; +yaffs_trace (YAFFS_TRACE_ALLOCATE , +"Allocated block %d, seq %d, %d left" , + dev->alloc_block_finder, dev->seq_number, + dev->n_erased_blocks); +return dev->alloc_block_finder; + } + } + +yaffs_trace (YAFFS_TRACE_ALWAYS , +"yaffs tragedy: no more erased blocks, but there should have been %d" , + dev->n_erased_blocks); + +return -1 ; +} + +static int yaffs_alloc_chunk (struct yaffs_dev *dev,int use_reserver, +struct yaffs_block_info **block_ptr) +{ +int ret_val; +struct yaffs_block_info *bi; + +if (dev->alloc_block <0 ) { +/* Get next block to allocate off */ + dev->alloc_block =yaffs_find_alloc_block (dev); + dev->alloc_page =0 ; + } + +if (!use_reserver && !yaffs_check_alloc_available (dev,1 )) { +/* No space unless we're allowed to use the reserve. */ +return -1 ; + } + +if (dev->n_erased_blocks < dev->param.n_reserved_blocks + && dev->alloc_page ==0 ) +yaffs_trace (YAFFS_TRACE_ALLOCATE ,"Allocating reserve" ); + +/* Next page please.... */ +if (dev->alloc_block >=0 ) { + bi =yaffs_get_block_info (dev, dev->alloc_block); + + ret_val = (dev->alloc_block * dev->param.chunks_per_block) + + dev->alloc_page; + bi->pages_in_use++; +yaffs_set_chunk_bit (dev, dev->alloc_block, dev->alloc_page); + + dev->alloc_page++; + + dev->n_free_chunks--; + +/* If the block is full set the state to full */ +if (dev->alloc_page >= dev->param.chunks_per_block) { + bi->block_state =YAFFS_BLOCK_STATE_FULL ; + dev->alloc_block =-1 ; + } + +if (block_ptr) + *block_ptr = bi; + +return ret_val; + } + +yaffs_trace (YAFFS_TRACE_ERROR , +"!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" ); + +return -1 ; +} + +static int yaffs_get_erased_chunks (struct yaffs_dev *dev) +{ +int n; + + n = dev->n_erased_blocks * dev->param.chunks_per_block; + +if (dev->alloc_block >0 ) + n += (dev->param.chunks_per_block - dev->alloc_page); + +return n; + +} + +/* +* yaffs_skip_rest_of_block() skips over the rest of the allocation block +* if we don't want to write to it. +*/ +void yaffs_skip_rest_of_block (struct yaffs_dev *dev) +{ +if (dev->alloc_block >0 ) { +struct yaffs_block_info *bi = +yaffs_get_block_info (dev, dev->alloc_block); +if (bi->block_state ==YAFFS_BLOCK_STATE_ALLOCATING ) { + bi->block_state =YAFFS_BLOCK_STATE_FULL ; + dev->alloc_block =-1 ; + } + } +} + +static int yaffs_write_new_chunk (struct yaffs_dev *dev, +const u8 *data, +struct yaffs_ext_tags *tags,int use_reserver) +{ +int attempts =0 ; +int write_ok =0 ; +int chunk; + +yaffs2_checkpt_invalidate (dev); + +do { +struct yaffs_block_info *bi =0 ; +int erased_ok =0 ; + + chunk =yaffs_alloc_chunk (dev, use_reserver, &bi); +if (chunk <0 ) { +/* no space */ +break ; + } + +/* First check this chunk is erased, if it needs +* checking. The checking policy (unless forced +* always on) is as follows: +* +* Check the first page we try to write in a block. +* If the check passes then we don't need to check any +* more. If the check fails, we check again... +* If the block has been erased, we don't need to check. +* +* However, if the block has been prioritised for gc, +* then we think there might be something odd about +* this block and stop using it. +* +* Rationale: We should only ever see chunks that have +* not been erased if there was a partially written +* chunk due to power loss. This checking policy should +* catch that case with very few checks and thus save a +* lot of checks that are most likely not needed. +* +* Mods to the above +* If an erase check fails or the write fails we skip the +* rest of the block. +*/ + +/* let's give it a try */ + attempts++; + +if (dev->param.always_check_erased) + bi->skip_erased_check =0 ; + +if (!bi->skip_erased_check) { + erased_ok =yaffs_check_chunk_erased (dev, chunk); +if (erased_ok !=YAFFS_OK ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>> yaffs chunk %d was not erased" , + chunk); + +/* If not erased, delete this one, +* skip rest of block and +* try another chunk */ +yaffs_chunk_del (dev, chunk,1 , __LINE__); +yaffs_skip_rest_of_block (dev); +continue ; + } + } + + write_ok =yaffs_wr_chunk_tags_nand (dev, chunk, data, tags); + +if (!bi->skip_erased_check) + write_ok = +yaffs_verify_chunk_written (dev, chunk, data, tags); + +if (write_ok !=YAFFS_OK ) { +/* Clean up aborted write, skip to next block and +* try another chunk */ +yaffs_handle_chunk_wr_error (dev, chunk, erased_ok); +continue ; + } + + bi->skip_erased_check =1 ; + +/* Copy the data into the robustification buffer */ +yaffs_handle_chunk_wr_ok (dev, chunk, data, tags); + + }while (write_ok !=YAFFS_OK && + (yaffs_wr_attempts <=0 || attempts <= yaffs_wr_attempts)); + +if (!write_ok) + chunk =-1 ; + +if (attempts >1 ) { +yaffs_trace (YAFFS_TRACE_ERROR , +"**>> yaffs write required %d attempts" , + attempts); + dev->n_retired_writes += (attempts -1 ); + } + +return chunk; +} + +/* +* Block retiring for handling a broken block. +*/ + +static void yaffs_retire_block (struct yaffs_dev *dev,int flash_block) +{ +struct yaffs_block_info *bi =yaffs_get_block_info (dev, flash_block); + +yaffs2_checkpt_invalidate (dev); + +yaffs2_clear_oldest_dirty_seq (dev, bi); + +if (yaffs_mark_bad (dev, flash_block) !=YAFFS_OK ) { +if (yaffs_erase_block (dev, flash_block) !=YAFFS_OK ) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"yaffs: Failed to mark bad and erase block %d" , + flash_block); + }else { +struct yaffs_ext_tags tags; +int chunk_id = + flash_block * dev->param.chunks_per_block; + +u8 *buffer =yaffs_get_temp_buffer (dev, __LINE__); + +memset (buffer,0xff , dev->data_bytes_per_chunk); +yaffs_init_tags (&tags); + tags.seq_number =YAFFS_SEQUENCE_BAD_BLOCK ; +if (dev->param.write_chunk_tags_fn (dev, chunk_id - + dev->chunk_offset, + buffer, + &tags) !=YAFFS_OK ) +yaffs_trace (YAFFS_TRACE_ALWAYS , +"yaffs: Failed to write bad block marker to block %d" , + flash_block); + +yaffs_release_temp_buffer (dev, buffer, __LINE__); + } + } + + bi->block_state =YAFFS_BLOCK_STATE_DEAD ; + bi->gc_prioritise =0 ; + bi->needs_retiring =0 ; + + dev->n_retired_blocks++; +} + +/*---------------- Name handling functions ------------*/ + +static u16 yaffs_calc_name_sum (const YCHAR *name) +{ +u16 sum =0 ; +u16 i =1 ; +const YUCHAR *bname = (const YUCHAR *)name; + +if (bname) { +while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH /2 ))) { + +/* 0x1f mask is case insensitive */ + sum += ((*bname) &0x1f ) * i; + i++; + bname++; + } + } +return sum; +} + +void yaffs_set_obj_name (struct yaffs_obj *obj,const YCHAR * name) +{ +#ifndef CONFIG_YAFFS_NO_SHORT_NAMES +memset (obj->short_name,0 ,sizeof (obj->short_name)); +if (name && +strnlen (name,YAFFS_SHORT_NAME_LENGTH +1 ) <= +YAFFS_SHORT_NAME_LENGTH ) +strcpy (obj->short_name, name); +else + obj->short_name[0 ] =_Y ('\0' ); +#endif + obj->sum =yaffs_calc_name_sum (name); +} + +void yaffs_set_obj_name_from_oh (struct yaffs_obj *obj, +const struct yaffs_obj_hdr *oh) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE +YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH +1 ]; +memset (tmp_name,0 ,sizeof (tmp_name)); +yaffs_load_name_from_oh (obj->my_dev, tmp_name, oh->name, +YAFFS_MAX_NAME_LENGTH +1 ); +yaffs_set_obj_name (obj, tmp_name); +#else +yaffs_set_obj_name (obj, oh->name); +#endif +} + +/*-------------------- TNODES ------------------- + +* List of spare tnodes +* The list is hooked together using the first pointer +* in the tnode. +*/ + +struct yaffs_tnode *yaffs_get_tnode (struct yaffs_dev *dev) +{ +struct yaffs_tnode *tn =yaffs_alloc_raw_tnode (dev); + +if (tn) { +memset (tn,0 , dev->tnode_size); + dev->n_tnodes++; + } + + dev->checkpoint_blocks_required =0 ;/* force recalculation */ + +return tn; +} + +/* FreeTnode frees up a tnode and puts it back on the free list */ +static void yaffs_free_tnode (struct yaffs_dev *dev,struct yaffs_tnode *tn) +{ +yaffs_free_raw_tnode (dev, tn); + dev->n_tnodes--; + dev->checkpoint_blocks_required =0 ;/* force recalculation */ +} + +static void yaffs_deinit_tnodes_and_objs (struct yaffs_dev *dev) +{ +yaffs_deinit_raw_tnodes_and_objs (dev); + dev->n_obj =0 ; + dev->n_tnodes =0 ; +} + +void yaffs_load_tnode_0 (struct yaffs_dev *dev,struct yaffs_tnode *tn, +unsigned pos,unsigned val) +{ +u32 *map = (u32 *) tn; +u32 bit_in_map; +u32 bit_in_word; +u32 word_in_map; +u32 mask; + + pos &=YAFFS_TNODES_LEVEL0_MASK ; + val >>= dev->chunk_grp_bits; + + bit_in_map = pos * dev->tnode_width; + word_in_map = bit_in_map /32 ; + bit_in_word = bit_in_map & (32 -1 ); + + mask = dev->tnode_mask << bit_in_word; + + map[word_in_map] &= ~mask; + map[word_in_map] |= (mask & (val << bit_in_word)); + +if (dev->tnode_width > (32 - bit_in_word)) { + bit_in_word = (32 - bit_in_word); + word_in_map++;; + mask = + dev->tnode_mask >> bit_in_word; + map[word_in_map] &= ~mask; + map[word_in_map] |= (mask & (val >> bit_in_word)); + } +} + +u32 yaffs_get_group_base (struct yaffs_dev *dev,struct yaffs_tnode *tn, +unsigned pos) +{ +u32 *map = (u32 *) tn; +u32 bit_in_map; +u32 bit_in_word; +u32 word_in_map; +u32 val; + + pos &=YAFFS_TNODES_LEVEL0_MASK ; + + bit_in_map = pos * dev->tnode_width; + word_in_map = bit_in_map /32 ; + bit_in_word = bit_in_map & (32 -1 ); + + val = map[word_in_map] >> bit_in_word; + +if (dev->tnode_width > (32 - bit_in_word)) { + bit_in_word = (32 - bit_in_word); + word_in_map++;; + val |= (map[word_in_map] << bit_in_word); + } + + val &= dev->tnode_mask; + val <<= dev->chunk_grp_bits; + +return val; +} + +/* ------------------- End of individual tnode manipulation -----------------*/ + +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ +* The look up tree is represented by the top tnode and the number of top_level +* in the tree. 0 means only the level 0 tnode is in the tree. +*/ + +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ +struct yaffs_tnode *yaffs_find_tnode_0 (struct yaffs_dev *dev, +struct yaffs_file_var *file_struct, +u32 chunk_id) +{ +struct yaffs_tnode *tn = file_struct->top; +u32 i; +int required_depth; +int level = file_struct->top_level; + + dev = dev; + +/* Check sane level and chunk Id */ +if (level <0 || level >YAFFS_TNODES_MAX_LEVEL ) +return NULL ; + +if (chunk_id >YAFFS_MAX_CHUNK_ID ) +return NULL ; + +/* First check we're tall enough (ie enough top_level) */ + + i = chunk_id >>YAFFS_TNODES_LEVEL0_BITS ; + required_depth =0 ; +while (i) { + i >>=YAFFS_TNODES_INTERNAL_BITS ; + required_depth++; + } + +if (required_depth > file_struct->top_level) +return NULL ;/* Not tall enough, so we can't find it */ + +/* Traverse down to level 0 */ +while (level >0 && tn) { + tn = tn->internal[(chunk_id >> + (YAFFS_TNODES_LEVEL0_BITS + + (level -1 ) * +YAFFS_TNODES_INTERNAL_BITS )) & +YAFFS_TNODES_INTERNAL_MASK ]; + level--; + } + +return tn; +} + +/* add_find_tnode_0 finds the level 0 tnode if it exists, +* otherwise first expands the tree. +* This happens in two steps: +* 1. If the tree isn't tall enough, then make it taller. +* 2. Scan down the tree towards the level 0 tnode adding tnodes if required. +* +* Used when modifying the tree. +* +* If the tn argument is NULL, then a fresh tnode will be added otherwise the +* specified tn will be plugged into the ttree. +*/ + +struct yaffs_tnode *yaffs_add_find_tnode_0 (struct yaffs_dev *dev, +struct yaffs_file_var *file_struct, +u32 chunk_id, +struct yaffs_tnode *passed_tn) +{ +int required_depth; +int i; +int l; +struct yaffs_tnode *tn; +u32 x; + +/* Check sane level and page Id */ +if (file_struct->top_level <0 + || file_struct->top_level >YAFFS_TNODES_MAX_LEVEL ) +return NULL ; + +if (chunk_id >YAFFS_MAX_CHUNK_ID ) +return NULL ; + +/* First check we're tall enough (ie enough top_level) */ + + x = chunk_id >>YAFFS_TNODES_LEVEL0_BITS ; + required_depth =0 ; +while (x) { + x >>=YAFFS_TNODES_INTERNAL_BITS ; + required_depth++; + } + +if (required_depth > file_struct->top_level) { +/* Not tall enough, gotta make the tree taller */ +for (i = file_struct->top_level; i < required_depth; i++) { + + tn =yaffs_get_tnode (dev); + +if (tn) { + tn->internal[0 ] = file_struct->top; + file_struct->top = tn; + file_struct->top_level++; + }else { +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs: no more tnodes" ); +return NULL ; + } + } + } + +/* Traverse down to level 0, adding anything we need */ + + l = file_struct->top_level; + tn = file_struct->top; + +if (l >0 ) { +while (l >0 && tn) { + x = (chunk_id >> + (YAFFS_TNODES_LEVEL0_BITS + + (l -1 ) *YAFFS_TNODES_INTERNAL_BITS )) & +YAFFS_TNODES_INTERNAL_MASK ; + +if ((l >1 ) && !tn->internal[x]) { +/* Add missing non-level-zero tnode */ + tn->internal[x] =yaffs_get_tnode (dev); +if (!tn->internal[x]) +return NULL ; + }else if (l ==1 ) { +/* Looking from level 1 at level 0 */ +if (passed_tn) { +/* If we already have one, release it */ +if (tn->internal[x]) +yaffs_free_tnode (dev, + tn->internal[x]); + tn->internal[x] = passed_tn; + + }else if (!tn->internal[x]) { +/* Don't have one, none passed in */ + tn->internal[x] =yaffs_get_tnode (dev); +if (!tn->internal[x]) +return NULL ; + } + } + + tn = tn->internal[x]; + l--; + } + }else { +/* top is level 0 */ +if (passed_tn) { +memcpy (tn, passed_tn, + (dev->tnode_width *YAFFS_NTNODES_LEVEL0 ) /8 ); +yaffs_free_tnode (dev, passed_tn); + } + } + +return tn; +} + +static int yaffs_tags_match (const struct yaffs_ext_tags *tags,int obj_id, +int chunk_obj) +{ +return (tags->chunk_id == chunk_obj && + tags->obj_id == obj_id && !tags->is_deleted) ?1 :0 ; + +} + +static int yaffs_find_chunk_in_group (struct yaffs_dev *dev,int the_chunk, +struct yaffs_ext_tags *tags,int obj_id, +int inode_chunk) +{ +int j; + +for (j =0 ; the_chunk && j < dev->chunk_grp_size; j++) { +if (yaffs_check_chunk_bit + (dev, the_chunk / dev->param.chunks_per_block, + the_chunk % dev->param.chunks_per_block)) { + +if (dev->chunk_grp_size ==1 ) +return the_chunk; +else { +yaffs_rd_chunk_tags_nand (dev, the_chunk,NULL , + tags); +if (yaffs_tags_match (tags, + obj_id, inode_chunk)) { +/* found it; */ +return the_chunk; + } + } + } + the_chunk++; + } +return -1 ; +} + +static int yaffs_find_chunk_in_file (struct yaffs_obj *in,int inode_chunk, +struct yaffs_ext_tags *tags) +{ +/*Get the Tnode, then get the level 0 offset chunk offset */ +struct yaffs_tnode *tn; +int the_chunk =-1 ; +struct yaffs_ext_tags local_tags; +int ret_val =-1 ; +struct yaffs_dev *dev = in->my_dev; + +if (!tags) { +/* Passed a NULL, so use our own tags space */ + tags = &local_tags; + } + + tn =yaffs_find_tnode_0 (dev, &in->variant.file_variant, inode_chunk); + +if (tn) { + the_chunk =yaffs_get_group_base (dev, tn, inode_chunk); + + ret_val = +yaffs_find_chunk_in_group (dev, the_chunk, tags, in->obj_id, + inode_chunk); + } +return ret_val; +} + +static int yaffs_find_del_file_chunk (struct yaffs_obj *in,int inode_chunk, +struct yaffs_ext_tags *tags) +{ +/* Get the Tnode, then get the level 0 offset chunk offset */ +struct yaffs_tnode *tn; +int the_chunk =-1 ; +struct yaffs_ext_tags local_tags; +struct yaffs_dev *dev = in->my_dev; +int ret_val =-1 ; + +if (!tags) { +/* Passed a NULL, so use our own tags space */ + tags = &local_tags; + } + + tn =yaffs_find_tnode_0 (dev, &in->variant.file_variant, inode_chunk); + +if (tn) { + + the_chunk =yaffs_get_group_base (dev, tn, inode_chunk); + + ret_val = +yaffs_find_chunk_in_group (dev, the_chunk, tags, in->obj_id, + inode_chunk); + +/* Delete the entry in the filestructure (if found) */ +if (ret_val !=-1 ) +yaffs_load_tnode_0 (dev, tn, inode_chunk,0 ); + } + +return ret_val; +} + +int yaffs_put_chunk_in_file (struct yaffs_obj *in,int inode_chunk, +int nand_chunk,int in_scan) +{ +/* NB in_scan is zero unless scanning. +* For forward scanning, in_scan is > 0; +* for backward scanning in_scan is < 0 +* +* nand_chunk = 0 is a dummy insert to make sure the tnodes are there. +*/ + +struct yaffs_tnode *tn; +struct yaffs_dev *dev = in->my_dev; +int existing_cunk; +struct yaffs_ext_tags existing_tags; +struct yaffs_ext_tags new_tags; +unsigned existing_serial, new_serial; + +if (in->variant_type !=YAFFS_OBJECT_TYPE_FILE ) { +/* Just ignore an attempt at putting a chunk into a non-file +* during scanning. +* If it is not during Scanning then something went wrong! +*/ +if (!in_scan) { +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs tragedy:attempt to put data chunk into a non-file" + ); +YBUG (); + } + +yaffs_chunk_del (dev, nand_chunk,1 , __LINE__); +return YAFFS_OK ; + } + + tn =yaffs_add_find_tnode_0 (dev, + &in->variant.file_variant, + inode_chunk,NULL ); +if (!tn) +return YAFFS_FAIL ; + +if (!nand_chunk) +/* Dummy insert, bail now */ +return YAFFS_OK ; + + existing_cunk =yaffs_get_group_base (dev, tn, inode_chunk); + +if (in_scan !=0 ) { +/* If we're scanning then we need to test for duplicates +* NB This does not need to be efficient since it should only +* happen when the power fails during a write, then only one +* chunk should ever be affected. +* +* Correction for YAFFS2: This could happen quite a lot and we +* need to think about efficiency! TODO +* Update: For backward scanning we don't need to re-read tags +* so this is quite cheap. +*/ + +if (existing_cunk >0 ) { +/* NB Right now existing chunk will not be real +* chunk_id if the chunk group size > 1 +* thus we have to do a FindChunkInFile to get the +* real chunk id. +* +* We have a duplicate now we need to decide which +* one to use: +* +* Backwards scanning YAFFS2: The old one is what +* we use, dump the new one. +* YAFFS1: Get both sets of tags and compare serial +* numbers. +*/ + +if (in_scan >0 ) { +/* Only do this for forward scanning */ +yaffs_rd_chunk_tags_nand (dev, + nand_chunk, +NULL , &new_tags); + +/* Do a proper find */ + existing_cunk = +yaffs_find_chunk_in_file (in, inode_chunk, + &existing_tags); + } + +if (existing_cunk <=0 ) { +/*Hoosterman - how did this happen? */ + +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs tragedy: existing chunk < 0 in scan" + ); + + } + +/* NB The deleted flags should be false, otherwise +* the chunks will not be loaded during a scan +*/ + +if (in_scan >0 ) { + new_serial = new_tags.serial_number; + existing_serial = existing_tags.serial_number; + } + +if ((in_scan >0 ) && + (existing_cunk <=0 || + ((existing_serial +1 ) &3 ) == new_serial)) { +/* Forward scanning. +* Use new +* Delete the old one and drop through to +* update the tnode +*/ +yaffs_chunk_del (dev, existing_cunk,1 , + __LINE__); + }else { +/* Backward scanning or we want to use the +* existing one +* Delete the new one and return early so that +* the tnode isn't changed +*/ +yaffs_chunk_del (dev, nand_chunk,1 , __LINE__); +return YAFFS_OK ; + } + } + + } + +if (existing_cunk ==0 ) + in->n_data_chunks++; + +yaffs_load_tnode_0 (dev, tn, inode_chunk, nand_chunk); + +return YAFFS_OK ; +} + +static void yaffs_soft_del_chunk (struct yaffs_dev *dev,int chunk) +{ +struct yaffs_block_info *the_block; +unsigned block_no; + +yaffs_trace (YAFFS_TRACE_DELETION ,"soft delete chunk %d" , chunk); + + block_no = chunk / dev->param.chunks_per_block; + the_block =yaffs_get_block_info (dev, block_no); +if (the_block) { + the_block->soft_del_pages++; + dev->n_free_chunks++; +yaffs2_update_oldest_dirty_seq (dev, block_no, the_block); + } +} + +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all +* the chunks in the file. +* All soft deleting does is increment the block's softdelete count and pulls +* the chunk out of the tnode. +* Thus, essentially this is the same as DeleteWorker except that the chunks +* are soft deleted. +*/ + +static int yaffs_soft_del_worker (struct yaffs_obj *in,struct yaffs_tnode *tn, +u32 level,int chunk_offset) +{ +int i; +int the_chunk; +int all_done =1 ; +struct yaffs_dev *dev = in->my_dev; + +if (tn) { +if (level >0 ) { +for (i =YAFFS_NTNODES_INTERNAL -1 ; + all_done && i >=0 ; + i--) { +if (tn->internal[i]) { + all_done = +yaffs_soft_del_worker (in, + tn->internal[i], + level -1 , + (chunk_offset << +YAFFS_TNODES_INTERNAL_BITS ) + + i); +if (all_done) { +yaffs_free_tnode (dev, + tn->internal[i]); + tn->internal[i] =NULL ; + }else { +/* Can this happen? */ + } + } + } +return (all_done) ?1 :0 ; + }else if (level ==0 ) { +for (i =YAFFS_NTNODES_LEVEL0 -1 ; i >=0 ; i--) { + the_chunk =yaffs_get_group_base (dev, tn, i); +if (the_chunk) { +yaffs_soft_del_chunk (dev, the_chunk); +yaffs_load_tnode_0 (dev, tn, i,0 ); + } + } +return 1 ; + } + } +return 1 ; +} + +static void yaffs_remove_obj_from_dir (struct yaffs_obj *obj) +{ +struct yaffs_dev *dev = obj->my_dev; +struct yaffs_obj *parent; + +yaffs_verify_obj_in_dir (obj); + parent = obj->parent; + +yaffs_verify_dir (parent); + +if (dev && dev->param.remove_obj_fn) + dev->param.remove_obj_fn (obj); + +list_del_init (&obj->siblings); + obj->parent =NULL ; + +yaffs_verify_dir (parent); +} + +void yaffs_add_obj_to_dir (struct yaffs_obj *directory,struct yaffs_obj *obj) +{ +if (!directory) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"tragedy: Trying to add an object to a null pointer directory" + ); +YBUG (); +return ; + } +if (directory->variant_type !=YAFFS_OBJECT_TYPE_DIRECTORY ) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"tragedy: Trying to add an object to a non-directory" + ); +YBUG (); + } + +if (obj->siblings.prev ==NULL ) { +/* Not initialised */ +YBUG (); + } + +yaffs_verify_dir (directory); + +yaffs_remove_obj_from_dir (obj); + +/* Now add it */ +list_add (&obj->siblings, &directory->variant.dir_variant.children); + obj->parent = directory; + +if (directory == obj->my_dev->unlinked_dir + || directory == obj->my_dev->del_dir) { + obj->unlinked =1 ; + obj->my_dev->n_unlinked_files++; + obj->rename_allowed =0 ; + } + +yaffs_verify_dir (directory); +yaffs_verify_obj_in_dir (obj); +} + +static int yaffs_change_obj_name (struct yaffs_obj *obj, +struct yaffs_obj *new_dir, +const YCHAR *new_name,int force,int shadows) +{ +int unlink_op; +int del_op; +struct yaffs_obj *existing_target; + +if (new_dir ==NULL ) + new_dir = obj->parent;/* use the old directory */ + +if (new_dir->variant_type !=YAFFS_OBJECT_TYPE_DIRECTORY ) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"tragedy: yaffs_change_obj_name: new_dir is not a directory" + ); +YBUG (); + } + +/* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ +if (obj->my_dev->param.is_yaffs2) + unlink_op = (new_dir == obj->my_dev->unlinked_dir); +else + unlink_op = (new_dir == obj->my_dev->unlinked_dir + && obj->variant_type ==YAFFS_OBJECT_TYPE_FILE ); + + del_op = (new_dir == obj->my_dev->del_dir); + + existing_target =yaffs_find_by_name (new_dir, new_name); + +/* If the object is a file going into the unlinked directory, +* then it is OK to just stuff it in since duplicate names are OK. +* else only proceed if the new name does not exist and we're putting +* it into a directory. +*/ +if ((unlink_op || + del_op || + force || + (shadows >0 ) || + !existing_target) && + new_dir->variant_type ==YAFFS_OBJECT_TYPE_DIRECTORY ) { +yaffs_set_obj_name (obj, new_name); + obj->dirty =1 ; + +yaffs_add_obj_to_dir (new_dir, obj); + +if (unlink_op) + obj->unlinked =1 ; + +/* If it is a deletion then we mark it as a shrink for gc */ +if (yaffs_update_oh (obj, new_name,0 , del_op, shadows,NULL ) >= +0 ) +return YAFFS_OK ; + } +return YAFFS_FAIL ; +} + +/*------------------------ Short Operations Cache ------------------------------ +* In many situations where there is no high level buffering a lot of +* reads might be short sequential reads, and a lot of writes may be short +* sequential writes. eg. scanning/writing a jpeg file. +* In these cases, a short read/write cache can provide a huge perfomance +* benefit with dumb-as-a-rock code. +* In Linux, the page cache provides read buffering and the short op cache +* provides write buffering. +* +* There are a small number (~10) of cache chunks per device so that we don't +* need a very intelligent search. +*/ + +static int yaffs_obj_cache_dirty (struct yaffs_obj *obj) +{ +struct yaffs_dev *dev = obj->my_dev; +int i; +struct yaffs_cache *cache; +int n_caches = obj->my_dev->param.n_caches; + +for (i =0 ; i < n_caches; i++) { + cache = &dev->cache[i]; +if (cache->object == obj && cache->dirty) +return 1 ; + } + +return 0 ; +} + +static void yaffs_flush_file_cache (struct yaffs_obj *obj) +{ +struct yaffs_dev *dev = obj->my_dev; +int lowest =-99 ;/* Stop compiler whining. */ +int i; +struct yaffs_cache *cache; +int chunk_written =0 ; +int n_caches = obj->my_dev->param.n_caches; + +if (n_caches >0 ) { +do { + cache =NULL ; + +/* Find the lowest dirty chunk for this object */ +for (i =0 ; i < n_caches; i++) { +if (dev->cache[i].object == obj && + dev->cache[i].dirty) { +if (!cache + || dev->cache[i].chunk_id < + lowest) { + cache = &dev->cache[i]; + lowest = cache->chunk_id; + } + } + } + +if (cache && !cache->locked) { +/* Write it out and free it up */ + chunk_written = +yaffs_wr_data_obj (cache->object, + cache->chunk_id, + cache->data, + cache->n_bytes,1 ); + cache->dirty =0 ; + cache->object =NULL ; + } + }while (cache && chunk_written >0 ); + +if (cache) +/* Hoosterman, disk full while writing cache out. */ +yaffs_trace (YAFFS_TRACE_ERROR , +"yaffs tragedy: no space during cache write" ); + } +} + +/*yaffs_flush_whole_cache(dev) +* +* +*/ + +void yaffs_flush_whole_cache (struct yaffs_dev *dev) +{ +struct yaffs_obj *obj; +int n_caches = dev->param.n_caches; +int i; + +/* Find a dirty object in the cache and flush it... +* until there are no further dirty objects. +*/ +do { + obj =NULL ; +for (i =0 ; i < n_caches && !obj; i++) { +if (dev->cache[i].object && dev->cache[i].dirty) + obj = dev->cache[i].object; + } +if (obj) +yaffs_flush_file_cache (obj); + }while (obj); + +} + +/* Grab us a cache chunk for use. +* First look for an empty one. +* Then look for the least recently used non-dirty one. +* Then look for the least recently used dirty one...., flush and look again. +*/ +static struct yaffs_cache *yaffs_grab_chunk_worker (struct yaffs_dev *dev) +{ +int i; + +if (dev->param.n_caches >0 ) { +for (i =0 ; i < dev->param.n_caches; i++) { +if (!dev->cache[i].object) +return &dev->cache[i]; + } + } +return NULL ; +} + +static struct yaffs_cache *yaffs_grab_chunk_cache (struct yaffs_dev *dev) +{ +struct yaffs_cache *cache; +struct yaffs_obj *the_obj; +int usage; +int i; +int pushout; + +if (dev->param.n_caches >0 ) { +/* Try find a non-dirty one... */ + + cache =yaffs_grab_chunk_worker (dev); + +if (!cache) { +/* They were all dirty, find the LRU object and flush +* its cache, then find again. +* NB what's here is not very accurate, +* we actually flush the object with the LRU chunk. +*/ + +/* With locking we can't assume we can use entry zero, +* Set the_obj to a valid pointer for Coverity. */ + + the_obj = dev->cache[0 ].object; + usage =-1 ; + cache =NULL ; + pushout =-1 ; + +for (i =0 ; i < dev->param.n_caches; i++) { +if (dev->cache[i].object && + !dev->cache[i].locked && + (dev->cache[i].last_use < usage + || !cache)) { + usage = dev->cache[i].last_use; + the_obj = dev->cache[i].object; + cache = &dev->cache[i]; + pushout = i; + } + } + +if (!cache || cache->dirty) { +/* Flush and try again */ +yaffs_flush_file_cache (the_obj); + cache =yaffs_grab_chunk_worker (dev); + } + } +return cache; + }else { +return NULL ; + } +} + +/* Find a cached chunk */ +static struct yaffs_cache *yaffs_find_chunk_cache (const struct yaffs_obj *obj, +int chunk_id) +{ +struct yaffs_dev *dev = obj->my_dev; +int i; + +if (dev->param.n_caches >0 ) { +for (i =0 ; i < dev->param.n_caches; i++) { +if (dev->cache[i].object == obj && + dev->cache[i].chunk_id == chunk_id) { + dev->cache_hits++; + +return &dev->cache[i]; + } + } + } +return NULL ; +} + +/* Mark the chunk for the least recently used algorithym */ +static void yaffs_use_cache (struct yaffs_dev *dev,struct yaffs_cache *cache, +int is_write) +{ +if (dev->param.n_caches >0 ) { +if (dev->cache_last_use <0 || + dev->cache_last_use >100000000 ) { +/* Reset the cache usages */ +int i; +for (i =1 ; i < dev->param.n_caches; i++) + dev->cache[i].last_use =0 ; + + dev->cache_last_use =0 ; + } + dev->cache_last_use++; + cache->last_use = dev->cache_last_use; + +if (is_write) + cache->dirty =1 ; + } +} + +/* Invalidate a single cache page. +* Do this when a whole page gets written, +* ie the short cache for this page is no longer valid. +*/ +static void yaffs_invalidate_chunk_cache (struct yaffs_obj *object,int chunk_id) +{ +if (object->my_dev->param.n_caches >0 ) { +struct yaffs_cache *cache = +yaffs_find_chunk_cache (object, chunk_id); + +if (cache) + cache->object =NULL ; + } +} + +/* Invalidate all the cache pages associated with this object +* Do this whenever ther file is deleted or resized. +*/ +static void yaffs_invalidate_whole_cache (struct yaffs_obj *in) +{ +int i; +struct yaffs_dev *dev = in->my_dev; + +if (dev->param.n_caches >0 ) { +/* Invalidate it. */ +for (i =0 ; i < dev->param.n_caches; i++) { +if (dev->cache[i].object == in) + dev->cache[i].object =NULL ; + } + } +} + +static void yaffs_unhash_obj (struct yaffs_obj *obj) +{ +int bucket; +struct yaffs_dev *dev = obj->my_dev; + +/* If it is still linked into the bucket list, free from the list */ +if (!list_empty (&obj->hash_link)) { +list_del_init (&obj->hash_link); + bucket =yaffs_hash_fn (obj->obj_id); + dev->obj_bucket[bucket].count--; + } +} + +/* FreeObject frees up a Object and puts it back on the free list */ +static void yaffs_free_obj (struct yaffs_obj *obj) +{ +struct yaffs_dev *dev = obj->my_dev; + +yaffs_trace (YAFFS_TRACE_OS ,"FreeObject %p inode %p" , + obj, obj->my_inode); + +if (!obj) { +YBUG (); +return ; + } +if (obj->parent) +YBUG (); +if (!list_empty (&obj->siblings)) +YBUG (); + +if (obj->my_inode) { +/* We're still hooked up to a cached inode. +* Don't delete now, but mark for later deletion +*/ + obj->defered_free =1 ; +return ; + } + +yaffs_unhash_obj (obj); + +yaffs_free_raw_obj (dev, obj); + dev->n_obj--; + dev->checkpoint_blocks_required =0 ;/* force recalculation */ +} + +void yaffs_handle_defered_free (struct yaffs_obj *obj) +{ +if (obj->defered_free) +yaffs_free_obj (obj); +} + +static int yaffs_generic_obj_del (struct yaffs_obj *in) +{ +/* Iinvalidate the file's data in the cache, without flushing. */ +yaffs_invalidate_whole_cache (in); + +if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) { +/* Move to unlinked directory so we have a deletion record */ +yaffs_change_obj_name (in, in->my_dev->del_dir,_Y ("deleted" ),0 , +0 ); + } + +yaffs_remove_obj_from_dir (in); +yaffs_chunk_del (in->my_dev, in->hdr_chunk,1 , __LINE__); + in->hdr_chunk =0 ; + +yaffs_free_obj (in); +return YAFFS_OK ; + +} + +static void yaffs_soft_del_file (struct yaffs_obj *obj) +{ +if (obj->deleted && + obj->variant_type ==YAFFS_OBJECT_TYPE_FILE && !obj->soft_del) { +if (obj->n_data_chunks <=0 ) { +/* Empty file with no duplicate object headers, +* just delete it immediately */ +yaffs_free_tnode (obj->my_dev, + obj->variant.file_variant.top); + obj->variant.file_variant.top =NULL ; +yaffs_trace (YAFFS_TRACE_TRACING , +"yaffs: Deleting empty file %d" , + obj->obj_id); +yaffs_generic_obj_del (obj); + }else { +yaffs_soft_del_worker (obj, + obj->variant.file_variant.top, + obj->variant. + file_variant.top_level,0 ); + obj->soft_del =1 ; + } + } +} + +/* Pruning removes any part of the file structure tree that is beyond the +* bounds of the file (ie that does not point to chunks). +* +* A file should only get pruned when its size is reduced. +* +* Before pruning, the chunks must be pulled from the tree and the +* level 0 tnode entries must be zeroed out. +* Could also use this for file deletion, but that's probably better handled +* by a special case. +* +* This function is recursive. For levels > 0 the function is called again on +* any sub-tree. For level == 0 we just check if the sub-tree has data. +* If there is no data in a subtree then it is pruned. +*/ + +static struct yaffs_tnode *yaffs_prune_worker (struct yaffs_dev *dev, +struct yaffs_tnode *tn,u32 level, +int del0) +{ +int i; +int has_data; + +if (tn) { + has_data =0 ; + +if (level >0 ) { +for (i =0 ; i <YAFFS_NTNODES_INTERNAL ; i++) { +if (tn->internal[i]) { + tn->internal[i] = +yaffs_prune_worker (dev, + tn->internal[i], + level -1 , + (i ==0 ) ? del0 :1 ); + } + +if (tn->internal[i]) + has_data++; + } + }else { +int tnode_size_u32 = dev->tnode_size /sizeof (u32); +u32 *map = (u32 *) tn; + +for (i =0 ; !has_data && i < tnode_size_u32; i++) { +if (map[i]) + has_data++; + } + } + +if (has_data ==0 && del0) { +/* Free and return NULL */ + +yaffs_free_tnode (dev, tn); + tn =NULL ; + } + } +return tn; +} + +static int yaffs_prune_tree (struct yaffs_dev *dev, +struct yaffs_file_var *file_struct) +{ +int i; +int has_data; +int done =0 ; +struct yaffs_tnode *tn; + +if (file_struct->top_level >0 ) { + file_struct->top = +yaffs_prune_worker (dev, file_struct->top, + file_struct->top_level,0 ); + +/* Now we have a tree with all the non-zero branches NULL but +* the height is the same as it was. +* Let's see if we can trim internal tnodes to shorten the tree. +* We can do this if only the 0th element in the tnode is in use +* (ie all the non-zero are NULL) +*/ + +while (file_struct->top_level && !done) { + tn = file_struct->top; + + has_data =0 ; +for (i =1 ; i <YAFFS_NTNODES_INTERNAL ; i++) { +if (tn->internal[i]) + has_data++; + } + +if (!has_data) { + file_struct->top = tn->internal[0 ]; + file_struct->top_level--; +yaffs_free_tnode (dev, tn); + }else { + done =1 ; + } + } + } +return YAFFS_OK ; +} + +/*-------------------- End of File Structure functions.-------------------*/ + +/* alloc_empty_obj gets us a clean Object.*/ +static struct yaffs_obj *yaffs_alloc_empty_obj (struct yaffs_dev *dev) +{ +struct yaffs_obj *obj =yaffs_alloc_raw_obj (dev); + +if (obj) { + dev->n_obj++; + +/* Now sweeten it up... */ + +memset (obj,0 ,sizeof (struct yaffs_obj )); + obj->being_created =1 ; + + obj->my_dev = dev; + obj->hdr_chunk =0 ; + obj->variant_type =YAFFS_OBJECT_TYPE_UNKNOWN ; +INIT_LIST_HEAD (&(obj->hard_links)); +INIT_LIST_HEAD (&(obj->hash_link)); +INIT_LIST_HEAD (&obj->siblings); + +/* Now make the directory sane */ +if (dev->root_dir) { + obj->parent = dev->root_dir; +list_add (&(obj->siblings), + &dev->root_dir->variant.dir_variant.children); + } + +/* Add it to the lost and found directory. +* NB Can't put root or lost-n-found in lost-n-found so +* check if lost-n-found exists first +*/ +if (dev->lost_n_found) +yaffs_add_obj_to_dir (dev->lost_n_found, obj); + + obj->being_created =0 ; + } + + dev->checkpoint_blocks_required =0 ;/* force recalculation */ + +return obj; +} + +static int yaffs_find_nice_bucket (struct yaffs_dev *dev) +{ +int i; +int l =999 ; +int lowest =999999 ; + +/* Search for the shortest list or one that +* isn't too long. +*/ + +for (i =0 ; i <10 && lowest >4 ; i++) { + dev->bucket_finder++; + dev->bucket_finder %=YAFFS_NOBJECT_BUCKETS ; +if (dev->obj_bucket[dev->bucket_finder].count < lowest) { + lowest = dev->obj_bucket[dev->bucket_finder].count; + l = dev->bucket_finder; + } + } + +return l; +} + +static int yaffs_new_obj_id (struct yaffs_dev *dev) +{ +int bucket =yaffs_find_nice_bucket (dev); +int found =0 ; +struct list_head *i; +u32 n = (u32 ) bucket; + +/* Now find an object value that has not already been taken +* by scanning the list. +*/ + +while (!found) { + found =1 ; + n +=YAFFS_NOBJECT_BUCKETS ; +if (1 || dev->obj_bucket[bucket].count >0 ) { +list_for_each (i, &dev->obj_bucket[bucket].list) { +/* If there is already one in the list */ + if (i && list_entry(i, struct yaffs_obj, + hash_link)->obj_id == n) { + found =0 ; + } + } + } + } +return n; +} + +static void yaffs_hash_obj (struct yaffs_obj *in) +{ +int bucket =yaffs_hash_fn (in->obj_id); +struct yaffs_dev *dev = in->my_dev; + +list_add (&in->hash_link, &dev->obj_bucket[bucket].list); + dev->obj_bucket[bucket].count++; +} + +struct yaffs_obj *yaffs_find_by_number (struct yaffs_dev *dev,u32 number) +{ +int bucket =yaffs_hash_fn (number); +struct list_head *i; +struct yaffs_obj *in; + +list_for_each (i, &dev->obj_bucket[bucket].list) { +/* Look if it is in the list */ + in = list_entry(i, struct yaffs_obj, hash_link); +if (in->obj_id == number) { +/* Don't show if it is defered free */ +if (in->defered_free) +return NULL ; +return in; + } + } + +return NULL ; +} + +struct yaffs_obj *yaffs_new_obj (struct yaffs_dev *dev,int number, +enum yaffs_obj_type type) +{ +struct yaffs_obj *the_obj =NULL ; +struct yaffs_tnode *tn =NULL ; + +if (number <0 ) + number =yaffs_new_obj_id (dev); + +if (type ==YAFFS_OBJECT_TYPE_FILE ) { + tn =yaffs_get_tnode (dev); +if (!tn) +return NULL ; + } + + the_obj =yaffs_alloc_empty_obj (dev); +if (!the_obj) { +if (tn) +yaffs_free_tnode (dev, tn); +return NULL ; + } + +if (the_obj) { + the_obj->fake =0 ; + the_obj->rename_allowed =1 ; + the_obj->unlink_allowed =1 ; + the_obj->obj_id = number; +yaffs_hash_obj (the_obj); + the_obj->variant_type = type; +yaffs_load_current_time (the_obj,1 ,1 ); + +switch (type) { +case YAFFS_OBJECT_TYPE_FILE : + the_obj->variant.file_variant.file_size =0 ; + the_obj->variant.file_variant.scanned_size =0 ; + the_obj->variant.file_variant.shrink_size = ~0 ; +/* max */ + the_obj->variant.file_variant.top_level =0 ; + the_obj->variant.file_variant.top = tn; +break ; +case YAFFS_OBJECT_TYPE_DIRECTORY : +INIT_LIST_HEAD (&the_obj->variant.dir_variant.children); +INIT_LIST_HEAD (&the_obj->variant.dir_variant.dirty); +break ; +case YAFFS_OBJECT_TYPE_SYMLINK : +case YAFFS_OBJECT_TYPE_HARDLINK : +case YAFFS_OBJECT_TYPE_SPECIAL : +/* No action required */ +break ; +case YAFFS_OBJECT_TYPE_UNKNOWN : +/* todo this should not happen */ +break ; + } + } + +return the_obj; +} + +static struct yaffs_obj *yaffs_create_fake_dir (struct yaffs_dev *dev, +int number,u32 mode) +{ + +struct yaffs_obj *obj = +yaffs_new_obj (dev, number,YAFFS_OBJECT_TYPE_DIRECTORY ); + +if (obj) { + obj->fake =1 ;/* it is fake so it might not use NAND */ + obj->rename_allowed =0 ; + obj->unlink_allowed =0 ; + obj->deleted =0 ; + obj->unlinked =0 ; + obj->yst_mode = mode; + obj->my_dev = dev; + obj->hdr_chunk =0 ;/* Not a valid chunk. */ + } +return obj; + +} + + +static void yaffs_init_tnodes_and_objs (struct yaffs_dev *dev) +{ +int i; + + dev->n_obj =0 ; + dev->n_tnodes =0 ; +yaffs_init_raw_tnodes_and_objs (dev); + +for (i =0 ; i <YAFFS_NOBJECT_BUCKETS ; i++) { +INIT_LIST_HEAD (&dev->obj_bucket[i].list); + dev->obj_bucket[i].count =0 ; + } +} + +struct yaffs_obj *yaffs_find_or_create_by_number (struct yaffs_dev *dev, +int number, +enum yaffs_obj_type type) +{ +struct yaffs_obj *the_obj =NULL ; + +if (number >0 ) + the_obj =yaffs_find_by_number (dev, number); + +if (!the_obj) + the_obj =yaffs_new_obj (dev, number, type); + +return the_obj; + +} + +YCHAR *yaffs_clone_str (const YCHAR *str) +{ +YCHAR *new_str =NULL ; +int len; + +if (!str) + str =_Y ("" ); + + len =strnlen (str,YAFFS_MAX_ALIAS_LENGTH ); + new_str =kmalloc ((len +1 ) *sizeof (YCHAR ),GFP_NOFS ); +if (new_str) { +strncpy (new_str, str, len); + new_str[len] =0 ; + } +return new_str; + +} +/* +*yaffs_update_parent() handles fixing a directories mtime and ctime when a new +* link (ie. name) is created or deleted in the directory. +* +* ie. +* create dir/a : update dir's mtime/ctime +* rm dir/a: update dir's mtime/ctime +* modify dir/a: don't update dir's mtimme/ctime +* +* This can be handled immediately or defered. Defering helps reduce the number +* of updates when many files in a directory are changed within a brief period. +* +* If the directory updating is defered then yaffs_update_dirty_dirs must be +* called periodically. +*/ + +static void yaffs_update_parent (struct yaffs_obj *obj) +{ +struct yaffs_dev *dev; + +if (!obj) +return ; + dev = obj->my_dev; + obj->dirty =1 ; +yaffs_load_current_time (obj,0 ,1 ); +if (dev->param.defered_dir_update) { +struct list_head *link = &obj->variant.dir_variant.dirty; + +if (list_empty (link)) { +list_add (link, &dev->dirty_dirs); +yaffs_trace (YAFFS_TRACE_BACKGROUND , +"Added object %d to dirty directories" , + obj->obj_id); + } + + }else { +yaffs_update_oh (obj,NULL ,0 ,0 ,0 ,NULL ); + } +} + +void yaffs_update_dirty_dirs (struct yaffs_dev *dev) +{ +struct list_head *link; +struct yaffs_obj *obj; +struct yaffs_dir_var *d_s; +union yaffs_obj_var *o_v; + +yaffs_trace (YAFFS_TRACE_BACKGROUND ,"Update dirty directories" ); + +while (!list_empty (&dev->dirty_dirs)) { + link = dev->dirty_dirs.next; +list_del_init (link); + + d_s = list_entry(link, struct yaffs_dir_var, dirty); + o_v = list_entry(d_s, union yaffs_obj_var, dir_variant); + obj = list_entry(o_v, struct yaffs_obj, variant); + +yaffs_trace (YAFFS_TRACE_BACKGROUND ,"Update directory %d" , + obj->obj_id); + +if (obj->dirty) +yaffs_update_oh (obj,NULL ,0 ,0 ,0 ,NULL ); + } +} + +/* +* Mknod (create) a new object. +* equiv_obj only has meaning for a hard link; +* alias_str only has meaning for a symlink. +* rdev only has meaning for devices (a subset of special objects) +*/ + +static struct yaffs_obj *yaffs_create_obj (enum yaffs_obj_type type, +struct yaffs_obj *parent, +const YCHAR *name, +u32 mode, +u32 uid, +u32 gid, +struct yaffs_obj *equiv_obj, +const YCHAR *alias_str,u32 rdev) +{ +struct yaffs_obj *in; +YCHAR *str =NULL ; +struct yaffs_dev *dev = parent->my_dev; + +/* Check if the entry exists. +* If it does then fail the call since we don't want a dup. */ +if (yaffs_find_by_name (parent, name)) +return NULL ; + +if (type ==YAFFS_OBJECT_TYPE_SYMLINK ) { + str =yaffs_clone_str (alias_str); +if (!str) +return NULL ; + } + + in =yaffs_new_obj (dev,-1 , type); + +if (!in) { +kfree (str); +return NULL ; + } + +if (in) { + in->hdr_chunk =0 ; + in->valid =1 ; + in->variant_type = type; + + in->yst_mode = mode; + +yaffs_attribs_init (in, gid, uid, rdev); + + in->n_data_chunks =0 ; + +yaffs_set_obj_name (in, name); + in->dirty =1 ; + +yaffs_add_obj_to_dir (parent, in); + + in->my_dev = parent->my_dev; + +switch (type) { +case YAFFS_OBJECT_TYPE_SYMLINK : + in->variant.symlink_variant.alias = str; +break ; +case YAFFS_OBJECT_TYPE_HARDLINK : + in->variant.hardlink_variant.equiv_obj = equiv_obj; + in->variant.hardlink_variant.equiv_id = + equiv_obj->obj_id; +list_add (&in->hard_links, &equiv_obj->hard_links); +break ; +case YAFFS_OBJECT_TYPE_FILE : +case YAFFS_OBJECT_TYPE_DIRECTORY : +case YAFFS_OBJECT_TYPE_SPECIAL : +case YAFFS_OBJECT_TYPE_UNKNOWN : +/* do nothing */ +break ; + } + +if (yaffs_update_oh (in, name,0 ,0 ,0 ,NULL ) <0 ) { +/* Could not create the object header, fail */ +yaffs_del_obj (in); + in =NULL ; + } + +yaffs_update_parent (parent); + } + +return in; +} + +struct yaffs_obj *yaffs_create_file (struct yaffs_obj *parent, +const YCHAR *name,u32 mode,u32 uid, +u32 gid) +{ +return yaffs_create_obj (YAFFS_OBJECT_TYPE_FILE , parent, name, mode, + uid, gid,NULL ,NULL ,0 ); +} + +struct yaffs_obj *yaffs_create_dir (struct yaffs_obj *parent,const YCHAR *name, +u32 mode,u32 uid,u32 gid) +{ +return yaffs_create_obj (YAFFS_OBJECT_TYPE_DIRECTORY , parent, name, + mode, uid, gid,NULL ,NULL ,0 ); +} + +struct yaffs_obj *yaffs_create_special (struct yaffs_obj *parent, +const YCHAR *name,u32 mode,u32 uid, +u32 gid,u32 rdev) +{ +return yaffs_create_obj (YAFFS_OBJECT_TYPE_SPECIAL , parent, name, mode, + uid, gid,NULL ,NULL , rdev); +} + +struct yaffs_obj *yaffs_create_symlink (struct yaffs_obj *parent, +const YCHAR *name,u32 mode,u32 uid, +u32 gid,const YCHAR *alias) +{ +return yaffs_create_obj (YAFFS_OBJECT_TYPE_SYMLINK , parent, name, mode, + uid, gid,NULL , alias,0 ); +} + +/* yaffs_link_obj returns the object id of the equivalent object.*/ +struct yaffs_obj *yaffs_link_obj (struct yaffs_obj *parent,const YCHAR * name, +struct yaffs_obj *equiv_obj) +{ +/* Get the real object in case we were fed a hard link obj */ + equiv_obj =yaffs_get_equivalent_obj (equiv_obj); + +if (yaffs_create_obj + (YAFFS_OBJECT_TYPE_HARDLINK , parent, name,0 ,0 ,0 , + equiv_obj,NULL ,0 )) +return equiv_obj; +else +return NULL ; + +} + + + +/*---------------------- Block Management and Page Allocation -------------*/ + +static int yaffs_init_blocks (struct yaffs_dev *dev) +{ +int n_blocks = dev->internal_end_block - dev->internal_start_block +1 ; + + dev->block_info =NULL ; + dev->chunk_bits =NULL ; + dev->alloc_block =-1 ;/* force it to get a new one */ + +/* If the first allocation strategy fails, thry the alternate one */ + dev->block_info = +kmalloc (n_blocks *sizeof (struct yaffs_block_info ),GFP_NOFS ); +if (!dev->block_info) { + dev->block_info = +vmalloc (n_blocks *sizeof (struct yaffs_block_info )); + dev->block_info_alt =1 ; + }else { + dev->block_info_alt =0 ; + } + +if (dev->block_info) { +/* Set up dynamic blockinfo stuff. Round up bytes. */ + dev->chunk_bit_stride = (dev->param.chunks_per_block +7 ) /8 ; + dev->chunk_bits = +kmalloc (dev->chunk_bit_stride * n_blocks,GFP_NOFS ); +if (!dev->chunk_bits) { + dev->chunk_bits = +vmalloc (dev->chunk_bit_stride * n_blocks); + dev->chunk_bits_alt =1 ; + }else { + dev->chunk_bits_alt =0 ; + } + } + +if (dev->block_info && dev->chunk_bits) { +memset (dev->block_info,0 , + n_blocks *sizeof (struct yaffs_block_info )); +memset (dev->chunk_bits,0 , dev->chunk_bit_stride * n_blocks); +return YAFFS_OK ; + } + +return YAFFS_FAIL ; +} + +static void yaffs_deinit_blocks (struct yaffs_dev *dev) +{ +if (dev->block_info_alt && dev->block_info) +vfree (dev->block_info); +else +kfree (dev->block_info); + + dev->block_info_alt =0 ; + + dev->block_info =NULL ; + +if (dev->chunk_bits_alt && dev->chunk_bits) +vfree (dev->chunk_bits); +else +kfree (dev->chunk_bits); + dev->chunk_bits_alt =0 ; + dev->chunk_bits =NULL ; +} + +void yaffs_block_became_dirty (struct yaffs_dev *dev,int block_no) +{ +struct yaffs_block_info *bi =yaffs_get_block_info (dev, block_no); +int erased_ok =0 ; + +/* If the block is still healthy erase it and mark as clean. +* If the block has had a data failure, then retire it. +*/ + +yaffs_trace (YAFFS_TRACE_GC |YAFFS_TRACE_ERASE , +"yaffs_block_became_dirty block %d state %d %s" , + block_no, bi->block_state, + (bi->needs_retiring) ?"needs retiring" :"" ); + +yaffs2_clear_oldest_dirty_seq (dev, bi); + + bi->block_state =YAFFS_BLOCK_STATE_DIRTY ; + +/* If this is the block being garbage collected then stop gc'ing */ +if (block_no == dev->gc_block) + dev->gc_block =0 ; + +/* If this block is currently the best candidate for gc +* then drop as a candidate */ +if (block_no == dev->gc_dirtiest) { + dev->gc_dirtiest =0 ; + dev->gc_pages_in_use =0 ; + } + +if (!bi->needs_retiring) { +yaffs2_checkpt_invalidate (dev); + erased_ok =yaffs_erase_block (dev, block_no); +if (!erased_ok) { + dev->n_erase_failures++; +yaffs_trace (YAFFS_TRACE_ERROR |YAFFS_TRACE_BAD_BLOCKS , +"**>> Erasure failed %d" , block_no); + } + } + +if (erased_ok && + ((yaffs_trace_mask &YAFFS_TRACE_ERASE ) + || !yaffs_skip_verification (dev))) { +int i; +for (i =0 ; i < dev->param.chunks_per_block; i++) { +if (!yaffs_check_chunk_erased + (dev, block_no * dev->param.chunks_per_block + i)) { +yaffs_trace (YAFFS_TRACE_ERROR , +">>Block %d erasure supposedly OK, but chunk %d not erased" , + block_no, i); + } + } + } + +if (erased_ok) { +/* Clean it up... */ + bi->block_state =YAFFS_BLOCK_STATE_EMPTY ; + bi->seq_number =0 ; + dev->n_erased_blocks++; + bi->pages_in_use =0 ; + bi->soft_del_pages =0 ; + bi->has_shrink_hdr =0 ; + bi->skip_erased_check =1 ;/* Clean, so no need to check */ + bi->gc_prioritise =0 ; +yaffs_clear_chunk_bits (dev, block_no); + +yaffs_trace (YAFFS_TRACE_ERASE , +"Erased block %d" , block_no); + }else { +/* We lost a block of free space */ + dev->n_free_chunks -= dev->param.chunks_per_block; +yaffs_retire_block (dev, block_no); +yaffs_trace (YAFFS_TRACE_ERROR |YAFFS_TRACE_BAD_BLOCKS , +"**>> Block %d retired" , block_no); + } +} + +static int yaffs_gc_process_chunk (struct yaffs_dev *dev, +struct yaffs_block_info *bi, +int old_chunk,u8 *buffer) +{ +int new_chunk; +int mark_flash =1 ; +struct yaffs_ext_tags tags; +struct yaffs_obj *object; +int matching_chunk; +int ret_val =YAFFS_OK ; + +yaffs_init_tags (&tags); +yaffs_rd_chunk_tags_nand (dev, old_chunk, + buffer, &tags); + object =yaffs_find_by_number (dev, tags.obj_id); + +yaffs_trace (YAFFS_TRACE_GC_DETAIL , +"Collecting chunk in block %d, %d %d %d " , + dev->gc_chunk, tags.obj_id, + tags.chunk_id, tags.n_bytes); + +if (object && !yaffs_skip_verification (dev)) { +if (tags.chunk_id ==0 ) + matching_chunk = + object->hdr_chunk; +else if (object->soft_del) +/* Defeat the test */ + matching_chunk = old_chunk; +else + matching_chunk = +yaffs_find_chunk_in_file + (object, tags.chunk_id, +NULL ); + +if (old_chunk != matching_chunk) +yaffs_trace (YAFFS_TRACE_ERROR , +"gc: page in gc mismatch: %d %d %d %d" , + old_chunk, + matching_chunk, + tags.obj_id, + tags.chunk_id); + } + +if (!object) { +yaffs_trace (YAFFS_TRACE_ERROR , +"page %d in gc has no object: %d %d %d " , + old_chunk, + tags.obj_id, tags.chunk_id, + tags.n_bytes); + } + +if (object && + object->deleted && + object->soft_del && tags.chunk_id !=0 ) { +/* Data chunk in a soft deleted file, +* throw it away. +* It's a soft deleted data chunk, +* No need to copy this, just forget +* about it and fix up the object. +*/ + +/* Free chunks already includes +* softdeleted chunks, how ever this +* chunk is going to soon be really +* deleted which will increment free +* chunks. We have to decrement free +* chunks so this works out properly. +*/ + dev->n_free_chunks--; + bi->soft_del_pages--; + + object->n_data_chunks--; +if (object->n_data_chunks <=0 ) { +/* remeber to clean up obj */ + dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id; + dev->n_clean_ups++; + } + mark_flash =0 ; + }else if (object) { +/* It's either a data chunk in a live +* file or an ObjectHeader, so we're +* interested in it. +* NB Need to keep the ObjectHeaders of +* deleted files until the whole file +* has been deleted off +*/ + tags.serial_number++; + dev->n_gc_copies++; + +if (tags.chunk_id ==0 ) { +/* It is an object Id, +* We need to nuke the +* shrinkheader flags since its +* work is done. +* Also need to clean up +* shadowing. +*/ +struct yaffs_obj_hdr *oh; + oh = (struct yaffs_obj_hdr *) buffer; + + oh->is_shrink =0 ; + tags.extra_is_shrink =0 ; + oh->shadows_obj =0 ; + oh->inband_shadowed_obj_id =0 ; + tags.extra_shadows =0 ; + +/* Update file size */ +if (object->variant_type ==YAFFS_OBJECT_TYPE_FILE ) { + oh->file_size = + object->variant.file_variant.file_size; + tags.extra_length = oh->file_size; + } + +yaffs_verify_oh (object, oh, &tags,1 ); + new_chunk = +yaffs_write_new_chunk (dev, (u8 *) oh, &tags,1 ); + }else { + new_chunk = +yaffs_write_new_chunk (dev, buffer, &tags,1 ); + } + +if (new_chunk <0 ) { + ret_val =YAFFS_FAIL ; + }else { + +/* Now fix up the Tnodes etc. */ + +if (tags.chunk_id ==0 ) { +/* It's a header */ + object->hdr_chunk = new_chunk; + object->serial = tags.serial_number; + }else { +/* It's a data chunk */ +yaffs_put_chunk_in_file (object, tags.chunk_id, + new_chunk,0 ); + } + } + } +if (ret_val ==YAFFS_OK ) +yaffs_chunk_del (dev, old_chunk, mark_flash, __LINE__); +return ret_val; +} + +static int yaffs_gc_block (struct yaffs_dev *dev,int block,int whole_block) +{ +int old_chunk; +int ret_val =YAFFS_OK ; +int i; +int is_checkpt_block; +int max_copies; +int chunks_before =yaffs_get_erased_chunks (dev); +int chunks_after; +struct yaffs_block_info *bi =yaffs_get_block_info (dev, block); + + is_checkpt_block = (bi->block_state ==YAFFS_BLOCK_STATE_CHECKPOINT ); + +yaffs_trace (YAFFS_TRACE_TRACING , +"Collecting block %d, in use %d, shrink %d, whole_block %d" , + block, bi->pages_in_use, bi->has_shrink_hdr, + whole_block); + +/*yaffs_verify_free_chunks(dev); */ + +if (bi->block_state ==YAFFS_BLOCK_STATE_FULL ) + bi->block_state =YAFFS_BLOCK_STATE_COLLECTING ; + + bi->has_shrink_hdr =0 ;/* clear the flag so that the block can erase */ + + dev->gc_disable =1 ; + +if (is_checkpt_block || !yaffs_still_some_chunks (dev, block)) { +yaffs_trace (YAFFS_TRACE_TRACING , +"Collecting block %d that has no chunks in use" , + block); +yaffs_block_became_dirty (dev, block); + }else { + +u8 *buffer =yaffs_get_temp_buffer (dev, __LINE__); + +yaffs_verify_blk (dev, bi, block); + + max_copies = (whole_block) ? dev->param.chunks_per_block :5 ; + old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk; + +for (/* init already done */ ; + ret_val ==YAFFS_OK && + dev->gc_chunk < dev->param.chunks_per_block && + (bi->block_state ==YAFFS_BLOCK_STATE_COLLECTING ) && + max_copies >0 ; + dev->gc_chunk++, old_chunk++) { +if (yaffs_check_chunk_bit (dev, block, dev->gc_chunk)) { +/* Page is in use and might need to be copied */ + max_copies--; + ret_val =yaffs_gc_process_chunk (dev, bi, + old_chunk, buffer); + } + } +yaffs_release_temp_buffer (dev, buffer, __LINE__); + } + +yaffs_verify_collected_blk (dev, bi, block); + +if (bi->block_state ==YAFFS_BLOCK_STATE_COLLECTING ) { +/* +* The gc did not complete. Set block state back to FULL +* because checkpointing does not restore gc. +*/ + bi->block_state =YAFFS_BLOCK_STATE_FULL ; + }else { +/* The gc completed. */ +/* Do any required cleanups */ +for (i =0 ; i < dev->n_clean_ups; i++) { +/* Time to delete the file too */ +struct yaffs_obj *object = +yaffs_find_by_number (dev, dev->gc_cleanup_list[i]); +if (object) { +yaffs_free_tnode (dev, + object->variant.file_variant.top); + object->variant.file_variant.top =NULL ; +yaffs_trace (YAFFS_TRACE_GC , +"yaffs: About to finally delete object %d" , + object->obj_id); +yaffs_generic_obj_del (object); + object->my_dev->n_deleted_files--; + } + + } + chunks_after =yaffs_get_erased_chunks (dev); +if (chunks_before >= chunks_after) +yaffs_trace (YAFFS_TRACE_GC , +"gc did not increase free chunks before %d after %d" , + chunks_before, chunks_after); + dev->gc_block =0 ; + dev->gc_chunk =0 ; + dev->n_clean_ups =0 ; + } + + dev->gc_disable =0 ; + +return ret_val; +} + +/* +* find_gc_block() selects the dirtiest block (or close enough) +* for garbage collection. +*/ + +static unsigned yaffs_find_gc_block (struct yaffs_dev *dev, +int aggressive,int background) +{ +int i; +int iterations; +unsigned selected =0 ; +int prioritised =0 ; +int prioritised_exist =0 ; +struct yaffs_block_info *bi; +int threshold; + +/* First let's see if we need to grab a prioritised block */ +if (dev->has_pending_prioritised_gc && !aggressive) { + dev->gc_dirtiest =0 ; + bi = dev->block_info; +for (i = dev->internal_start_block; + i <= dev->internal_end_block && !selected; i++) { + +if (bi->gc_prioritise) { + prioritised_exist =1 ; +if (bi->block_state ==YAFFS_BLOCK_STATE_FULL && +yaffs_block_ok_for_gc (dev, bi)) { + selected = i; + prioritised =1 ; + } + } + bi++; + } + +/* +* If there is a prioritised block and none was selected then +* this happened because there is at least one old dirty block +* gumming up the works. Let's gc the oldest dirty block. +*/ + +if (prioritised_exist && + !selected && dev->oldest_dirty_block >0 ) + selected = dev->oldest_dirty_block; + +if (!prioritised_exist)/* None found, so we can clear this */ + dev->has_pending_prioritised_gc =0 ; + } + +/* If we're doing aggressive GC then we are happy to take a less-dirty +* block, and search harder. +* else (leasurely gc), then we only bother to do this if the +* block has only a few pages in use. +*/ + +if (!selected) { +int pages_used; +int n_blocks = + dev->internal_end_block - dev->internal_start_block +1 ; +if (aggressive) { + threshold = dev->param.chunks_per_block; + iterations = n_blocks; + }else { +int max_threshold; + +if (background) + max_threshold = dev->param.chunks_per_block /2 ; +else + max_threshold = dev->param.chunks_per_block /8 ; + +if (max_threshold <YAFFS_GC_PASSIVE_THRESHOLD ) + max_threshold =YAFFS_GC_PASSIVE_THRESHOLD ; + + threshold = background ? (dev->gc_not_done +2 ) *2 :0 ; +if (threshold <YAFFS_GC_PASSIVE_THRESHOLD ) + threshold =YAFFS_GC_PASSIVE_THRESHOLD ; +if (threshold > max_threshold) + threshold = max_threshold; + + iterations = n_blocks /16 +1 ; +if (iterations >100 ) + iterations =100 ; + } + +for (i =0 ; + i < iterations && + (dev->gc_dirtiest <1 || + dev->gc_pages_in_use >YAFFS_GC_GOOD_ENOUGH ); + i++) { + dev->gc_block_finder++; +if (dev->gc_block_finder < dev->internal_start_block || + dev->gc_block_finder > dev->internal_end_block) + dev->gc_block_finder = + dev->internal_start_block; + + bi =yaffs_get_block_info (dev, dev->gc_block_finder); + + pages_used = bi->pages_in_use - bi->soft_del_pages; + +if (bi->block_state ==YAFFS_BLOCK_STATE_FULL && + pages_used < dev->param.chunks_per_block && + (dev->gc_dirtiest <1 || + pages_used < dev->gc_pages_in_use) && +yaffs_block_ok_for_gc (dev, bi)) { + dev->gc_dirtiest = dev->gc_block_finder; + dev->gc_pages_in_use = pages_used; + } + } + +if (dev->gc_dirtiest >0 && dev->gc_pages_in_use <= threshold) + selected = dev->gc_dirtiest; + } + +/* +* If nothing has been selected for a while, try the oldest dirty +* because that's gumming up the works. +*/ + +if (!selected && dev->param.is_yaffs2 && + dev->gc_not_done >= (background ?10 :20 )) { +yaffs2_find_oldest_dirty_seq (dev); +if (dev->oldest_dirty_block >0 ) { + selected = dev->oldest_dirty_block; + dev->gc_dirtiest = selected; + dev->oldest_dirty_gc_count++; + bi =yaffs_get_block_info (dev, selected); + dev->gc_pages_in_use = + bi->pages_in_use - bi->soft_del_pages; + }else { + dev->gc_not_done =0 ; + } + } + +if (selected) { +yaffs_trace (YAFFS_TRACE_GC , +"GC Selected block %d with %d free, prioritised:%d" , + selected, + dev->param.chunks_per_block - dev->gc_pages_in_use, + prioritised); + + dev->n_gc_blocks++; +if (background) + dev->bg_gcs++; + + dev->gc_dirtiest =0 ; + dev->gc_pages_in_use =0 ; + dev->gc_not_done =0 ; +if (dev->refresh_skip >0 ) + dev->refresh_skip--; + }else { + dev->gc_not_done++; +yaffs_trace (YAFFS_TRACE_GC , +"GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" , + dev->gc_block_finder, dev->gc_not_done, threshold, + dev->gc_dirtiest, dev->gc_pages_in_use, + dev->oldest_dirty_block, background ?" bg" :"" ); + } + +return selected; +} + +/* New garbage collector +* If we're very low on erased blocks then we do aggressive garbage collection +* otherwise we do "leasurely" garbage collection. +* Aggressive gc looks further (whole array) and will accept less dirty blocks. +* Passive gc only inspects smaller areas and only accepts more dirty blocks. +* +* The idea is to help clear out space in a more spread-out manner. +* Dunno if it really does anything useful. +*/ +static int yaffs_check_gc (struct yaffs_dev *dev,int background) +{ +int aggressive =0 ; +int gc_ok =YAFFS_OK ; +int max_tries =0 ; +int min_erased; +int erased_chunks; +int checkpt_block_adjust; + +if (dev->param.gc_control && (dev->param.gc_control (dev) &1 ) ==0 ) +return YAFFS_OK ; + +if (dev->gc_disable) { +/* Bail out so we don't get recursive gc */ +return YAFFS_OK ; + } + +/* This loop should pass the first time. +* Only loops here if the collection does not increase space. +*/ + +do { + max_tries++; + + checkpt_block_adjust =yaffs_calc_checkpt_blocks_required (dev); + + min_erased = + dev->param.n_reserved_blocks + checkpt_block_adjust +1 ; + erased_chunks = + dev->n_erased_blocks * dev->param.chunks_per_block; + +/* If we need a block soon then do aggressive gc. */ +if (dev->n_erased_blocks < min_erased) + aggressive =1 ; +else { +if (!background + && erased_chunks > (dev->n_free_chunks /4 )) +break ; + +if (dev->gc_skip >20 ) + dev->gc_skip =20 ; +if (erased_chunks < dev->n_free_chunks /2 || + dev->gc_skip <1 || background) + aggressive =0 ; +else { + dev->gc_skip--; +break ; + } + } + + dev->gc_skip =5 ; + +/* If we don't already have a block being gc'd then see if we +* should start another */ + +if (dev->gc_block <1 && !aggressive) { + dev->gc_block =yaffs2_find_refresh_block (dev); + dev->gc_chunk =0 ; + dev->n_clean_ups =0 ; + } +if (dev->gc_block <1 ) { + dev->gc_block = +yaffs_find_gc_block (dev, aggressive, background); + dev->gc_chunk =0 ; + dev->n_clean_ups =0 ; + } + +if (dev->gc_block >0 ) { + dev->all_gcs++; +if (!aggressive) + dev->passive_gc_count++; + +yaffs_trace (YAFFS_TRACE_GC , +"yaffs: GC n_erased_blocks %d aggressive %d" , + dev->n_erased_blocks, aggressive); + + gc_ok =yaffs_gc_block (dev, dev->gc_block, aggressive); + } + +if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) + && dev->gc_block >0 ) { +yaffs_trace (YAFFS_TRACE_GC , +"yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d" , + dev->n_erased_blocks, max_tries, + dev->gc_block); + } + }while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) && + (dev->gc_block >0 ) && (max_tries <2 )); + +return aggressive ? gc_ok :YAFFS_OK ; +} + +/* +* yaffs_bg_gc() +* Garbage collects. Intended to be called from a background thread. +* Returns non-zero if at least half the free chunks are erased. +*/ +int yaffs_bg_gc (struct yaffs_dev *dev,unsigned urgency) +{ +int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block; + +yaffs_trace (YAFFS_TRACE_BACKGROUND ,"Background gc %u" , urgency); + +yaffs_check_gc (dev,1 ); +return erased_chunks > dev->n_free_chunks /2 ; +} + +/*-------------------- Data file manipulation -----------------*/ + +static int yaffs_rd_data_obj (struct yaffs_obj *in,int inode_chunk,u8 * buffer) +{ +int nand_chunk =yaffs_find_chunk_in_file (in, inode_chunk,NULL ); + +if (nand_chunk >=0 ) +return yaffs_rd_chunk_tags_nand (in->my_dev, nand_chunk, + buffer,NULL ); +else { +yaffs_trace (YAFFS_TRACE_NANDACCESS , +"Chunk %d not found zero instead" , + nand_chunk); +/* get sane (zero) data if you read a hole */ +memset (buffer,0 , in->my_dev->data_bytes_per_chunk); +return 0 ; + } + +} + +void yaffs_chunk_del (struct yaffs_dev *dev,int chunk_id,int mark_flash, +int lyn) +{ +int block; +int page; +struct yaffs_ext_tags tags; +struct yaffs_block_info *bi; + +if (chunk_id <=0 ) +return ; + + dev->n_deletions++; + block = chunk_id / dev->param.chunks_per_block; + page = chunk_id % dev->param.chunks_per_block; + +if (!yaffs_check_chunk_bit (dev, block, page)) +yaffs_trace (YAFFS_TRACE_VERIFY , +"Deleting invalid chunk %d" , chunk_id); + + bi =yaffs_get_block_info (dev, block); + +yaffs2_update_oldest_dirty_seq (dev, block, bi); + +yaffs_trace (YAFFS_TRACE_DELETION , +"line %d delete of chunk %d" , + lyn, chunk_id); + +if (!dev->param.is_yaffs2 && mark_flash && + bi->block_state !=YAFFS_BLOCK_STATE_COLLECTING ) { + +yaffs_init_tags (&tags); + tags.is_deleted =1 ; +yaffs_wr_chunk_tags_nand (dev, chunk_id,NULL , &tags); +yaffs_handle_chunk_update (dev, chunk_id, &tags); + }else { + dev->n_unmarked_deletions++; + } + +/* Pull out of the management area. +* If the whole block became dirty, this will kick off an erasure. +*/ +if (bi->block_state ==YAFFS_BLOCK_STATE_ALLOCATING || + bi->block_state ==YAFFS_BLOCK_STATE_FULL || + bi->block_state ==YAFFS_BLOCK_STATE_NEEDS_SCANNING || + bi->block_state ==YAFFS_BLOCK_STATE_COLLECTING ) { + dev->n_free_chunks++; +yaffs_clear_chunk_bit (dev, block, page); + bi->pages_in_use--; + +if (bi->pages_in_use ==0 && + !bi->has_shrink_hdr && + bi->block_state !=YAFFS_BLOCK_STATE_ALLOCATING && + bi->block_state !=YAFFS_BLOCK_STATE_NEEDS_SCANNING ) {
Lines of this file are not shown. View the raw message.
fs/yaffs2/yaffs_guts.h new file +938 -0
938 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.7.1
Part of the diff is not shown here. View the raw message.
PATCH 9/10 Add yaffs2 file system: Linux glue code
In reply to Charles Manning--- fs/yaffs2/yaffs_linux.h | 41 + fs/yaffs2/yaffs_vfs.c | 2756 +++++++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yportenv.h | 70 ++ 3 files changed, 2867 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_linux.h create mode 100644 fs/yaffs2/yaffs_vfs.c create mode 100644 fs/yaffs2/yportenv.h
fs/yaffs2/yaffs_linux.h new file +41 -0
@@ -0,0 +1,41 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_LINUX_H__ +#define __YAFFS_LINUX_H__ + +#include "yportenv.h" + +struct yaffs_linux_context { +struct list_head context_list;/* List of these we have mounted */ +struct yaffs_dev *dev; +struct super_block *super; +struct task_struct *bg_thread;/* Background thread for this device */ +int bg_running; +struct mutex gross_lock;/* Gross locking mutex*/ +u8 *spare_buffer;/* For mtdif2 use. Don't know the buffer size +* at compile time so we have to allocate it. +*/ +struct list_head search_contexts; +void (*put_super_fn) (struct super_block *sb); + +struct task_struct *readdir_process; +unsigned mount_id; +}; + +#define yaffs_dev_to_lc (dev) ((struct yaffs_linux_context *)((dev)->os_context)) +#define yaffs_dev_to_mtd (dev) ((struct mtd_info *)((dev)->driver_context)) + +#endif
fs/yaffs2/yaffs_vfs.c new file +2756 -0
2,756 lines not on this page · raw message
fs/yaffs2/yportenv.h new file +70 -0
70 lines not on this page · raw message
Signature · 1 line
1.7.1
Re: [PATCH 09/10] Add yaffs2 file system: Linux glue code
Quoted 2 lines · Charles Manning
Signed-off-by Charles Manning <[email protected]>---
...
fs/yaffs2/yaffs_vfs.c line 546
Quoted 8 lines
fs/yaffs2/yaffs_vfs.c new file +8
-0+static int yaffs_setxattr (struct dentry *dentry,const char *name, +const void *value,size_t size,int flags) +{ +struct inode *inode = dentry->d_inode; +int error =0 ; +struct yaffs_dev *dev; +struct yaffs_obj *obj =yaffs_inode_to_obj (inode); +
You only use the local variable 'inode' in the call to yaffs_inode_to_obj(), so you could get rid of that local variable and just do
struct yaffs_obj *obj = yaffs_inode_to_obj(dentry->d_inode);
this applies to a few other function in this file as well.
Signature · 3 lines
Jesper Juhl <[email protected]> http://www.chaosbits.net/ Don't top-post http://www.catb.org/~esr/jargon/html/T/top-post.html Plain text mails only, please.
Re: [PATCH 09/10] Add yaffs2 file system: Linux glue code
In reply to Charles ManningQuoted 1 line · Charles Manning
Signed-off-by Charles Manning <[email protected]>
Hi Charles,
More comments below,
~Ryan
Quoted 126 lines
--- fs/yaffs2/yaffs_linux.h | 41 + fs/yaffs2/yaffs_vfs.c | 2756 +++++++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/yportenv.h | 70 ++ 3 files changed, 2867 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/yaffs_linux.h create mode 100644 fs/yaffs2/yaffs_vfs.c create mode 100644 fs/yaffs2/yportenv.hfs/yaffs2/yaffs_linux.h new file +41
-0@@ -0,0 +1,41 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YAFFS_LINUX_H__ +#define __YAFFS_LINUX_H__ + +#include "yportenv.h" + +struct yaffs_linux_context { +struct list_head context_list;/* List of these we have mounted */ +struct yaffs_dev *dev; +struct super_block *super; +struct task_struct *bg_thread;/* Background thread for this device */ +int bg_running; +struct mutex gross_lock;/* Gross locking mutex*/ +u8 *spare_buffer;/* For mtdif2 use. Don't know the buffer size +* at compile time so we have to allocate it. +*/ +struct list_head search_contexts; +void (*put_super_fn) (struct super_block *sb); + +struct task_struct *readdir_process; +unsigned mount_id; +}; + +#define yaffs_dev_to_lc (dev) ((struct yaffs_linux_context *)((dev)->os_context)) +#define yaffs_dev_to_mtd (dev) ((struct mtd_info *)((dev)->driver_context)) + +#endif fs/yaffs2/yaffs_vfs.c new file +64
-0@@ -0,0 +1,2756 @@ +/* +* YAFFS: Yet Another Flash File System. A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* Acknowledgements: +* Luc van OostenRyck for numerous patches. +* Nick Bane for numerous patches. +* Nick Bane for 2.5/2.6 integration. +* Andras Toth for mknod rdev issue. +* Michael Fischer for finding the problem with inode inconsistency. +* Some code bodily lifted from JFFS +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ + +/* +* +* This is the file system front-end to YAFFS that hooks it up to +* the VFS. +* +* Special notes: +* >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with +* this superblock +* >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this +* superblock +* >> inode->u.generic_ip points to the associated struct yaffs_obj. +*/ + +/* +* NB There are two variants of Linux VFS glue code. This variant supports +* a single version and should not include any multi-version code. +*/ +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/proc_fs.h> +#include <linux/smp_lock.h> +#include <linux/pagemap.h> +#include <linux/mtd/mtd.h> +#include <linux/interrupt.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <linux/namei.h> +#include <linux/exportfs.h> +#include <linux/kthread.h> +#include <linux/delay.h> +#include <linux/freezer.h> +#include <asm/div64.h> +#include <linux/statfs.h> +#include <linux/uaccess.h> +#include <linux/mtd/mtd.h> + +#include "yportenv.h" +#include "yaffs_trace.h" +#include "yaffs_guts.h" +#include "yaffs_attribs.h"
fs/yaffs2/yaffs_vfs.c line 74
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+#include "yaffs_linux.h" +#include "yaffs_mtdif.h" +#include "yaffs_mtdif1.h" +#include "yaffs_mtdif2.h" + +unsigned int yaffs_trace_mask =YAFFS_TRACE_BAD_BLOCKS |YAFFS_TRACE_ALWAYS ; +unsigned int yaffs_wr_attempts =YAFFS_WR_ATTEMPTS ; +unsigned int yaffs_auto_checkpoint =1 ; +unsigned int yaffs_gc_control =1 ; +unsigned int yaffs_bg_enable =1 ;
Some of these can be static I think.
fs/yaffs2/yaffs_vfs.c line 85
Quoted 11 lines
fs/yaffs2/yaffs_vfs.c new file +11
-0+ +/* Module Parameters */ +module_param (yaffs_trace_mask, uint,0644 ); +module_param (yaffs_wr_attempts, uint,0644 ); +module_param (yaffs_auto_checkpoint, uint,0644 ); +module_param (yaffs_gc_control, uint,0644 ); +module_param (yaffs_bg_enable, uint,0644 ); + +#define yaffs_devname (sb, buf) bdevname(sb->s_bdev, buf) + +static uint32_t YCALCBLOCKS (uint64_t partition_size,uint32_t block_size)
Lower case names for functions. Types should also be u32 and u64.
Quoted 6 lines
fs/yaffs2/yaffs_vfs.c new file +6
-0+{ +uint64_t result = partition_size; + +do_div (result, block_size); +return (uint32_t ) result; +}
fs/yaffs2/yaffs_vfs.c line 101
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ +#define yaffs_inode_to_obj_lv (iptr) ((iptr)->i_private) +#define yaffs_inode_to_obj (iptr)\ + ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr))) +#define yaffs_dentry_to_obj (dptr) yaffs_inode_to_obj((dptr)->d_inode) +#define yaffs_super_to_dev (sb) ((struct yaffs_dev *)sb->s_fs_info) + +#define update_dir_time (dir) do {\ + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \ + } while (0)
Any reason this can't be a function. Possibly static inline?
Quoted 69 lines
fs/yaffs2/yaffs_vfs.c new file +69
-0+ + +static unsigned yaffs_gc_control_callback (struct yaffs_dev *dev) +{ +return yaffs_gc_control; +} + +static void yaffs_gross_lock (struct yaffs_dev *dev) +{ +yaffs_trace (YAFFS_TRACE_LOCK ,"yaffs locking %p" , current); +mutex_lock (&(yaffs_dev_to_lc (dev)->gross_lock)); +yaffs_trace (YAFFS_TRACE_LOCK ,"yaffs locked %p" , current); +} + +static void yaffs_gross_unlock (struct yaffs_dev *dev) +{ +yaffs_trace (YAFFS_TRACE_LOCK ,"yaffs unlocking %p" , current); +mutex_unlock (&(yaffs_dev_to_lc (dev)->gross_lock)); +} + +static void yaffs_fill_inode_from_obj (struct inode *inode, +struct yaffs_obj *obj); + +static struct inode *yaffs_iget (struct super_block *sb,unsigned long ino) +{ +struct inode *inode; +struct yaffs_obj *obj; +struct yaffs_dev *dev =yaffs_super_to_dev (sb); + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_iget for %lu" , ino); + + inode =iget_locked (sb, ino); +if (!inode) +return ERR_PTR (-ENOMEM ); +if (!(inode->i_state &I_NEW )) +return inode; + +/* NB This is called as a side effect of other functions, but +* we had to release the lock to prevent deadlocks, so +* need to lock again. +*/ + +yaffs_gross_lock (dev); + + obj =yaffs_find_by_number (dev, inode->i_ino); +yaffs_fill_inode_from_obj (inode, obj); + +yaffs_gross_unlock (dev); + +unlock_new_inode (inode); +return inode; +} + +struct inode *yaffs_get_inode (struct super_block *sb,int mode,int dev, +struct yaffs_obj *obj) +{ +struct inode *inode; + +if (!sb) { +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_get_inode for NULL super_block!!" ); +return NULL ; + + } + +if (!obj) { +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_get_inode for NULL object!!" ); +return NULL ;
fs/yaffs2/yaffs_vfs.c line 180
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ + } + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_get_inode for object %d" , + obj->obj_id); + + inode =yaffs_iget (sb, obj->obj_id); +if (IS_ERR (inode)) +return NULL ;
Should this function not propagate the error up by returning PTR_ERR also?
Quoted 30 lines
fs/yaffs2/yaffs_vfs.c new file +30
-0+ +/* NB Side effect: iget calls back to yaffs_read_inode(). */ +/* iget also increments the inode's i_count */ +/* NB You can't be holding gross_lock or deadlock will happen! */ + +return inode; +} + +static int yaffs_mknod (struct inode *dir,struct dentry *dentry,int mode, +dev_t rdev) +{ +struct inode *inode; +struct yaffs_obj *obj =NULL ; +struct yaffs_dev *dev; +struct yaffs_obj *parent =yaffs_inode_to_obj (dir); +int error = -ENOSPC ; +uid_t uid = current->cred->fsuid; +gid_t gid = + (dir->i_mode &S_ISGID ) ? dir->i_gid : current->cred->fsgid; + +if ((dir->i_mode &S_ISGID ) &&S_ISDIR (mode)) + mode |=S_ISGID ; + +if (parent) { +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_mknod: parent object %d type %d" , + parent->obj_id, parent->variant_type); + }else { +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_mknod: could not get parent object" );
fs/yaffs2/yaffs_vfs.c line 220
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+return -EPERM ; + } + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_mknod: making oject for %s, mode %x dev %x" , + dentry->d_name.name, mode, rdev); + + dev = parent->my_dev; + +yaffs_gross_lock (dev);
Possibly a start to removing the gross locking, or replacing it with more fine grained locking is to push it down into each of the creation functions below.
Quoted 20 lines
fs/yaffs2/yaffs_vfs.c new file +20
-0+ +switch (mode &S_IFMT ) { +default : +/* Special (socket, fifo, device...) */ +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_mknod: making special" ); + obj = +yaffs_create_special (parent, dentry->d_name.name, mode, uid, + gid,old_encode_dev (rdev)); +break ; +case S_IFREG :/* file */ +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_mknod: making file" ); + obj =yaffs_create_file (parent, dentry->d_name.name, mode, uid, + gid); +break ; +case S_IFDIR :/* directory */ +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_mknod: making directory" ); + obj =yaffs_create_dir (parent, dentry->d_name.name, mode, + uid, gid); +break ; +case S_IFLNK :/* symlink */
fs/yaffs2/yaffs_vfs.c line 250
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+yaffs_trace (YAFFS_TRACE_OS ,"yaffs_mknod: making symlink" ); + obj =NULL ;/* Do we ever get here? */ +break ; + } + +/* Can not call yaffs_get_inode() with gross lock held */ +yaffs_gross_unlock (dev); + +if (obj) { + inode =yaffs_get_inode (dir->i_sb, mode, rdev, obj);
if (!inode)?
Quoted 54 lines
fs/yaffs2/yaffs_vfs.c new file +54
-0+d_instantiate (dentry, inode); +update_dir_time (dir); +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_mknod created object %d count = %d" , + obj->obj_id,atomic_read (&inode->i_count)); + error =0 ; +yaffs_fill_inode_from_obj (dir, parent); + }else { +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_mknod failed making object" ); + error = -ENOMEM ; + } + +return error; +} + +static int yaffs_mkdir (struct inode *dir,struct dentry *dentry,int mode) +{ +return yaffs_mknod (dir, dentry, mode |S_IFDIR ,0 ); +} + +static int yaffs_create (struct inode *dir,struct dentry *dentry,int mode, +struct nameidata *n) +{ +return yaffs_mknod (dir, dentry, mode |S_IFREG ,0 ); +} + +static int yaffs_link (struct dentry *old_dentry,struct inode *dir, +struct dentry *dentry) +{ +struct inode *inode = old_dentry->d_inode; +struct yaffs_obj *obj =NULL ; +struct yaffs_obj *link =NULL ; +struct yaffs_dev *dev; + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_link" ); + + obj =yaffs_inode_to_obj (inode); + dev = obj->my_dev; + +yaffs_gross_lock (dev); + +if (!S_ISDIR (inode->i_mode))/* Don't link directories */ + link = +yaffs_link_obj (yaffs_inode_to_obj (dir), dentry->d_name.name, + obj); + +if (link) { + old_dentry->d_inode->i_nlink =yaffs_get_obj_link_count (obj); +d_instantiate (dentry, old_dentry->d_inode); +atomic_inc (&old_dentry->d_inode->i_count); +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_link link count %d i_count %d" , + old_dentry->d_inode->i_nlink, +atomic_read (&old_dentry->d_inode->i_count));
fs/yaffs2/yaffs_vfs.c line 314
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ } + +yaffs_gross_unlock (dev); + +if (link) { +update_dir_time (dir); +return 0 ; + } + +return -EPERM ;
I would change this to:
if (!link) return -EPERM; update_dir_time(dir); return 0;
To make the successful path more obvious.
Quoted 22 lines
fs/yaffs2/yaffs_vfs.c new file +22
-0+} + +static int yaffs_symlink (struct inode *dir,struct dentry *dentry, +const char *symname) +{ +struct yaffs_obj *obj; +struct yaffs_dev *dev; +uid_t uid = current->cred->fsuid; +gid_t gid = + (dir->i_mode &S_ISGID ) ? dir->i_gid : current->cred->fsgid; + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_symlink" ); + + dev =yaffs_inode_to_obj (dir)->my_dev; +yaffs_gross_lock (dev); + obj =yaffs_create_symlink (yaffs_inode_to_obj (dir), dentry->d_name.name, +S_IFLNK |S_IRWXUGO , uid, gid, symname); +yaffs_gross_unlock (dev); + +if (obj) { +struct inode *inode; +
fs/yaffs2/yaffs_vfs.c line 346
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ inode =yaffs_get_inode (dir->i_sb, obj->yst_mode,0 , obj); +d_instantiate (dentry, inode); +update_dir_time (dir); +yaffs_trace (YAFFS_TRACE_OS ,"symlink created OK" ); +return 0 ; + }else { +yaffs_trace (YAFFS_TRACE_OS ,"symlink not created" ); + } + +return -ENOMEM ;
Again, make the successful path more obvious:
if (!obj) {
yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
return -ENOMEM;
}
...
return 0;Quoted 25 lines
fs/yaffs2/yaffs_vfs.c new file +25
-0+} + +static struct dentry *yaffs_lookup (struct inode *dir,struct dentry *dentry, +struct nameidata *n) +{ +struct yaffs_obj *obj; +struct inode *inode =NULL ; +struct yaffs_dev *dev =yaffs_inode_to_obj (dir)->my_dev; + +if (current !=yaffs_dev_to_lc (dev)->readdir_process) +yaffs_gross_lock (dev); + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_lookup for %d:%s" , +yaffs_inode_to_obj (dir)->obj_id, dentry->d_name.name); + + obj =yaffs_find_by_name (yaffs_inode_to_obj (dir), dentry->d_name.name); + + obj =yaffs_get_equivalent_obj (obj);/* in case it was a hardlink */ + +/* Can't hold gross lock when calling yaffs_get_inode() */ +if (current !=yaffs_dev_to_lc (dev)->readdir_process) +yaffs_gross_unlock (dev); + +if (obj) {
fs/yaffs2/yaffs_vfs.c line 381
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+yaffs_trace (YAFFS_TRACE_OS , +"yaffs_lookup found %d" , obj->obj_id); + + inode =yaffs_get_inode (dir->i_sb, obj->yst_mode,0 , obj); + +if (inode) { +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_loookup dentry" ); +d_add (dentry, inode); +/* return dentry; */ +return NULL ;
This comment seems inaccurate.
fs/yaffs2/yaffs_vfs.c line 391
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ } + + }else { +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_lookup not found" ); + + } + +d_add (dentry, inode); + +return NULL ;
I can't even tell what the success path is here :-/.
Quoted 88 lines
fs/yaffs2/yaffs_vfs.c new file +88
-0+} + +static int yaffs_unlink (struct inode *dir,struct dentry *dentry) +{ +int ret_val; +struct yaffs_dev *dev; +struct yaffs_obj *obj; + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_unlink %d:%s" , + (int )(dir->i_ino), dentry->d_name.name); + obj =yaffs_inode_to_obj (dir); + dev = obj->my_dev; + +yaffs_gross_lock (dev); + + ret_val =yaffs_unlinker (obj, dentry->d_name.name); + +if (ret_val ==YAFFS_OK ) { + dentry->d_inode->i_nlink--; + dir->i_version++; +yaffs_gross_unlock (dev); +mark_inode_dirty (dentry->d_inode); +update_dir_time (dir); +return 0 ; + } +yaffs_gross_unlock (dev); +return -ENOTEMPTY ; +} + +static int yaffs_sync_object (struct file *file,int datasync) +{ + +struct yaffs_obj *obj; +struct yaffs_dev *dev; +struct dentry *dentry = file->f_path.dentry; + + obj =yaffs_dentry_to_obj (dentry); + + dev = obj->my_dev; + +yaffs_trace (YAFFS_TRACE_OS |YAFFS_TRACE_SYNC ,"yaffs_sync_object" ); +yaffs_gross_lock (dev); +yaffs_flush_file (obj,1 , datasync); +yaffs_gross_unlock (dev); +return 0 ; +} +/* +* The VFS layer already does all the dentry stuff for rename. +* +* NB: POSIX says you can rename an object over an old object of the same name +*/ +static int yaffs_rename (struct inode *old_dir,struct dentry *old_dentry, +struct inode *new_dir,struct dentry *new_dentry) +{ +struct yaffs_dev *dev; +int ret_val =YAFFS_FAIL ; +struct yaffs_obj *target; + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_rename" ); + dev =yaffs_inode_to_obj (old_dir)->my_dev; + +yaffs_gross_lock (dev); + +/* Check if the target is an existing directory that is not empty. */ + target =yaffs_find_by_name (yaffs_inode_to_obj (new_dir), + new_dentry->d_name.name); + +if (target && target->variant_type ==YAFFS_OBJECT_TYPE_DIRECTORY && + !list_empty (&target->variant.dir_variant.children)) { + +yaffs_trace (YAFFS_TRACE_OS ,"target is non-empty dir" ); + + ret_val =YAFFS_FAIL ; + }else { +/* Now does unlinking internally using shadowing mechanism */ +yaffs_trace (YAFFS_TRACE_OS ,"calling yaffs_rename_obj" ); + + ret_val =yaffs_rename_obj (yaffs_inode_to_obj (old_dir), + old_dentry->d_name.name, +yaffs_inode_to_obj (new_dir), + new_dentry->d_name.name); + } +yaffs_gross_unlock (dev); + +if (ret_val ==YAFFS_OK ) { +if (target) { + new_dentry->d_inode->i_nlink--;
fs/yaffs2/yaffs_vfs.c line 489
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+mark_inode_dirty (new_dentry->d_inode); + } + +update_dir_time (old_dir); +if (old_dir != new_dir) +update_dir_time (new_dir); +return 0 ; + }else { +return -ENOTEMPTY ; + }
if (ret_val != YAFFS_OK) return -ENOTEMPTY; ...
Quoted 5 lines
fs/yaffs2/yaffs_vfs.c new file +5
-0+} + +static int yaffs_setattr (struct dentry *dentry,struct iattr *attr) +{ +struct inode *inode = dentry->d_inode;
fs/yaffs2/yaffs_vfs.c line 504
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+int error =0 ; +struct yaffs_dev *dev; + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_setattr of object %d" , +yaffs_inode_to_obj (inode)->obj_id); + +/* Fail if a requested resize >= 2GB */ +if (attr->ia_valid &ATTR_SIZE && (attr->ia_size >>31 )) + error = -EINVAL ;
Here you set the error and then do nothing for the rest of the function because of all the if (error == 0) checks. Either return immediately here, or use a goto to get to the end of the function and then remove all the checks.
Quoted 41 lines
fs/yaffs2/yaffs_vfs.c new file +41
-0+ +if (error ==0 ) + error =inode_change_ok (inode, attr); +if (error ==0 ) { +int result; +if (!error) { +setattr_copy (inode, attr); +yaffs_trace (YAFFS_TRACE_OS ,"inode_setattr called" ); +if (attr->ia_valid &ATTR_SIZE ) { +truncate_setsize (inode, attr->ia_size); + inode->i_blocks = (inode->i_size +511 ) >>9 ; + } + } + dev =yaffs_inode_to_obj (inode)->my_dev; +if (attr->ia_valid &ATTR_SIZE ) { +yaffs_trace (YAFFS_TRACE_OS ,"resize to %d(%x)" , + (int )(attr->ia_size), + (int )(attr->ia_size)); + } +yaffs_gross_lock (dev); + result =yaffs_set_attribs (yaffs_inode_to_obj (inode), attr); +if (result ==YAFFS_OK ) + error =0 ; +else + error = -EPERM ; +yaffs_gross_unlock (dev); + } + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_setattr done returning %d" , error); + +return error; +} + +#ifdef CONFIG_YAFFS_XATTR +static int yaffs_setxattr (struct dentry *dentry,const char *name, +const void *value,size_t size,int flags) +{ +struct inode *inode = dentry->d_inode; +int error =0 ; +struct yaffs_dev *dev; +struct yaffs_obj *obj =yaffs_inode_to_obj (inode);
fs/yaffs2/yaffs_vfs.c line 555
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_setxattr of object %d" , obj->obj_id); + +if (error ==0 ) { +int result; + dev = obj->my_dev; +yaffs_gross_lock (dev); + result =yaffs_set_xattrib (obj, name, value, size, flags); +if (result ==YAFFS_OK ) + error =0 ;
error is already zero. error and result are also basically the same thing, I don't think you need both variables.
Quoted 12 lines
fs/yaffs2/yaffs_vfs.c new file +12
-0+else if (result <0 ) + error = result; +yaffs_gross_unlock (dev); + } +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_setxattr done returning %d" , error); + +return error; +} + +static ssize_t yaffs_getxattr (struct dentry *dentry,const char *name, +void *buff,size_t size) +{
fs/yaffs2/yaffs_vfs.c line 577
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+struct inode *inode = dentry->d_inode; +int error =0 ; +struct yaffs_dev *dev; +struct yaffs_obj *obj =yaffs_inode_to_obj (inode); + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_getxattr \"%s\" from object %d" , + name, obj->obj_id); + +if (error ==0 ) {
Umm, error is explicitly initialised to zero?
Quoted 11 lines
fs/yaffs2/yaffs_vfs.c new file +11
-0+ dev = obj->my_dev; +yaffs_gross_lock (dev); + error =yaffs_get_xattrib (obj, name, buff, size); +yaffs_gross_unlock (dev); + } +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_getxattr done returning %d" , error); + +return error; +} + +static int yaffs_removexattr (struct dentry *dentry,const char *name)
fs/yaffs2/yaffs_vfs.c line 598
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+{ +struct inode *inode = dentry->d_inode; +int error =0 ; +struct yaffs_dev *dev; +struct yaffs_obj *obj =yaffs_inode_to_obj (inode); + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_removexattr of object %d" , obj->obj_id); + +if (error ==0 ) {
Again, error is guaranteed to be zero here.
fs/yaffs2/yaffs_vfs.c line 604
Quoted 6 lines
fs/yaffs2/yaffs_vfs.c new file +6
-0+int result; + dev = obj->my_dev; +yaffs_gross_lock (dev); + result =yaffs_remove_xattrib (obj, name); +if (result ==YAFFS_OK ) + error =0 ;
and here.
Quoted 11 lines
fs/yaffs2/yaffs_vfs.c new file +11
-0+else if (result <0 ) + error = result; +yaffs_gross_unlock (dev); + } +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_removexattr done returning %d" , error); + +return error; +} + +static ssize_t yaffs_listxattr (struct dentry *dentry,char *buff,size_t size)
fs/yaffs2/yaffs_vfs.c line 625
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+{ +struct inode *inode = dentry->d_inode; +int error =0 ; +struct yaffs_dev *dev; +struct yaffs_obj *obj =yaffs_inode_to_obj (inode); + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_listxattr of object %d" , obj->obj_id); + +if (error ==0 ) {
and here.
Quoted 60 lines
fs/yaffs2/yaffs_vfs.c new file +60
-0+ dev = obj->my_dev; +yaffs_gross_lock (dev); + error =yaffs_list_xattrib (obj, buff, size); + yaffs_gross_unlock(dev); + } +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_listxattr done returning %d" , error); + +return error; +} + +#endif + +static const struct inode_operations yaffs_dir_inode_operations = { + .create = yaffs_create, + .lookup = yaffs_lookup, + .link = yaffs_link, + .unlink = yaffs_unlink, + .symlink = yaffs_symlink, + .mkdir = yaffs_mkdir, + .rmdir = yaffs_unlink, + .mknod = yaffs_mknod, + .rename = yaffs_rename, + .setattr = yaffs_setattr, +#ifdef CONFIG_YAFFS_XATTR + .setxattr = yaffs_setxattr, + .getxattr = yaffs_getxattr, + .listxattr = yaffs_listxattr, + .removexattr = yaffs_removexattr, +#endif +}; +/*-----------------------------------------------------------------*/ +/* Directory search context allows us to unlock access to yaffs during +* filldir without causing problems with the directory being modified. +* This is similar to the tried and tested mechanism used in yaffs direct. +* +* A search context iterates along a doubly linked list of siblings in the +* directory. If the iterating object is deleted then this would corrupt +* the list iteration, likely causing a crash. The search context avoids +* this by using the remove_obj_fn to move the search context to the +* next object before the object is deleted. +* +* Many readdirs (and thus seach conexts) may be alive simulateously so +* each struct yaffs_dev has a list of these. +* +* A seach context lives for the duration of a readdir. +* +* All these functions must be called while yaffs is locked. +*/ + +struct yaffs_search_context { +struct yaffs_dev *dev; +struct yaffs_obj *dir_obj; +struct yaffs_obj *next_return; +struct list_head others; +}; + +/* +* yaffs_new_search() creates a new search context, initialises it and +* adds it to the device's search context list.
fs/yaffs2/yaffs_vfs.c line 695
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+* +* Called at start of readdir. +*/ +static struct yaffs_search_context *yaffs_new_search (struct yaffs_obj *dir) +{ +struct yaffs_dev *dev = dir->my_dev; +struct yaffs_search_context *sc = +kmalloc (sizeof (struct yaffs_search_context ),GFP_NOFS ); + +if (sc) {
if (!sc)
return NULL;
Remove indentation of normal executation path :-).
Quoted 58 lines
fs/yaffs2/yaffs_vfs.c new file +58
-0+ sc->dir_obj = dir; + sc->dev = dev; +if (list_empty (&sc->dir_obj->variant.dir_variant.children)) + sc->next_return =NULL ; +else + sc->next_return = +list_entry (dir->variant.dir_variant.children.next, + struct yaffs_obj, siblings); +INIT_LIST_HEAD (&sc->others); +list_add (&sc->others, &(yaffs_dev_to_lc (dev)->search_contexts)); + } +return sc; +} + +/* +* yaffs_search_end() disposes of a search context and cleans up. +*/ +static void yaffs_search_end (struct yaffs_search_context *sc) +{ +if (sc) { +list_del (&sc->others); +kfree (sc); + } +} + +/* +* yaffs_search_advance() moves a search context to the next object. +* Called when the search iterates or when an object removal causes +* the search context to be moved to the next object. +*/ +static void yaffs_search_advance (struct yaffs_search_context *sc) +{ +if (!sc) +return ; + +if (sc->next_return ==NULL || +list_empty (&sc->dir_obj->variant.dir_variant.children)) + sc->next_return =NULL ; +else { +struct list_head *next = sc->next_return->siblings.next; + +if (next == &sc->dir_obj->variant.dir_variant.children) + sc->next_return =NULL ;/* end of list */ +else + sc->next_return = + list_entry(next, struct yaffs_obj, siblings); + } +} + +/* +* yaffs_remove_obj_callback() is called when an object is unlinked. +* We check open search contexts and advance any which are currently +* on the object being iterated. +*/ +static void yaffs_remove_obj_callback (struct yaffs_obj *obj) +{ + +struct list_head *i;
fs/yaffs2/yaffs_vfs.c line 763
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+struct yaffs_search_context *sc; +struct list_head *search_contexts = + &(yaffs_dev_to_lc (obj->my_dev)->search_contexts); + +/* Iterate through the directory search contexts. +* If any are currently on the object being removed, then advance +* the search context to the next object to prevent a hanging pointer. +*/ +list_for_each (i, search_contexts) { + sc = list_entry(i, struct yaffs_search_context, others);
list_for_each_entry(i, search_contexts, others)
Quoted 33 lines
fs/yaffs2/yaffs_vfs.c new file +33
-0+if (sc->next_return == obj) +yaffs_search_advance (sc); + } + +} + +static int yaffs_readdir (struct file *f,void *dirent,filldir_t filldir) +{ +struct yaffs_obj *obj; +struct yaffs_dev *dev; +struct yaffs_search_context *sc; +struct inode *inode = f->f_dentry->d_inode; +unsigned long offset, curoffs; +struct yaffs_obj *l; +int ret_val =0 ; +char name[YAFFS_MAX_NAME_LENGTH +1 ]; + + obj =yaffs_dentry_to_obj (f->f_dentry); + dev = obj->my_dev; + +yaffs_gross_lock (dev); + +yaffs_dev_to_lc (dev)->readdir_process = current; + + offset = f->f_pos; + + sc =yaffs_new_search (obj); +if (!sc) { + ret_val = -ENOMEM ; + goto out; + } + + yaffs_trace(YAFFS_TRACE_OS,
fs/yaffs2/yaffs_vfs.c line 806
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ "yaffs_readdir: starting at %d", (int)offset); + +if (offset ==0 ) { +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_readdir: entry . ino %d" , + (int )inode->i_ino); +yaffs_gross_unlock (dev); +if (filldir (dirent,"." ,1 , offset, inode->i_ino,DT_DIR ) <0 ) { +yaffs_gross_lock (dev); + goto out;
This is a bit ugly. Probably cleaner to have separate exit labels for the case where you don't need the unlock.
What is gross lock actually protecting here? Can it be more fine grained?
Quoted 136 lines
fs/yaffs2/yaffs_vfs.c new file +136
-0+ } +yaffs_gross_lock (dev); + offset++; + f->f_pos++; + } +if (offset ==1 ) { +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_readdir: entry .. ino %d" , + (int )f->f_dentry->d_parent->d_inode->i_ino); +yaffs_gross_unlock (dev); +if (filldir (dirent,".." ,2 , offset, + f->f_dentry->d_parent->d_inode->i_ino, +DT_DIR ) <0 ) { +yaffs_gross_lock (dev); + goto out; + } +yaffs_gross_lock (dev); + offset++; + f->f_pos++; + } + + curoffs =1 ; + +/* If the directory has changed since the open or last call to +readdir, rewind to after the 2 canned entries. */ +if (f->f_version != inode->i_version) { + offset =2 ; + f->f_pos = offset; + f->f_version = inode->i_version; + } + +while (sc->next_return) { + curoffs++; + l = sc->next_return; +if (curoffs >= offset) { +int this_inode =yaffs_get_obj_inode (l); +int this_type =yaffs_get_obj_type (l); + +yaffs_get_obj_name (l, name,YAFFS_MAX_NAME_LENGTH +1 ); +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_readdir: %s inode %d" , + name,yaffs_get_obj_inode (l)); + +yaffs_gross_unlock (dev); + +if (filldir (dirent, + name, +strlen (name), + offset, this_inode, this_type) <0 ) { +yaffs_gross_lock (dev); + goto out; + } + +yaffs_gross_lock (dev); + + offset++; + f->f_pos++; + } +yaffs_search_advance (sc); + } + +out: +yaffs_search_end (sc); +yaffs_dev_to_lc (dev)->readdir_process =NULL ; +yaffs_gross_unlock (dev); + +return ret_val; +} + +static const struct file_operations yaffs_dir_operations = { + .read = generic_read_dir, + .readdir = yaffs_readdir, + .fsync = yaffs_sync_object, + .llseek = generic_file_llseek, +}; + + + +static int yaffs_file_flush (struct file *file,fl_owner_t id) +{ +struct yaffs_obj *obj =yaffs_dentry_to_obj (file->f_dentry); +struct yaffs_dev *dev = obj->my_dev; + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_file_flush object %d (%s)" , + obj->obj_id, obj->dirty ?"dirty" :"clean" ); + +yaffs_gross_lock (dev); + +yaffs_flush_file (obj,1 ,0 ); + +yaffs_gross_unlock (dev); + +return 0 ; +} + +static const struct file_operations yaffs_file_operations = { + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, + .mmap = generic_file_mmap, + .flush = yaffs_file_flush, + .fsync = yaffs_sync_object, + .splice_read = generic_file_splice_read, + .splice_write = generic_file_splice_write, + .llseek = generic_file_llseek, +}; + + +/* ExportFS support */ +static struct inode *yaffs2_nfs_get_inode (struct super_block *sb,uint64_t ino, +uint32_t generation) +{ +return yaffs_iget (sb, ino); +} + +static struct dentry *yaffs2_fh_to_dentry (struct super_block *sb, +struct fid *fid,int fh_len, +int fh_type) +{ +return generic_fh_to_dentry (sb, fid, fh_len, fh_type, + yaffs2_nfs_get_inode); +} + +static struct dentry *yaffs2_fh_to_parent (struct super_block *sb, +struct fid *fid,int fh_len, +int fh_type) +{ +return generic_fh_to_parent (sb, fid, fh_len, fh_type, + yaffs2_nfs_get_inode); +} + +struct dentry *yaffs2_get_parent (struct dentry *dentry) +{ +
fs/yaffs2/yaffs_vfs.c line 952
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+struct super_block *sb = dentry->d_inode->i_sb; +struct dentry *parent =ERR_PTR (-ENOENT ); +struct inode *inode; +unsigned long parent_ino; +struct yaffs_obj *d_obj; +struct yaffs_obj *parent_obj; + + d_obj =yaffs_inode_to_obj (dentry->d_inode); + +if (d_obj) {
if (!d_obj)
return ERR_PTR(-ENOENT);
You can use goto fail; if you want single return point.
fs/yaffs2/yaffs_vfs.c line 959
Quoted 7 lines
fs/yaffs2/yaffs_vfs.c new file +7
-0+ parent_obj = d_obj->parent; +if (parent_obj) { + parent_ino =yaffs_get_obj_inode (parent_obj); + inode =yaffs_iget (sb, parent_ino); + +if (IS_ERR (inode)) { + parent =ERR_CAST (inode);
Return/goto directly from here. Makes the normal path easier to follow.
Quoted 27 lines
fs/yaffs2/yaffs_vfs.c new file +27
-0+ }else { + parent =d_obtain_alias (inode); +if (!IS_ERR (parent)) { + parent =ERR_PTR (-ENOMEM ); +iput (inode); + } + } + } + } +return parent; +} + +/* Just declare a zero structure as a NULL value implies +* using the default functions of exportfs. +*/ + +static struct export_operations yaffs_export_ops = { + .fh_to_dentry = yaffs2_fh_to_dentry, + .fh_to_parent = yaffs2_fh_to_parent, + .get_parent = yaffs2_get_parent, +}; + + +/*-----------------------------------------------------------------*/ + +static int yaffs_readlink (struct dentry *dentry,char __user * buffer, +int buflen)
fs/yaffs2/yaffs_vfs.c line 996
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+{ +unsigned char *alias; +int ret; +struct yaffs_dev *dev =yaffs_dentry_to_obj (dentry)->my_dev; + +yaffs_gross_lock (dev); + + alias =yaffs_get_symlink_alias (yaffs_dentry_to_obj (dentry)); + +yaffs_gross_unlock (dev);
What does gross lock protect here? Is it safe to use/free alias outside of the lock below?
Quoted 17 lines
fs/yaffs2/yaffs_vfs.c new file +17
-0+ +if (!alias) +return -ENOMEM ; + + ret =vfs_readlink (dentry, buffer, buflen, alias); +kfree (alias); +return ret; +} + +static void *yaffs_follow_link (struct dentry *dentry,struct nameidata *nd) +{ +unsigned char *alias; +void *ret; +struct yaffs_dev *dev =yaffs_dentry_to_obj (dentry)->my_dev; + +yaffs_gross_lock (dev); +
fs/yaffs2/yaffs_vfs.c line 1023
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ alias =yaffs_get_symlink_alias (yaffs_dentry_to_obj (dentry)); +yaffs_gross_unlock (dev); + +if (!alias) { + ret =ERR_PTR (-ENOMEM ); + goto out; + } + +nd_set_link (nd, alias); + ret = (void *)alias;
Shoudn't need the cast.
Quoted 84 lines
fs/yaffs2/yaffs_vfs.c new file +84
-0+out: +return ret; +} + +void yaffs_put_link (struct dentry *dentry,struct nameidata *nd,void *alias) +{ +kfree (alias); +} + + +static void yaffs_unstitch_obj (struct inode *inode,struct yaffs_obj *obj) +{ +/* Clear the association between the inode and +* the struct yaffs_obj. +*/ + obj->my_inode =NULL ; +yaffs_inode_to_obj_lv (inode) =NULL ; + +/* If the object freeing was deferred, then the real +* free happens now. +* This should fix the inode inconsistency problem. +*/ +yaffs_handle_defered_free (obj); +} + +/* yaffs_evict_inode combines into one operation what was previously done in +* yaffs_clear_inode() and yaffs_delete_inode() +* +*/ +static void yaffs_evict_inode (struct inode *inode) +{ +struct yaffs_obj *obj; +struct yaffs_dev *dev; +int deleteme =0 ; + + obj =yaffs_inode_to_obj (inode); + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_evict_inode: ino %d, count %d %s" , + (int )inode->i_ino, +atomic_read (&inode->i_count), + obj ?"object exists" :"null object" ); + +if (!inode->i_nlink && !is_bad_inode (inode)) + deleteme =1 ; +truncate_inode_pages (&inode->i_data,0 ); +end_writeback (inode); + +if (deleteme && obj) { + dev = obj->my_dev; +yaffs_gross_lock (dev); +yaffs_del_obj (obj); +yaffs_gross_unlock (dev); + } +if (obj) { + dev = obj->my_dev; +yaffs_gross_lock (dev); +yaffs_unstitch_obj (inode, obj); +yaffs_gross_unlock (dev); + } + +} + +static void yaffs_touch_super (struct yaffs_dev *dev) +{ +struct super_block *sb =yaffs_dev_to_lc (dev)->super; + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_touch_super() sb = %p" , sb); +if (sb) + sb->s_dirt =1 ; +} + +static int yaffs_readpage_nolock (struct file *f,struct page *pg) +{ +/* Lifted from jffs2 */ + +struct yaffs_obj *obj; +unsigned char *pg_buf; +int ret; +struct yaffs_dev *dev; + + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_readpage_nolock at %08x, size %08x", + (unsigned)(pg->index << PAGE_CACHE_SHIFT),
fs/yaffs2/yaffs_vfs.c line 1117
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ (unsigned)PAGE_CACHE_SIZE); + + obj =yaffs_dentry_to_obj (f->f_dentry); + + dev = obj->my_dev; + +BUG_ON (!PageLocked (pg)); + + pg_buf =kmap (pg); +/* FIXME: Can kmap fail? */
A warning at least?
Quoted 84 lines
fs/yaffs2/yaffs_vfs.c new file +84
-0+ +yaffs_gross_lock (dev); + + ret =yaffs_file_rd (obj, pg_buf, + pg->index <<PAGE_CACHE_SHIFT ,PAGE_CACHE_SIZE ); + +yaffs_gross_unlock (dev); + +if (ret >=0 ) + ret =0 ; + +if (ret) { +ClearPageUptodate (pg); +SetPageError (pg); + }else { +SetPageUptodate (pg); +ClearPageError (pg); + } + +flush_dcache_page (pg); +kunmap (pg); + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_readpage_nolock done" ); +return ret; +} + +static int yaffs_readpage_unlock (struct file *f,struct page *pg) +{ +int ret =yaffs_readpage_nolock (f, pg); + +unlock_page (pg); +return ret; +} + +static int yaffs_readpage (struct file *f,struct page *pg) +{ +int ret; + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_readpage" ); + ret =yaffs_readpage_unlock (f, pg); +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_readpage done" ); +return ret; +} + +/* writepage inspired by/stolen from smbfs */ + +static int yaffs_writepage (struct page *page,struct writeback_control *wbc) +{ +struct yaffs_dev *dev; +struct address_space *mapping = page->mapping; +struct inode *inode; +unsigned long end_index; +char *buffer; +struct yaffs_obj *obj; +int n_written =0 ; +unsigned n_bytes; +loff_t i_size; + +if (!mapping) +BUG (); + inode = mapping->host; +if (!inode) +BUG (); + i_size =i_size_read (inode); + + end_index = i_size >>PAGE_CACHE_SHIFT ; + +if (page->index < end_index) + n_bytes =PAGE_CACHE_SIZE ; +else { + n_bytes = i_size & (PAGE_CACHE_SIZE -1 ); + +if (page->index > end_index || !n_bytes) { +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_writepage at %08x, inode size = %08x!!!" , + (unsigned )(page->index <<PAGE_CACHE_SHIFT ), + (unsigned )inode->i_size); +yaffs_trace (YAFFS_TRACE_OS , +" -> don't care!!" ); + +zero_user_segment (page,0 ,PAGE_CACHE_SIZE ); +set_page_writeback (page); +unlock_page (page); +end_page_writeback (page);
fs/yaffs2/yaffs_vfs.c line 1211
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+return 0 ; + } + } + +if (n_bytes !=PAGE_CACHE_SIZE ) +zero_user_segment (page, n_bytes,PAGE_CACHE_SIZE ); + +get_page (page); + + buffer =kmap (page);
if (!buffer)?
Quoted 60 lines
fs/yaffs2/yaffs_vfs.c new file +60
-0+ + obj =yaffs_inode_to_obj (inode); + dev = obj->my_dev; +yaffs_gross_lock (dev); + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_writepage at %08x, size %08x" , + (unsigned )(page->index <<PAGE_CACHE_SHIFT ), n_bytes); +yaffs_trace (YAFFS_TRACE_OS , +"writepag0: obj = %05x, ino = %05x" , + (int )obj->variant.file_variant.file_size, (int )inode->i_size); + + n_written =yaffs_wr_file (obj, buffer, + page->index <<PAGE_CACHE_SHIFT , n_bytes,0 ); + +yaffs_touch_super (dev); + +yaffs_trace (YAFFS_TRACE_OS , +"writepag1: obj = %05x, ino = %05x" , + (int )obj->variant.file_variant.file_size, (int )inode->i_size); + +yaffs_gross_unlock (dev); + +kunmap (page); +set_page_writeback (page); +unlock_page (page); +end_page_writeback (page); +put_page (page); + +return (n_written == n_bytes) ?0 : -ENOSPC ; +} + +/* Space holding and freeing is done to ensure we have space available for +* write_begin/end. +* For now we just assume few parallel writes and check against a small +* number. +* Todo: need to do this with a counter to handle parallel reads better +*/ + +static ssize_t yaffs_hold_space (struct file *f) +{ +struct yaffs_obj *obj; +struct yaffs_dev *dev; +int n_free_chunks; + + obj =yaffs_dentry_to_obj (f->f_dentry); + + dev = obj->my_dev; + +yaffs_gross_lock (dev); + + n_free_chunks =yaffs_get_n_free_chunks (dev); + +yaffs_gross_unlock (dev); + +return (n_free_chunks >20 ) ?1 :0 ; +} + +static void yaffs_release_space (struct file *f) +{
fs/yaffs2/yaffs_vfs.c line 1281
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+struct yaffs_obj *obj; +struct yaffs_dev *dev; + + obj =yaffs_dentry_to_obj (f->f_dentry); + + dev = obj->my_dev; + +yaffs_gross_lock (dev); + +yaffs_gross_unlock (dev);
What does this lock/unlock do?
Quoted 152 lines
fs/yaffs2/yaffs_vfs.c new file +152
-0+} + +static int yaffs_write_begin (struct file *filp,struct address_space *mapping, +loff_t pos,unsigned len,unsigned flags, +struct page **pagep,void **fsdata) +{ +struct page *pg =NULL ; +pgoff_t index = pos >>PAGE_CACHE_SHIFT ; +int ret =0 ; +int space_held =0 ; + +/* Get a page */ + pg =grab_cache_page_write_begin (mapping, index, flags); + + *pagep = pg; +if (!pg) { + ret = -ENOMEM ; + goto out; + } +yaffs_trace (YAFFS_TRACE_OS , +"start yaffs_write_begin index %d(%x) uptodate %d" , + (int )index, (int )index,PageUptodate (pg) ?1 :0 ); + +/* Get fs space */ + space_held =yaffs_hold_space (filp); + +if (!space_held) { + ret = -ENOSPC ; + goto out; + } + +/* Update page if required */ + +if (!PageUptodate (pg)) + ret =yaffs_readpage_nolock (filp, pg); + +if (ret) + goto out; + +/* Happy path return */ +yaffs_trace (YAFFS_TRACE_OS ,"end yaffs_write_begin - ok" ); + +return 0 ; + +out: +yaffs_trace (YAFFS_TRACE_OS , +"end yaffs_write_begin fail returning %d" , ret); +if (space_held) +yaffs_release_space (filp); +if (pg) { +unlock_page (pg); +page_cache_release (pg); + } +return ret; +} + +static ssize_t yaffs_file_write (struct file *f,const char *buf,size_t n, +loff_t *pos) +{ +struct yaffs_obj *obj; +int n_written, ipos; +struct inode *inode; +struct yaffs_dev *dev; + + obj =yaffs_dentry_to_obj (f->f_dentry); + +if (!obj) { +/* This should not happen */ +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_file_write: hey obj is null!" ); +return -EINVAL ; + } + + dev = obj->my_dev; + +yaffs_gross_lock (dev); + + inode = f->f_dentry->d_inode; + +if (!S_ISBLK (inode->i_mode) && f->f_flags &O_APPEND ) + ipos = inode->i_size; +else + ipos = *pos; + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_file_write about to write writing %u(%x) bytes to object %d at %d(%x)" , + (unsigned )n, (unsigned )n, obj->obj_id, ipos, ipos); + + n_written =yaffs_wr_file (obj, buf, ipos, n,0 ); + +yaffs_touch_super (dev); + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_file_write: %d(%x) bytes written" , + (unsigned )n, (unsigned )n); + +if (n_written >0 ) { + ipos += n_written; + *pos = ipos; +if (ipos > inode->i_size) { + inode->i_size = ipos; + inode->i_blocks = (ipos +511 ) >>9 ; + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_file_write size updated to %d bytes, %d blocks" , + ipos, (int )(inode->i_blocks)); + } + } +yaffs_gross_unlock (dev); +return (n_written ==0 ) && (n >0 ) ? -ENOSPC : n_written; +} + +static int yaffs_write_end (struct file *filp,struct address_space *mapping, +loff_t pos,unsigned len,unsigned copied, +struct page *pg,void *fsdadata) +{ +int ret =0 ; +void *addr, *kva; +uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE -1 ); + + kva =kmap (pg); + addr = kva + offset_into_page; + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_write_end addr %p pos %x n_bytes %d" , + addr, (unsigned )pos, copied); + + ret =yaffs_file_write (filp, addr, copied, &pos); + +if (ret != copied) { +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_write_end not same size ret %d copied %d" , + ret, copied); +SetPageError (pg); + } + +kunmap (pg); + +yaffs_release_space (filp); +unlock_page (pg); +page_cache_release (pg); +return ret; +} + +static int yaffs_statfs (struct dentry *dentry,struct kstatfs *buf) +{ +struct yaffs_dev *dev =yaffs_dentry_to_obj (dentry)->my_dev; +struct super_block *sb = dentry->d_sb; + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_statfs" ); + +yaffs_gross_lock (dev);
fs/yaffs2/yaffs_vfs.c line 1443
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ + buf->f_type =YAFFS_MAGIC ; + buf->f_bsize = sb->s_blocksize; + buf->f_namelen =255 ; + +if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk -1 )) { +/* Do this if chunk size is not a power of 2 */ + +uint64_t bytes_in_dev; +uint64_t bytes_free;
u64?
Quoted 174 lines
fs/yaffs2/yaffs_vfs.c new file +174
-0+ + bytes_in_dev = + ((uint64_t ) + ((dev->param.end_block - dev->param.start_block + +1 ))) * ((uint64_t ) (dev->param.chunks_per_block * + dev->data_bytes_per_chunk)); + +do_div (bytes_in_dev, sb->s_blocksize); +/* bytes_in_dev becomes the number of blocks */ + buf->f_blocks = bytes_in_dev; + + bytes_free = ((uint64_t ) (yaffs_get_n_free_chunks (dev))) * + ((uint64_t ) (dev->data_bytes_per_chunk)); + +do_div (bytes_free, sb->s_blocksize); + + buf->f_bfree = bytes_free; + + }else if (sb->s_blocksize > dev->data_bytes_per_chunk) { + + buf->f_blocks = + (dev->param.end_block - dev->param.start_block +1 ) * + dev->param.chunks_per_block / + (sb->s_blocksize / dev->data_bytes_per_chunk); + buf->f_bfree = +yaffs_get_n_free_chunks (dev) / + (sb->s_blocksize / dev->data_bytes_per_chunk); + }else { + buf->f_blocks = + (dev->param.end_block - dev->param.start_block +1 ) * + dev->param.chunks_per_block * + (dev->data_bytes_per_chunk / sb->s_blocksize); + + buf->f_bfree = +yaffs_get_n_free_chunks (dev) * + (dev->data_bytes_per_chunk / sb->s_blocksize); + } + + buf->f_files =0 ; + buf->f_ffree =0 ; + buf->f_bavail = buf->f_bfree; + +yaffs_gross_unlock (dev); +return 0 ; +} + +static void yaffs_flush_inodes (struct super_block *sb) +{ +struct inode *iptr; +struct yaffs_obj *obj; + +list_for_each_entry (iptr, &sb->s_inodes, i_sb_list) { + obj =yaffs_inode_to_obj (iptr); +if (obj) { +yaffs_trace (YAFFS_TRACE_OS , +"flushing obj %d" , obj->obj_id); +yaffs_flush_file (obj,1 ,0 ); + } + } +} + +static void yaffs_flush_super (struct super_block *sb,int do_checkpoint) +{ +struct yaffs_dev *dev =yaffs_super_to_dev (sb); + +if (!dev) +return ; + +yaffs_flush_inodes (sb); +yaffs_update_dirty_dirs (dev); +yaffs_flush_whole_cache (dev); +if (do_checkpoint) +yaffs_checkpoint_save (dev); +} + +static unsigned yaffs_bg_gc_urgency (struct yaffs_dev *dev) +{ +unsigned erased_chunks = + dev->n_erased_blocks * dev->param.chunks_per_block; +struct yaffs_linux_context *context =yaffs_dev_to_lc (dev); +unsigned scattered =0 ;/* Free chunks not in an erased block */ + +if (erased_chunks < dev->n_free_chunks) + scattered = (dev->n_free_chunks - erased_chunks); + +if (!context->bg_running) +return 0 ; +else if (scattered < (dev->param.chunks_per_block *2 )) +return 0 ; +else if (erased_chunks > dev->n_free_chunks /2 ) +return 0 ; +else if (erased_chunks > dev->n_free_chunks /4 ) +return 1 ; +else +return 2 ; +} + +static int yaffs_do_sync_fs (struct super_block *sb,int request_checkpoint) +{ + +struct yaffs_dev *dev =yaffs_super_to_dev (sb); +unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint &4 ); +unsigned gc_urgent =yaffs_bg_gc_urgency (dev); +int do_checkpoint; + +yaffs_trace (YAFFS_TRACE_OS |YAFFS_TRACE_SYNC |YAFFS_TRACE_BACKGROUND , +"yaffs_do_sync_fs: gc-urgency %d %s %s%s" , + gc_urgent, + sb->s_dirt ?"dirty" :"clean" , + request_checkpoint ?"checkpoint requested" :"no checkpoint" , + oneshot_checkpoint ?" one-shot" :"" ); + +yaffs_gross_lock (dev); + do_checkpoint = ((request_checkpoint && !gc_urgent) || + oneshot_checkpoint) && !dev->is_checkpointed; + +if (sb->s_dirt || do_checkpoint) { +yaffs_flush_super (sb, !dev->is_checkpointed && do_checkpoint); + sb->s_dirt =0 ; +if (oneshot_checkpoint) + yaffs_auto_checkpoint &= ~4 ; + } +yaffs_gross_unlock (dev); + +return 0 ; +} + +/* +* yaffs background thread functions . +* yaffs_bg_thread_fn() the thread function +* yaffs_bg_start() launches the background thread. +* yaffs_bg_stop() cleans up the background thread. +* +* NB: +* The thread should only run after the yaffs is initialised +* The thread should be stopped before yaffs is unmounted. +* The thread should not do any writing while the fs is in read only. +*/ + +void yaffs_background_waker (unsigned long data) +{ +wake_up_process ((struct task_struct *)data); +} + +static int yaffs_bg_thread_fn (void *data) +{ +struct yaffs_dev *dev = (struct yaffs_dev *)data; +struct yaffs_linux_context *context =yaffs_dev_to_lc (dev); +unsigned long now = jiffies; +unsigned long next_dir_update = now; +unsigned long next_gc = now; +unsigned long expires; +unsigned int urgency; +int gc_result; +struct timer_list timer; + +yaffs_trace (YAFFS_TRACE_BACKGROUND , +"yaffs_background starting for dev %p" , (void *)dev); + +set_freezable (); +while (context->bg_running) { +yaffs_trace (YAFFS_TRACE_BACKGROUND ,"yaffs_background" ); + +if (kthread_should_stop ()) +break ; + +if (try_to_freeze ()) +continue ; + +yaffs_gross_lock (dev); + + now = jiffies; + +if (time_after (now, next_dir_update) && yaffs_bg_enable) {
fs/yaffs2/yaffs_vfs.c line 1627
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+yaffs_update_dirty_dirs (dev); + next_dir_update = now +HZ ; + } + +if (time_after (now, next_gc) && yaffs_bg_enable) { +if (!dev->is_checkpointed) { + urgency =yaffs_bg_gc_urgency (dev); + gc_result =yaffs_bg_gc (dev, urgency); +if (urgency >1 ) + next_gc = now +HZ /20 +1 ;
The msecs_to_jiffies macro could make the times here clearer.
Quoted 30 lines
fs/yaffs2/yaffs_vfs.c new file +30
-0+else if (urgency >0 ) + next_gc = now +HZ /10 +1 ; +else + next_gc = now +HZ *2 ; + }else { +/* +* gc not running so set to next_dir_update +* to cut down on wake ups +*/ + next_gc = next_dir_update; + } + } +yaffs_gross_unlock (dev); + expires = next_dir_update; +if (time_before (next_gc, expires)) + expires = next_gc; +if (time_before (expires, now)) + expires = now +HZ ; + +init_timer_on_stack (&timer); + timer.expires = expires +1 ; + timer.data = (unsigned long )current; + timer.function = yaffs_background_waker; + +set_current_state (TASK_INTERRUPTIBLE ); +add_timer (&timer); +schedule (); +del_timer_sync (&timer); + } +
fs/yaffs2/yaffs_vfs.c line 1667
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+return 0 ; +} + +static int yaffs_bg_start (struct yaffs_dev *dev) +{ +int retval =0 ; +struct yaffs_linux_context *context =yaffs_dev_to_lc (dev); + +if (dev->read_only) +return -1 ;
Proper errno value.
Quoted 43 lines
fs/yaffs2/yaffs_vfs.c new file +43
-0+ + context->bg_running =1 ; + + context->bg_thread =kthread_run (yaffs_bg_thread_fn, + (void *)dev,"yaffs-bg-%d" , + context->mount_id); + +if (IS_ERR (context->bg_thread)) { + retval =PTR_ERR (context->bg_thread); + context->bg_thread =NULL ; + context->bg_running =0 ; + } +return retval; +} + +static void yaffs_bg_stop (struct yaffs_dev *dev) +{ +struct yaffs_linux_context *ctxt =yaffs_dev_to_lc (dev); + + ctxt->bg_running =0 ; + +if (ctxt->bg_thread) { +kthread_stop (ctxt->bg_thread); + ctxt->bg_thread =NULL ; + } +} + +static void yaffs_write_super (struct super_block *sb) +{ +unsigned request_checkpoint = (yaffs_auto_checkpoint >=2 ); + +yaffs_trace (YAFFS_TRACE_OS |YAFFS_TRACE_SYNC |YAFFS_TRACE_BACKGROUND , +"yaffs_write_super%s" , + request_checkpoint ?" checkpt" :"" ); + +yaffs_do_sync_fs (sb, request_checkpoint); + +} + +static int yaffs_sync_fs (struct super_block *sb,int wait) +{ +unsigned request_checkpoint = (yaffs_auto_checkpoint >=1 ); +
fs/yaffs2/yaffs_vfs.c line 1720
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+yaffs_trace (YAFFS_TRACE_OS |YAFFS_TRACE_SYNC , +"yaffs_sync_fs%s" , request_checkpoint ?" checkpt" :"" ); + +yaffs_do_sync_fs (sb, request_checkpoint); + +return 0 ; +} + +static LIST_HEAD (yaffs_context_list); +struct mutex yaffs_context_lock;
Should be static?
fs/yaffs2/yaffs_vfs.c line 1733
Quoted 12 lines
fs/yaffs2/yaffs_vfs.c new file +12
-0+struct yaffs_options { +int inband_tags; +int skip_checkpoint_read; +int skip_checkpoint_write; +int no_cache; +int tags_ecc_on; +int tags_ecc_overridden; +int lazy_loading_enabled; +int lazy_loading_overridden; +int empty_lost_and_found; +int empty_lost_and_found_overridden; +};
Also should be static?
Quoted 48 lines
fs/yaffs2/yaffs_vfs.c new file +48
-0+ +#define MAX_OPT_LEN 30 +static int yaffs_parse_options (struct yaffs_options *options, +const char *options_str) +{ +char cur_opt[MAX_OPT_LEN +1 ]; +int p; +int error =0 ; + +/* Parse through the options which is a comma seperated list */ + +while (options_str && *options_str && !error) { +memset (cur_opt,0 ,MAX_OPT_LEN +1 ); + p =0 ; + +while (*options_str ==',' ) + options_str++; + +while (*options_str && *options_str !=',' ) { +if (p <MAX_OPT_LEN ) { + cur_opt[p] = *options_str; + p++; + } + options_str++; + } + +if (!strcmp (cur_opt,"inband-tags" )) { + options->inband_tags =1 ; + }else if (!strcmp (cur_opt,"tags-ecc-off" )) { + options->tags_ecc_on =0 ; + options->tags_ecc_overridden =1 ; + }else if (!strcmp (cur_opt,"tags-ecc-on" )) { + options->tags_ecc_on =1 ; + options->tags_ecc_overridden =1 ; + }else if (!strcmp (cur_opt,"lazy-loading-off" )) { + options->lazy_loading_enabled =0 ; + options->lazy_loading_overridden =1 ; + }else if (!strcmp (cur_opt,"lazy-loading-on" )) { + options->lazy_loading_enabled =1 ; + options->lazy_loading_overridden =1 ; + }else if (!strcmp (cur_opt,"empty-lost-and-found-off" )) { + options->empty_lost_and_found =0 ; + options->empty_lost_and_found_overridden =1 ; + }else if (!strcmp (cur_opt,"empty-lost-and-found-on" )) { + options->empty_lost_and_found =1 ; + options->empty_lost_and_found_overridden =1 ; + }else if (!strcmp (cur_opt,"no-cache" )) { + options->no_cache =1 ;
fs/yaffs2/yaffs_vfs.c line 1791
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ }else if (!strcmp (cur_opt,"no-checkpoint-read" )) { + options->skip_checkpoint_read =1 ; + }else if (!strcmp (cur_opt,"no-checkpoint-write" )) { + options->skip_checkpoint_write =1 ; + }else if (!strcmp (cur_opt,"no-checkpoint" )) { + options->skip_checkpoint_read =1 ; + options->skip_checkpoint_write =1 ; + }else { +printk (KERN_INFO "yaffs: Bad mount option \"%s\"\n" , + cur_opt);
Probably should be KERN_ERR or KERN_WARN
Quoted 75 lines
fs/yaffs2/yaffs_vfs.c new file +75
-0+ error =1 ; + } + } +return error; +} + +static const struct address_space_operations yaffs_file_address_operations = { + .readpage = yaffs_readpage, + .writepage = yaffs_writepage, + .write_begin = yaffs_write_begin, + .write_end = yaffs_write_end, +}; + + + +static const struct inode_operations yaffs_file_inode_operations = { + .setattr = yaffs_setattr, +#ifdef CONFIG_YAFFS_XATTR + .setxattr = yaffs_setxattr, + .getxattr = yaffs_getxattr, + .listxattr = yaffs_listxattr, + .removexattr = yaffs_removexattr, +#endif +}; + +static const struct inode_operations yaffs_symlink_inode_operations = { + .readlink = yaffs_readlink, + .follow_link = yaffs_follow_link, + .put_link = yaffs_put_link, + .setattr = yaffs_setattr, +#ifdef CONFIG_YAFFS_XATTR + .setxattr = yaffs_setxattr, + .getxattr = yaffs_getxattr, + .listxattr = yaffs_listxattr, + .removexattr = yaffs_removexattr, +#endif +}; + +static void yaffs_fill_inode_from_obj (struct inode *inode, +struct yaffs_obj *obj) +{ +if (inode && obj) { +/* Check mode against the variant type +* and attempt to repair if broken. */ +u32 mode = obj->yst_mode; +switch (obj->variant_type) { +case YAFFS_OBJECT_TYPE_FILE : +if (!S_ISREG (mode)) { + obj->yst_mode &= ~S_IFMT ; + obj->yst_mode |=S_IFREG ; + } + +break ; +case YAFFS_OBJECT_TYPE_SYMLINK : +if (!S_ISLNK (mode)) { + obj->yst_mode &= ~S_IFMT ; + obj->yst_mode |=S_IFLNK ; + } + +break ; +case YAFFS_OBJECT_TYPE_DIRECTORY : +if (!S_ISDIR (mode)) { + obj->yst_mode &= ~S_IFMT ; + obj->yst_mode |=S_IFDIR ; + } + +break ; +case YAFFS_OBJECT_TYPE_UNKNOWN : +case YAFFS_OBJECT_TYPE_HARDLINK : +case YAFFS_OBJECT_TYPE_SPECIAL : +default : +/* TODO? */ +break ; + } +
fs/yaffs2/yaffs_vfs.c line 1876
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ inode->i_flags |=S_NOATIME ; + + inode->i_ino = obj->obj_id; + inode->i_mode = obj->yst_mode; + inode->i_uid = obj->yst_uid; + inode->i_gid = obj->yst_gid; + + inode->i_rdev =old_decode_dev (obj->yst_rdev); + + inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
Why are yst_[amt]time not already time_t?
Quoted 84 lines
fs/yaffs2/yaffs_vfs.c new file +84
-0+ inode->i_atime.tv_nsec =0 ; + inode->i_mtime.tv_sec = (time_t ) obj->yst_mtime; + inode->i_mtime.tv_nsec =0 ; + inode->i_ctime.tv_sec = (time_t ) obj->yst_ctime; + inode->i_ctime.tv_nsec =0 ; + inode->i_size =yaffs_get_obj_length (obj); + inode->i_blocks = (inode->i_size +511 ) >>9 ; + + inode->i_nlink =yaffs_get_obj_link_count (obj); + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_fill_inode mode %x uid %d gid %d size %d count %d" , + inode->i_mode, inode->i_uid, inode->i_gid, + (int )inode->i_size,atomic_read (&inode->i_count)); + +switch (obj->yst_mode &S_IFMT ) { +default :/* fifo, device or socket */ +init_special_inode (inode, obj->yst_mode, +old_decode_dev (obj->yst_rdev)); +break ; +case S_IFREG :/* file */ + inode->i_op = &yaffs_file_inode_operations; + inode->i_fop = &yaffs_file_operations; + inode->i_mapping->a_ops = + &yaffs_file_address_operations; +break ; +case S_IFDIR :/* directory */ + inode->i_op = &yaffs_dir_inode_operations; + inode->i_fop = &yaffs_dir_operations; +break ; +case S_IFLNK :/* symlink */ + inode->i_op = &yaffs_symlink_inode_operations; +break ; + } + +yaffs_inode_to_obj_lv (inode) = obj; + obj->my_inode = inode; + + }else { +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_fill_inode invalid parameters" ); + } +} + +static void yaffs_put_super (struct super_block *sb) +{ +struct yaffs_dev *dev =yaffs_super_to_dev (sb); + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_put_super" ); + +yaffs_trace (YAFFS_TRACE_OS |YAFFS_TRACE_BACKGROUND , +"Shutting down yaffs background thread" ); +yaffs_bg_stop (dev); +yaffs_trace (YAFFS_TRACE_OS |YAFFS_TRACE_BACKGROUND , +"yaffs background thread shut down" ); + +yaffs_gross_lock (dev); + +yaffs_flush_super (sb,1 ); + +if (yaffs_dev_to_lc (dev)->put_super_fn) +yaffs_dev_to_lc (dev)->put_super_fn (sb); + +yaffs_deinitialise (dev); + +yaffs_gross_unlock (dev); +mutex_lock (&yaffs_context_lock); +list_del_init (&(yaffs_dev_to_lc (dev)->context_list)); +mutex_unlock (&yaffs_context_lock); + +if (yaffs_dev_to_lc (dev)->spare_buffer) { +kfree (yaffs_dev_to_lc (dev)->spare_buffer); +yaffs_dev_to_lc (dev)->spare_buffer =NULL ; + } + +kfree (dev); +} + +static void yaffs_mtd_put_super (struct super_block *sb) +{ +struct mtd_info *mtd =yaffs_dev_to_mtd (yaffs_super_to_dev (sb)); + +if (mtd->sync) + mtd->sync (mtd);
fs/yaffs2/yaffs_vfs.c line 1970
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ +put_mtd_device (mtd); +} + +static const struct super_operations yaffs_super_ops = { + .statfs = yaffs_statfs, + .put_super = yaffs_put_super, + .evict_inode = yaffs_evict_inode, + .sync_fs = yaffs_sync_fs, + .write_super = yaffs_write_super,
Nitpick: tab-delimt struct initialisers to make them more readable.
Quoted 4 lines
fs/yaffs2/yaffs_vfs.c new file +4
-0+}; + +static struct super_block *yaffs_internal_read_super(int yaffs_version, + struct super_block *sb,
fs/yaffs2/yaffs_vfs.c line 1984
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ void *data, int silent) +{ + int n_blocks; +struct inode *inode =NULL ; +struct dentry *root; +struct yaffs_dev *dev =0 ; +char devname_buf[BDEVNAME_SIZE +1 ]; +struct mtd_info *mtd; +int err; +char *data_str = (char *)data;
Shouldn't need the cast.
fs/yaffs2/yaffs_vfs.c line 1995
Quoted 11 lines
fs/yaffs2/yaffs_vfs.c new file +11
-0+struct yaffs_linux_context *context =NULL ; +struct yaffs_param *param; +int read_only =0 ; +struct yaffs_options options; +unsigned mount_id; +int found; +struct yaffs_linux_context *context_iterator; +struct list_head *l; + +if (!sb) { +printk (KERN_INFO "yaffs: sb is NULL\n" );
KERN_ERR/KERN_WARN?
Quoted 68 lines
fs/yaffs2/yaffs_vfs.c new file +68
-0+return NULL ; + } + + sb->s_magic =YAFFS_MAGIC ; + sb->s_op = &yaffs_super_ops; + sb->s_flags |=MS_NOATIME ; + + read_only = ((sb->s_flags &MS_RDONLY ) !=0 ); + + sb->s_export_op = &yaffs_export_ops; + +if (!sb->s_dev) +printk (KERN_INFO "yaffs: sb->s_dev is NULL\n" ); +else if (!yaffs_devname (sb, devname_buf)) +printk (KERN_INFO "yaffs: devname is NULL\n" ); +else +printk (KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n" , + sb->s_dev, +yaffs_devname (sb, devname_buf), read_only ?"ro" :"rw" ); + +if (!data_str) + data_str ="" ; + +printk (KERN_INFO "yaffs: passed flags \"%s\"\n" , data_str); + +memset (&options,0 ,sizeof (options)); + +if (yaffs_parse_options (&options, data_str)) { +/* Option parsing failed */ +return NULL ; + } + + sb->s_blocksize =PAGE_CACHE_SIZE ; + sb->s_blocksize_bits =PAGE_CACHE_SHIFT ; + +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_read_super: Using yaffs%d" , yaffs_version); +yaffs_trace (YAFFS_TRACE_OS , +"yaffs_read_super: block size %d" , (int )(sb->s_blocksize)); + +yaffs_trace (YAFFS_TRACE_ALWAYS , +"Attempting MTD mount of %u.%u,\"%s\"" , +MAJOR (sb->s_dev),MINOR (sb->s_dev), +yaffs_devname (sb, devname_buf)); + +/* Check it's an mtd device..... */ +if (MAJOR (sb->s_dev) !=MTD_BLOCK_MAJOR ) +return NULL ;/* This isn't an mtd device */ + +/* Get the device */ + mtd =get_mtd_device (NULL ,MINOR (sb->s_dev)); +if (!mtd) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"MTD device #%u doesn't appear to exist" , +MINOR (sb->s_dev)); +return NULL ; + } +/* Check it's NAND */ +if (mtd->type !=MTD_NANDFLASH ) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"MTD device is not NAND it's type %d" , + mtd->type); +return NULL ; + } + +yaffs_trace (YAFFS_TRACE_OS ," erase %p" , mtd->erase); +yaffs_trace (YAFFS_TRACE_OS ," read %p" , mtd->read); +yaffs_trace (YAFFS_TRACE_OS ," write %p" , mtd->write);
fs/yaffs2/yaffs_vfs.c line 2073
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+yaffs_trace (YAFFS_TRACE_OS ," readoob %p" , mtd->read_oob); +yaffs_trace (YAFFS_TRACE_OS ," writeoob %p" , mtd->write_oob); +yaffs_trace (YAFFS_TRACE_OS ," block_isbad %p" , mtd->block_isbad); +yaffs_trace (YAFFS_TRACE_OS ," block_markbad %p" , mtd->block_markbad); +yaffs_trace (YAFFS_TRACE_OS ," writesize %d" , mtd->writesize); +yaffs_trace (YAFFS_TRACE_OS ," oobsize %d" , mtd->oobsize); +yaffs_trace (YAFFS_TRACE_OS ," erasesize %d" , mtd->erasesize); +yaffs_trace (YAFFS_TRACE_OS ," size %lld" , mtd->size); + +#ifdef CONFIG_YAFFS_AUTO_YAFFS2
should also depend on CONFIG_YAFFS_YAFFS2 I guess?
Quoted 61 lines
fs/yaffs2/yaffs_vfs.c new file +61
-0+ +if (yaffs_version ==1 && mtd->writesize >=2048 ) { +yaffs_trace (YAFFS_TRACE_ALWAYS ,"auto selecting yaffs2" ); + yaffs_version =2 ; + } + +/* Added NCB 26/5/2006 for completeness */ +if (yaffs_version ==2 && !options.inband_tags && + mtd->writesize ==512 ) { +yaffs_trace (YAFFS_TRACE_ALWAYS ,"auto selecting yaffs1" ); + yaffs_version =1 ; + } +#endif + +if (yaffs_version ==2 ) { +/* Check for version 2 style functions */ +if (!mtd->erase || + !mtd->block_isbad || + !mtd->block_markbad || + !mtd->read || + !mtd->write || !mtd->read_oob || !mtd->write_oob) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"MTD device does not support required functions" ); +return NULL ; + } + +if ((mtd->writesize <YAFFS_MIN_YAFFS2_CHUNK_SIZE || + mtd->oobsize <YAFFS_MIN_YAFFS2_SPARE_SIZE ) && + !options.inband_tags) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"MTD device does not have the right page sizes" ); +return NULL ; + } + }else { +/* Check for V1 style functions */ +if (!mtd->erase || + !mtd->read || + !mtd->write || !mtd->read_oob || !mtd->write_oob) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"MTD device does not support required functions" ); +return NULL ; + } + +if (mtd->writesize <YAFFS_BYTES_PER_CHUNK || + mtd->oobsize !=YAFFS_BYTES_PER_SPARE ) { +yaffs_trace (YAFFS_TRACE_ALWAYS , +"MTD device does not support have the right page sizes" ); +return NULL ; + } + } + +/* OK, so if we got here, we have an MTD that's NAND and looks +* like it has the right capabilities +* Set the struct yaffs_dev up for mtd +*/ + +if (!read_only && !(mtd->flags &MTD_WRITEABLE )) { + read_only =1 ; +printk (KERN_INFO +"yaffs: mtd is read only, setting superblock read only" ); + sb->s_flags |=MS_RDONLY ;
fs/yaffs2/yaffs_vfs.c line 2144
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ } + + dev =kmalloc (sizeof (struct yaffs_dev ),GFP_KERNEL ); + context =kmalloc (sizeof (struct yaffs_linux_context ),GFP_KERNEL ); + +if (!dev || !context) { +kfree (dev); +kfree (context); + dev =NULL ; + context =NULL ;
It looks like you should just bail here. You have an explicit check for !dev below, but if you manage to allocate dev, but not context you will blow up on the memset below. So you just want something like:
if (!dev || !context) {
kfree(dev);
kfree(context);
return NULL;
}Quoted 34 lines
fs/yaffs2/yaffs_vfs.c new file +34
-0+ } + +if (!dev) { +/* Deep shit could not allocate device structure */ +yaffs_trace (YAFFS_TRACE_ALWAYS , +"yaffs_read_super failed trying to allocate yaffs_dev" ); +return NULL ; + } +memset (dev,0 ,sizeof (struct yaffs_dev )); + param = &(dev->param); + +memset (context,0 ,sizeof (struct yaffs_linux_context )); + dev->os_context = context; +INIT_LIST_HEAD (&(context->context_list)); + context->dev = dev; + context->super = sb; + + dev->read_only = read_only; + + sb->s_fs_info = dev; + + dev->driver_context = mtd; + param->name = mtd->name; + +/* Set up the memory size parameters.... */ + + n_blocks = +YCALCBLOCKS (mtd->size, + (YAFFS_CHUNKS_PER_BLOCK *YAFFS_BYTES_PER_CHUNK )); + + param->start_block =0 ; + param->end_block = n_blocks -1 ; + param->chunks_per_block =YAFFS_CHUNKS_PER_BLOCK ; + param->total_bytes_per_chunk =YAFFS_BYTES_PER_CHUNK ;
fs/yaffs2/yaffs_vfs.c line 2188
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ param->n_reserved_blocks =5 ; + param->n_caches = (options.no_cache) ?0 :10 ; + param->inband_tags = options.inband_tags; + +#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD + param->disable_lazy_load =1 ; +#endif +#ifdef CONFIG_YAFFS_XATTR + param->enable_xattr =1 ; +#endif
If these parameters are bool, I think you can somehow do:
param->enable_xattr = CONFIG_YAFFS_XATTR;
Though I still think some of these ifdefs need to be converted to runtime options :-).
Quoted 72 lines
fs/yaffs2/yaffs_vfs.c new file +72
-0+if (options.lazy_loading_overridden) + param->disable_lazy_load = !options.lazy_loading_enabled; + +#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC + param->no_tags_ecc =1 ; +#endif + +#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND +#else + param->defered_dir_update =1 ; +#endif + +if (options.tags_ecc_overridden) + param->no_tags_ecc = !options.tags_ecc_on; + +#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND + param->empty_lost_n_found =1 ; +#endif + +#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING + param->refresh_period =0 ; +#else + param->refresh_period =500 ; +#endif + +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED + param->always_check_erased =1 ; +#endif + +if (options.empty_lost_and_found_overridden) + param->empty_lost_n_found = options.empty_lost_and_found; + +/* ... and the functions. */ +if (yaffs_version ==2 ) { + param->write_chunk_tags_fn = nandmtd2_write_chunk_tags; + param->read_chunk_tags_fn = nandmtd2_read_chunk_tags; + param->bad_block_fn = nandmtd2_mark_block_bad; + param->query_block_fn = nandmtd2_query_block; +yaffs_dev_to_lc (dev)->spare_buffer = +kmalloc (mtd->oobsize,GFP_NOFS ); + param->is_yaffs2 =1 ; + param->total_bytes_per_chunk = mtd->writesize; + param->chunks_per_block = mtd->erasesize / mtd->writesize; + n_blocks =YCALCBLOCKS (mtd->size, mtd->erasesize); + + param->start_block =0 ; + param->end_block = n_blocks -1 ; + }else { +/* use the MTD interface in yaffs_mtdif1.c */ + param->write_chunk_tags_fn = nandmtd1_write_chunk_tags; + param->read_chunk_tags_fn = nandmtd1_read_chunk_tags; + param->bad_block_fn = nandmtd1_mark_block_bad; + param->query_block_fn = nandmtd1_query_block; + param->is_yaffs2 =0 ; + } +/* ... and common functions */ + param->erase_fn = nandmtd_erase_block; + param->initialise_flash_fn = nandmtd_initialise; + +yaffs_dev_to_lc (dev)->put_super_fn = yaffs_mtd_put_super; + + param->sb_dirty_fn = yaffs_touch_super; + param->gc_control = yaffs_gc_control_callback; + +yaffs_dev_to_lc (dev)->super = sb; + +#ifndef CONFIG_YAFFS_DOES_ECC + param->use_nand_ecc =1 ; +#endif + + param->skip_checkpt_rd = options.skip_checkpoint_read; + param->skip_checkpt_wr = options.skip_checkpoint_write;
fs/yaffs2/yaffs_vfs.c line 2270
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ +mutex_lock (&yaffs_context_lock); +/* Get a mount id */ + found =0 ; +for (mount_id =0 ; !found; mount_id++) { + found =1 ; +list_for_each (l, &yaffs_context_list) { + context_iterator = + list_entry(l, struct yaffs_linux_context, + context_list);
list_for_each_entry(context_iterator, &yaffs_context_list,
context_list)
Quoted 9 lines
fs/yaffs2/yaffs_vfs.c new file +9
-0+if (context_iterator->mount_id == mount_id) + found =0 ; + } + } + context->mount_id = mount_id; + +list_add_tail (&(yaffs_dev_to_lc (dev)->context_list), + &yaffs_context_list); +mutex_unlock (&yaffs_context_lock);
fs/yaffs2/yaffs_vfs.c line 2289
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ +/* Directory search handling... */ +INIT_LIST_HEAD (&(yaffs_dev_to_lc (dev)->search_contexts)); + param->remove_obj_fn = yaffs_remove_obj_callback; + +mutex_init (&(yaffs_dev_to_lc (dev)->gross_lock)); + +yaffs_gross_lock (dev); + + err =yaffs_guts_initialise (dev);
We seem to carry on for a while if this function fails?
Quoted 107 lines
fs/yaffs2/yaffs_vfs.c new file +107
-0+yaffs_trace (YAFFS_TRACE_OS , +"yaffs_read_super: guts initialised %s" , + (err ==YAFFS_OK ) ?"OK" :"FAILED" ); + +if (err ==YAFFS_OK ) +yaffs_bg_start (dev); + +if (!context->bg_thread) + param->defered_dir_update =0 ; + +/* Release lock before yaffs_get_inode() */ +yaffs_gross_unlock (dev); + +/* Create root inode */ +if (err ==YAFFS_OK ) + inode =yaffs_get_inode (sb,S_IFDIR |0755 ,0 ,yaffs_root (dev)); + +if (!inode) +return NULL ; + + inode->i_op = &yaffs_dir_inode_operations; + inode->i_fop = &yaffs_dir_operations; + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_read_super: got root inode" ); + + root =d_alloc_root (inode); + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_read_super: d_alloc_root done" ); + +if (!root) { +iput (inode); +return NULL ; + } + sb->s_root = root; + sb->s_dirt = !dev->is_checkpointed; +yaffs_trace (YAFFS_TRACE_ALWAYS , +"yaffs_read_super: is_checkpointed %d" , + dev->is_checkpointed); + +yaffs_trace (YAFFS_TRACE_OS ,"yaffs_read_super: done" ); +return sb; +} + +static int yaffs_internal_read_super_mtd (struct super_block *sb,void *data, +int silent) +{ +return yaffs_internal_read_super (1 , sb, data, silent) ?0 : -EINVAL ; +} + +static int yaffs_read_super (struct file_system_type *fs, +int flags,const char *dev_name, +void *data,struct vfsmount *mnt) +{ + +return get_sb_bdev (fs, flags, dev_name, data, + yaffs_internal_read_super_mtd, mnt); +} + +static struct file_system_type yaffs_fs_type = { + .owner =THIS_MODULE , + .name ="yaffs" , + .get_sb = yaffs_read_super, + .kill_sb = kill_block_super, + .fs_flags =FS_REQUIRES_DEV , +}; + +#ifdef CONFIG_YAFFS_YAFFS2 + +static int yaffs2_internal_read_super_mtd (struct super_block *sb,void *data, +int silent) +{ +return yaffs_internal_read_super (2 , sb, data, silent) ?0 : -EINVAL ; +} + +static int yaffs2_read_super (struct file_system_type *fs, +int flags,const char *dev_name,void *data, +struct vfsmount *mnt) +{ +return get_sb_bdev (fs, flags, dev_name, data, + yaffs2_internal_read_super_mtd, mnt); +} + +static struct file_system_type yaffs2_fs_type = { + .owner =THIS_MODULE , + .name ="yaffs2" , + .get_sb = yaffs2_read_super, + .kill_sb = kill_block_super, + .fs_flags =FS_REQUIRES_DEV , +}; +#endif /* CONFIG_YAFFS_YAFFS2 */ + +static struct proc_dir_entry *my_proc_entry; + +static char *yaffs_dump_dev_part0 (char *buf,struct yaffs_dev *dev) +{ +struct yaffs_param *param = &dev->param; + + buf +=sprintf (buf,"start_block........... %d\n" , param->start_block); + buf +=sprintf (buf,"end_block............. %d\n" , param->end_block); + buf +=sprintf (buf,"total_bytes_per_chunk. %d\n" , + param->total_bytes_per_chunk); + buf +=sprintf (buf,"use_nand_ecc.......... %d\n" , + param->use_nand_ecc); + buf +=sprintf (buf,"no_tags_ecc........... %d\n" , param->no_tags_ecc); + buf +=sprintf (buf,"is_yaffs2............. %d\n" , param->is_yaffs2); + buf +=sprintf (buf,"inband_tags........... %d\n" , param->inband_tags); + buf += sprintf(buf, "empty_lost_n_found.... %d\n",
fs/yaffs2/yaffs_vfs.c line 2407
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ param->empty_lost_n_found); + buf +=sprintf (buf,"disable_lazy_load..... %d\n" , + param->disable_lazy_load); + buf +=sprintf (buf,"refresh_period........ %d\n" , + param->refresh_period); + buf +=sprintf (buf,"n_caches.............. %d\n" , param->n_caches); + buf +=sprintf (buf,"n_reserved_blocks..... %d\n" , + param->n_reserved_blocks); + buf +=sprintf (buf,"always_check_erased... %d\n" , + param->always_check_erased);
How big is buf? snprintf with maxlen would be better.
Quoted 67 lines
fs/yaffs2/yaffs_vfs.c new file +67
-0+ +return buf; +} + +static char *yaffs_dump_dev_part1 (char *buf,struct yaffs_dev *dev) +{ + buf += +sprintf (buf,"data_bytes_per_chunk.. %d\n" , + dev->data_bytes_per_chunk); + buf +=sprintf (buf,"chunk_grp_bits........ %d\n" , dev->chunk_grp_bits); + buf +=sprintf (buf,"chunk_grp_size........ %d\n" , dev->chunk_grp_size); + buf += +sprintf (buf,"n_erased_blocks....... %d\n" , dev->n_erased_blocks); + buf += +sprintf (buf,"blocks_in_checkpt..... %d\n" , dev->blocks_in_checkpt); + buf +=sprintf (buf,"\n" ); + buf +=sprintf (buf,"n_tnodes.............. %d\n" , dev->n_tnodes); + buf +=sprintf (buf,"n_obj................. %d\n" , dev->n_obj); + buf +=sprintf (buf,"n_free_chunks......... %d\n" , dev->n_free_chunks); + buf +=sprintf (buf,"\n" ); + buf +=sprintf (buf,"n_page_writes......... %u\n" , dev->n_page_writes); + buf +=sprintf (buf,"n_page_reads.......... %u\n" , dev->n_page_reads); + buf +=sprintf (buf,"n_erasures............ %u\n" , dev->n_erasures); + buf +=sprintf (buf,"n_gc_copies........... %u\n" , dev->n_gc_copies); + buf +=sprintf (buf,"all_gcs............... %u\n" , dev->all_gcs); + buf += +sprintf (buf,"passive_gc_count...... %u\n" , dev->passive_gc_count); + buf += +sprintf (buf,"oldest_dirty_gc_count. %u\n" , + dev->oldest_dirty_gc_count); + buf +=sprintf (buf,"n_gc_blocks........... %u\n" , dev->n_gc_blocks); + buf +=sprintf (buf,"bg_gcs................ %u\n" , dev->bg_gcs); + buf += +sprintf (buf,"n_retired_writes...... %u\n" , dev->n_retired_writes); + buf += +sprintf (buf,"n_retired_blocks...... %u\n" , dev->n_retired_blocks); + buf +=sprintf (buf,"n_ecc_fixed........... %u\n" , dev->n_ecc_fixed); + buf +=sprintf (buf,"n_ecc_unfixed......... %u\n" , dev->n_ecc_unfixed); + buf += +sprintf (buf,"n_tags_ecc_fixed...... %u\n" , dev->n_tags_ecc_fixed); + buf += +sprintf (buf,"n_tags_ecc_unfixed.... %u\n" , + dev->n_tags_ecc_unfixed); + buf +=sprintf (buf,"cache_hits............ %u\n" , dev->cache_hits); + buf += +sprintf (buf,"n_deleted_files....... %u\n" , dev->n_deleted_files); + buf += +sprintf (buf,"n_unlinked_files...... %u\n" , dev->n_unlinked_files); + buf +=sprintf (buf,"refresh_count......... %u\n" , dev->refresh_count); + buf +=sprintf (buf,"n_bg_deletions........ %u\n" , dev->n_bg_deletions); + +return buf; +} + +static int yaffs_proc_read (char *page, +char **start, +off_t offset,int count,int *eof,void *data) +{ +struct list_head *item; +char *buf = page; +int step = offset; +int n =0 ; + +/* Get proc_file_read() to step 'offset' by one on each sucessive call. +* We use 'offset' (*ppos) to indicate where we are in dev_list. +* This also assumes the user has posted a read buffer large +* enough to hold the complete output; but that's life in /proc.
fs/yaffs2/yaffs_vfs.c line 2484
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+*/ + + *(int *)start =1 ; + +/* Print header first */ +if (step ==0 ) + buf +=sprintf (buf,"YAFFS built:" __DATE__" " __TIME__"\n" ); +else if (step ==1 ) + buf +=sprintf (buf,"\n" ); +else {
IIRC you can use seq_file for this which is safer/easier than using sprintf.
Quoted 78 lines
fs/yaffs2/yaffs_vfs.c new file +78
-0+ step -=2 ; + +mutex_lock (&yaffs_context_lock); + +/* Locate and print the Nth entry. +* Order N-squared but N is small. */ +list_for_each (item, &yaffs_context_list) { +struct yaffs_linux_context *dc = + list_entry(item, struct yaffs_linux_context, + context_list); +struct yaffs_dev *dev = dc->dev; + +if (n < (step & ~1 )) { + n +=2 ; +continue ; + } +if ((step &1 ) ==0 ) { + buf += +sprintf (buf,"\nDevice %d \"%s\"\n" , n, + dev->param.name); + buf =yaffs_dump_dev_part0 (buf, dev); + }else { + buf =yaffs_dump_dev_part1 (buf, dev); + } + +break ; + } +mutex_unlock (&yaffs_context_lock); + } + +return buf - page < count ? buf - page : count; +} + + +/** +* Set the verbosity of the warnings and error messages. +* +* Note that the names can only be a..z or _ with the current code. +*/ + +static struct { +char *mask_name; +unsigned mask_bitfield; +} mask_flags[] = { + {"allocate" ,YAFFS_TRACE_ALLOCATE }, + {"always" ,YAFFS_TRACE_ALWAYS }, + {"background" ,YAFFS_TRACE_BACKGROUND }, + {"bad_blocks" ,YAFFS_TRACE_BAD_BLOCKS }, + {"buffers" ,YAFFS_TRACE_BUFFERS }, + {"bug" ,YAFFS_TRACE_BUG }, + {"checkpt" ,YAFFS_TRACE_CHECKPOINT }, + {"deletion" ,YAFFS_TRACE_DELETION }, + {"erase" ,YAFFS_TRACE_ERASE }, + {"error" ,YAFFS_TRACE_ERROR }, + {"gc_detail" ,YAFFS_TRACE_GC_DETAIL }, + {"gc" ,YAFFS_TRACE_GC }, + {"lock" ,YAFFS_TRACE_LOCK }, + {"mtd" ,YAFFS_TRACE_MTD }, + {"nandaccess" ,YAFFS_TRACE_NANDACCESS }, + {"os" ,YAFFS_TRACE_OS }, + {"scan_debug" ,YAFFS_TRACE_SCAN_DEBUG }, + {"scan" ,YAFFS_TRACE_SCAN }, + {"mount" ,YAFFS_TRACE_MOUNT }, + {"tracing" ,YAFFS_TRACE_TRACING }, + {"sync" ,YAFFS_TRACE_SYNC }, + {"write" ,YAFFS_TRACE_WRITE }, + {"verify" ,YAFFS_TRACE_VERIFY }, + {"verify_nand" ,YAFFS_TRACE_VERIFY_NAND }, + {"verify_full" ,YAFFS_TRACE_VERIFY_FULL }, + {"verify_all" ,YAFFS_TRACE_VERIFY_ALL }, + {"all" ,0xffffffff }, + {"none" ,0 }, + {NULL ,0 }, +}; + +#define MAX_MASK_NAME_LENGTH 40 +static int yaffs_proc_write_trace_options (struct file *file,const char *buf, +unsigned long count,void *data)
fs/yaffs2/yaffs_vfs.c line 2572
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+{ +unsigned rg =0 , mask_bitfield; +char *end; +char *mask_name; +const char *x; +char substring[MAX_MASK_NAME_LENGTH +1 ]; +int i; +int done =0 ; +int add, len =0 ; +int pos =0 ;
sysfs is probably a better interface for controlling this sort of thing.
Quoted 117 lines
fs/yaffs2/yaffs_vfs.c new file +117
-0+ rg = yaffs_trace_mask; + +while (!done && (pos < count)) { + done =1 ; +while ((pos < count) &&isspace (buf[pos])) + pos++; + +switch (buf[pos]) { +case '+' : +case '-' : +case '=' : + add = buf[pos]; + pos++; +break ; + +default : + add =' ' ; +break ; + } + mask_name =NULL ; + + mask_bitfield =simple_strtoul (buf + pos, &end,0 ); + +if (end > buf + pos) { + mask_name ="numeral" ; + len = end - (buf + pos); + pos += len; + done =0 ; + }else { +for (x = buf + pos, i =0 ; + (*x =='_' || (*x >='a' && *x <='z' )) && + i <MAX_MASK_NAME_LENGTH ; x++, i++, pos++) + substring[i] = *x; + substring[i] ='\0' ; + +for (i =0 ; mask_flags[i].mask_name !=NULL ; i++) { +if (strcmp (substring, mask_flags[i].mask_name) + ==0 ) { + mask_name = mask_flags[i].mask_name; + mask_bitfield = + mask_flags[i].mask_bitfield; + done =0 ; +break ; + } + } + } + +if (mask_name !=NULL ) { + done =0 ; +switch (add) { +case '-' : + rg &= ~mask_bitfield; +break ; +case '+' : + rg |= mask_bitfield; +break ; +case '=' : + rg = mask_bitfield; +break ; +default : + rg |= mask_bitfield; +break ; + } + } + } + + yaffs_trace_mask = rg |YAFFS_TRACE_ALWAYS ; + +printk (KERN_DEBUG "new trace = 0x%08X\n" , yaffs_trace_mask); + +if (rg &YAFFS_TRACE_ALWAYS ) { +for (i =0 ; mask_flags[i].mask_name !=NULL ; i++) { +char flag; + flag = ((rg & mask_flags[i].mask_bitfield) == + mask_flags[i].mask_bitfield) ?'+' :'-' ; +printk (KERN_DEBUG "%c%s\n" , flag, + mask_flags[i].mask_name); + } + } + +return count; +} + +static int yaffs_proc_write (struct file *file,const char *buf, +unsigned long count,void *data) +{ +return yaffs_proc_write_trace_options (file, buf, count, data); +} + +/* Stuff to handle installation of file systems */ +struct file_system_to_install { +struct file_system_type *fst; +int installed; +}; + +static struct file_system_to_install fs_to_install[] = { + {&yaffs_fs_type,0 }, + {&yaffs2_fs_type,0 }, + {NULL ,0 } +}; + +static int __init init_yaffs_fs (void ) +{ +int error =0 ; +struct file_system_to_install *fsinst; + +yaffs_trace (YAFFS_TRACE_ALWAYS , +"yaffs built " __DATE__" " __TIME__" Installing." ); + +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED +yaffs_trace (YAFFS_TRACE_ALWAYS , +"\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n" ); +#endif + +mutex_init (&yaffs_context_lock); + +/* Install the proc_fs entries */
fs/yaffs2/yaffs_vfs.c line 2700
Quoted 10 lines
fs/yaffs2/yaffs_vfs.c new file +10
-0+ my_proc_entry =create_proc_entry ("yaffs" , +S_IRUGO |S_IFREG ,NULL ); + +if (my_proc_entry) { + my_proc_entry->write_proc = yaffs_proc_write; + my_proc_entry->read_proc = yaffs_proc_read; + my_proc_entry->data =NULL ; + }else { +return -ENOMEM ; + }
Make the successful path the simple one:
if (!my_proc_entry) return -ENOMEM;
Quoted 84 lines
fs/yaffs2/yaffs_vfs.c new file +56
-0+ + +/* Now add the file system entries */ + + fsinst = fs_to_install; + +while (fsinst->fst && !error) { + error =register_filesystem (fsinst->fst); +if (!error) + fsinst->installed =1 ; + fsinst++; + } + +/* Any errors? uninstall */ +if (error) { + fsinst = fs_to_install; + +while (fsinst->fst) { +if (fsinst->installed) { +unregister_filesystem (fsinst->fst); + fsinst->installed =0 ; + } + fsinst++; + } + } + +return error; +} + +static void __exit exit_yaffs_fs(void) +{ + +struct file_system_to_install *fsinst; + +yaffs_trace (YAFFS_TRACE_ALWAYS , +"yaffs built " __DATE__" " __TIME__" removing." ); + +remove_proc_entry ("yaffs" ,NULL ); + + fsinst = fs_to_install; + +while (fsinst->fst) { +if (fsinst->installed) { +unregister_filesystem (fsinst->fst); + fsinst->installed =0 ; + } + fsinst++; + } +} + +module_init(init_yaffs_fs) +module_exit(exit_yaffs_fs) + +MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); +MODULE_AUTHOR ("Charles Manning, Aleph One Ltd., 2002-2010" ); +MODULE_LICENSE ("GPL" );fs/yaffs2/yportenv.h new file +22
-0@@ -0,0 +1,70 @@ +/* +* YAFFS: Yet another Flash File System . A NAND-flash specific file system. +* +* Copyright (C) 2002-2010 Aleph One Ltd. +* for Toby Churchill Ltd and Brightstar Engineering +* +* Created by Charles Manning <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 2.1 as +* published by the Free Software Foundation. +* +* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. +*/ + +#ifndef __YPORTENV_LINUX_H__ +#define __YPORTENV_LINUX_H__ + +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/sched.h>
fs/yaffs2/yportenv.h line 32
Quoted 10 lines
fs/yaffs2/yportenv.h new file +10
-0+#include <linux/string.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/xattr.h> +#include <linux/list.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/stat.h> +#include <linux/sort.h> +#include <linux/bitops.h>
Are these all necessary? Each file should only include the headers it actually requires. I don't image you need linux/version.h for mainline :-).
Quoted 7 lines
fs/yaffs2/yportenv.h new file +7
-0+ +#define YCHAR char +#define YUCHAR unsigned char +#define _Y (x) x + +#define YAFFS_LOSTNFOUND_NAME "lost+found" +#define YAFFS_LOSTNFOUND_PREFIX "obj"
fs/yaffs2/yportenv.h line 49
Quoted 10 lines
fs/yaffs2/yportenv.h new file +10
-0+ + +#define YAFFS_ROOT_MODE 0755 +#define YAFFS_LOSTNFOUND_MODE 0700 + +#define Y_CURRENT_TIME CURRENT_TIME.tv_sec +#define Y_TIME_CONVERT (x) (x).tv_sec + +#define compile_time_assertion (assertion) \ + ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
Have a look at the BUILD_BUG_ON macros in include/linux/kernel.h
fs/yaffs2/yportenv.h line 54
Quoted 4 lines
fs/yaffs2/yportenv.h new file +4
-0+ +#ifndef Y_DUMP_STACK +#define Y_DUMP_STACK () dump_stack() +#endif
Do you need this wrapper? If you change YBUG to BUG then this can probably go away as well.
fs/yaffs2/yportenv.h line 67
Quoted 12 lines
fs/yaffs2/yportenv.h new file +12
-0+#define yaffs_trace (msk, fmt, ...) do { \ + if (yaffs_trace_mask & (msk)) \ + printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \ +} while (0) + +#ifndef YBUG +#define YBUG () do {\ + yaffs_trace(YAFFS_TRACE_BUG,\ + "bug " __FILE__ " %d",\ + __LINE__);\ + Y_DUMP_STACK();\ +} while (0)
I think this should be replaced with just BUG. The naming here implies that it has similar behaviour to BUG, which it does not. I'm guessing that most of the places you are calling YBUG are unexpected states and actually continuing is likely to result in further damage to the filesystem. In general I think it would be better to just call BUG, have the machine crash and get problems reported.
Quoted 3 lines
fs/yaffs2/yportenv.h new file +3
-0+#endif + +#endif
Signature · 7 lines
Bluewater Systems Ltd - ARM Technology Solution Centre Ryan Mallon 5 Amuri Park, 404 Barbadoes St [email protected] PO Box 13 889, Christchurch 8013 http://www.bluewatersys.com New Zealand Phone: +64 3 3779127 Freecall: Australia 1800 148 751 Fax: +64 3 3779135 USA 1800 261 2934
PATCH 10/10 Add yaffs2 file system: Hook in to Linux tree
In reply to Charles ManningChange existing Makefile, Kconfig and MAINTAINERS. Add yaffs2 specific Makefile and Kconfig
--- MAINTAINERS | 7 ++ fs/Kconfig | 1 + fs/Makefile | 1 + fs/yaffs2/Kconfig | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/Makefile | 17 ++++++ 5 files changed, 187 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/Kconfig create mode 100644 fs/yaffs2/Makefile
MAINTAINERS +7 -0
@@ -6838,6 +6838,13 @@ L: [email protected] S: Maintained F: drivers/serial/uartlite.c +YAFFS2 FLASH FILE SYSTEM +M: Charles Manning <[email protected]> +W: http://www.yaffs.net/ +L: [email protected] +S: Maintained +F: fs/yaffs2 + YAM DRIVER FOR AX.25 M: Jean-Paul Roubelat <[email protected]> L: [email protected]
fs/Kconfig +1 -0
@@ -176,6 +176,7 @@ source "fs/hfsplus/Kconfig" source "fs/befs/Kconfig" source "fs/bfs/Kconfig" source "fs/efs/Kconfig" +source "fs/yaffs2/Kconfig" source "fs/jffs2/Kconfig" # UBIFS File system configuration source "fs/ubifs/Kconfig"
fs/Makefile +1 -0
@@ -121,3 +121,4 @@ obj-$(CONFIG_BTRFS_FS) += btrfs/ obj-$(CONFIG_GFS2_FS) += gfs2/ obj-$(CONFIG_EXOFS_FS) += exofs/ obj-$(CONFIG_CEPH_FS) += ceph/ +obj-$(CONFIG_YAFFS_FS) += yaffs2/
fs/yaffs2/Kconfig new file +161 -0
161 lines not on this page · raw message
fs/yaffs2/Makefile new file +17 -0
@@ -0,0 +1,17 @@ +# +# Makefile for the linux YAFFS filesystem routines. +# + +obj-$(CONFIG_YAFFS_FS) += yaffs.o + +yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o +yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o +yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o +yaffs-y += yaffs_nameval.o yaffs_attribs.o +yaffs-y += yaffs_allocator.o +yaffs-y += yaffs_yaffs1.o +yaffs-y += yaffs_yaffs2.o +yaffs-y += yaffs_bitmap.o +yaffs-y += yaffs_verify.o +
Signature · 1 line
1.7.1
Re: [PATCH 10/10] Add yaffs2 file system: Hook in to Linux tree
Hi Charles,
A few minor comments below.
Quoted 59 lines · Charles Manning
Change existing
Makefile,KconfigandMAINTAINERS. Add yaffs2 specificMakefileandKconfigSigned-off-by Charles Manning <[email protected]>--- MAINTAINERS | 7 ++ fs/Kconfig | 1 + fs/Makefile | 1 + fs/yaffs2/Kconfig | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/yaffs2/Makefile | 17 ++++++ 5 files changed, 187 insertions(+), 0 deletions(-) create mode 100644 fs/yaffs2/Kconfig create mode 100644 fs/yaffs2/MakefileMAINTAINERS +7
-0@@ -6838,6 +6838,13 @@ L: [email protected] S: Maintained F: drivers/serial/uartlite.c +YAFFS2 FLASH FILE SYSTEM +M: Charles Manning <[email protected]> +W: http://www.yaffs.net/ +L: [email protected] +S: Maintained +F: fs/yaffs2 + YAM DRIVER FOR AX.25 M: Jean-Paul Roubelat <[email protected]> L: [email protected]fs/Kconfig +1
-0@@ -176,6 +176,7 @@ source "fs/hfsplus/Kconfig" source "fs/befs/Kconfig" source "fs/bfs/Kconfig" source "fs/efs/Kconfig" +source "fs/yaffs2/Kconfig" source "fs/jffs2/Kconfig" # UBIFS File system configuration source "fs/ubifs/Kconfig"fs/Makefile +1
-0@@ -121,3 +121,4 @@ obj-$(CONFIG_BTRFS_FS) += btrfs/ obj-$(CONFIG_GFS2_FS) += gfs2/ obj-$(CONFIG_EXOFS_FS) += exofs/ obj-$(CONFIG_CEPH_FS) += ceph/ +obj-$(CONFIG_YAFFS_FS) += yaffs2/fs/yaffs2/Kconfig new file +0
-0
fs/yaffs2/Kconfig line 6
Quoted 6 lines
fs/yaffs2/Kconfig new file +6
-0@@ -0,0 +1,161 @@ +# +# YAFFS file system configurations +# + +config YAFFS_FS + tristate "YAFFS2 file system support"
"file system"
fs/yaffs2/Kconfig line 12
Quoted 6 lines
fs/yaffs2/Kconfig new file +6
-0+ default n + depends on MTD_BLOCK + select YAFFS_YAFFS1 + select YAFFS_YAFFS2 + help + YAFFS2, or Yet Another Flash Filing System, is a filing system
"filing system"
fs/yaffs2/Kconfig line 15
Quoted 3 lines
fs/yaffs2/Kconfig new file +3
-0+ optimised for NAND Flash chips. + + To compile the YAFFS2 file system support as a module, choose M
"file system"
Why "file system" in some places and "filing system" in others?
Quoted 27 lines
fs/yaffs2/Kconfig new file +27
-0+ here: the module will be called yaffs2. + + If unsure, say N. + + Further information on YAFFS2 is available at + <http://www.aleph1.co.uk/yaffs/>. + +config YAFFS_YAFFS1 + bool "512 byte / page devices" + depends on YAFFS_FS + default y + help + Enable YAFFS1 support -- yaffs for 512 byte / page devices + + Not needed for 2K-page devices. + + If unsure, say Y. + +config YAFFS_9BYTE_TAGS + bool "Use older-style on-NAND data format with pageStatus byte" + depends on YAFFS_YAFFS1 + default n + help + + Older-style on-NAND data format has a "pageStatus" byte to record + chunk/page state. This byte is zero when the page is discarded. + Choose this option if you have existing on-NAND data using this
fs/yaffs2/Kconfig line 52
Quoted 10 lines
fs/yaffs2/Kconfig new file +10
-0+ format that you need to continue to support. New data written + also uses the older-style format. Note: Use of this option + generally requires that MTD's oob layout be adjusted to use the + older-style format. See notes on tags formats and MTD versions + in yaffs_mtdif1.c. + + If unsure, say N. + +config YAFFS_DOES_ECC + bool "Lets Yaffs do its own ECC"
Shouldn't this read "Let Yaffs do its own ECC" ?
Ohh and why the different capitalization? Here it is "Yaffs", elsewhere it it is "YAFFS".
fs/yaffs2/Kconfig line 56
Quoted 4 lines
fs/yaffs2/Kconfig new file +4
-0+ depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS + default n + help + This enables Yaffs to use its own ECC functions instead of using
Again - "Yaffs" vs "YAFFS". Personally I'd say "pick one".
fs/yaffs2/Kconfig line 62
Quoted 6 lines
fs/yaffs2/Kconfig new file +6
-0+ the ones from the generic MTD-NAND driver. + + If unsure, say N. + +config YAFFS_ECC_WRONG_ORDER + bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
Shouldn't this be "Use the same ECC byte order ..." ?
fs/yaffs2/Kconfig line 67
Quoted 5 lines
fs/yaffs2/Kconfig new file +5
-0+ depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS + default n + help + This makes yaffs_ecc.c use the same ecc byte order as Steven + Hill's nand_ecc.c. If not set, then you get the same ecc byte
ECC?
fs/yaffs2/Kconfig line 77
Quoted 10 lines
fs/yaffs2/Kconfig new file +10
-0+ order as SmartMedia. + + If unsure, say N. + +config YAFFS_YAFFS2 + bool "2048 byte (or larger) / page devices" + depends on YAFFS_FS + default y + help + Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
YAFFS vs Yaffs vs yaffs... - elsewhere as well, not pointing this out for the rest of the patch..
Quoted 23 lines
fs/yaffs2/Kconfig new file +23
-0+ + If unsure, say Y. + +config YAFFS_AUTO_YAFFS2 + bool "Autoselect yaffs2 format" + depends on YAFFS_YAFFS2 + default y + help + Without this, you need to explicitely use yaffs2 as the file + system type. With this, you can say "yaffs" and yaffs or yaffs2 + will be used depending on the device page size (yaffs on + 512-byte page devices, yaffs2 on 2K page devices). + + If unsure, say Y. + +config YAFFS_DISABLE_TAGS_ECC + bool "Disable YAFFS from doing ECC on tags by default" + depends on YAFFS_FS && YAFFS_YAFFS2 + default n + help + This defaults Yaffs to using its own ECC calculations on tags instead of + just relying on the MTD. + This behavior can also be overridden with tags_ecc_on and
fs/yaffs2/Kconfig line 110
Quoted 10 lines
fs/yaffs2/Kconfig new file +10
-0+ tags_ecc_off mount options. + + If unsure, say N. + +config YAFFS_ALWAYS_CHECK_CHUNK_ERASED + bool "Force chunk erase check" + depends on YAFFS_FS + default n + help + Normally YAFFS only checks chunks before writing until an erased
You don't have this extra indentation at the start of the first line for other help entries...
fs/yaffs2/Kconfig line 118
Quoted 8 lines
fs/yaffs2/Kconfig new file +8
-0+ chunk is found. This helps to detect any partially written + chunks that might have happened due to power loss. + + Enabling this forces on the test that chunks are erased in flash + before writing to them. This takes more time but is potentially + a bit more secure. + + Suggest setting Y during development and ironing out driver
Perhaps "It is suggested to set this to Y during development ..." or "We recommend setting this to Y during .." - the current wording is a little clumsy IMHO.
fs/yaffs2/Kconfig line 120
Quoted 2 lines
fs/yaffs2/Kconfig new file +2
-0+ issues etc. Suggest setting to N if you want faster writing. +
Same for "N".
fs/yaffs2/Kconfig line 129
Quoted 9 lines
fs/yaffs2/Kconfig new file +9
-0+ If unsure, say Y. + +config YAFFS_EMPTY_LOST_AND_FOUND + bool "Empty lost and found on boot" + depends on YAFFS_FS + default n + help + If this is enabled then the contents of lost and found is + automatically dumped at mount.
Hmm, isn't the dir named "lost+found", not "lost and found" ?
Quoted 22 lines
fs/yaffs2/Kconfig new file +22
-0+ + If unsure, say N. + +config YAFFS_DISABLE_BLOCK_REFRESHING + bool "Disable yaffs2 block refreshing" + depends on YAFFS_FS + default n + help + If this is set, then block refreshing is disabled. + Block refreshing infrequently refreshes the oldest block in + a yaffs2 file system. This mechanism helps to refresh flash to + mitigate against data loss. This is particularly useful for MLC. + + If unsure, say N. + +config YAFFS_DISABLE_BACKGROUND + bool "Disable yaffs2 background processing" + depends on YAFFS_FS + default n + help + If this is set, then background processing is disabled. + Background processing makes many foreground activities faster.
fs/yaffs2/Kconfig line 161
Quoted 10 lines
fs/yaffs2/Kconfig new file +10
-0+ + If unsure, say N. + +config YAFFS_XATTR + bool "Enable yaffs2 xattr support" + depends on YAFFS_FS + default y + help + If this is set then yaffs2 will provide xattr support. + If unsure, say Y.
You usually have a blank line before the "If unsure, say X" line, but not here - I think you should have.
Quoted 24 lines
fs/yaffs2/Makefile new file +17
-0@@ -0,0 +1,17 @@ +# +# Makefile for the linux YAFFS filesystem routines. +# + +obj-$(CONFIG_YAFFS_FS) += yaffs.o + +yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o +yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o +yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o +yaffs-y += yaffs_nameval.o yaffs_attribs.o +yaffs-y += yaffs_allocator.o +yaffs-y += yaffs_yaffs1.o +yaffs-y += yaffs_yaffs2.o +yaffs-y += yaffs_bitmap.o +yaffs-y += yaffs_verify.o +
Signature · 3 lines
Jesper Juhl <[email protected]> http://www.chaosbits.net/ Don't top-post http://www.catb.org/~esr/jargon/html/T/top-post.html Plain text mails only, please.