| 1 | --- a/fs/Kconfig |
| 2 | +++ b/fs/Kconfig |
| 3 | @@ -35,7 +35,6 @@ source "fs/gfs2/Kconfig" |
| 4 | source "fs/ocfs2/Kconfig" |
| 5 | source "fs/btrfs/Kconfig" |
| 6 | source "fs/nilfs2/Kconfig" |
| 7 | -source "fs/yaffs2/Kconfig" |
| 8 | |
| 9 | endif # BLOCK |
| 10 | |
| 11 | @@ -194,6 +193,10 @@ source "fs/hfsplus/Kconfig" |
| 12 | source "fs/befs/Kconfig" |
| 13 | source "fs/bfs/Kconfig" |
| 14 | source "fs/efs/Kconfig" |
| 15 | + |
| 16 | +# Patched by YAFFS |
| 17 | +source "fs/yaffs2/Kconfig" |
| 18 | + |
| 19 | source "fs/jffs2/Kconfig" |
| 20 | # UBIFS File system configuration |
| 21 | source "fs/ubifs/Kconfig" |
| 22 | --- a/fs/Makefile |
| 23 | +++ b/fs/Makefile |
| 24 | @@ -125,5 +125,6 @@ obj-$(CONFIG_GFS2_FS) += gfs2/ |
| 25 | obj-$(CONFIG_EXOFS_FS) += exofs/ |
| 26 | obj-$(CONFIG_CEPH_FS) += ceph/ |
| 27 | obj-$(CONFIG_PSTORE) += pstore/ |
| 28 | -obj-$(CONFIG_YAFFS_FS) += yaffs2/ |
| 29 | |
| 30 | +# Patched by YAFFS |
| 31 | +obj-$(CONFIG_YAFFS_FS) += yaffs2/ |
| 32 | --- a/fs/yaffs2/devextras.h |
| 33 | +++ b/fs/yaffs2/devextras.h |
| 34 | @@ -1,7 +1,7 @@ |
| 35 | /* |
| 36 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 37 | * |
| 38 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 39 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 40 | * for Toby Churchill Ltd and Brightstar Engineering |
| 41 | * |
| 42 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 43 | @@ -24,6 +24,8 @@ |
| 44 | #define __EXTRAS_H__ |
| 45 | |
| 46 | |
| 47 | +#include "yportenv.h" |
| 48 | + |
| 49 | #if !(defined __KERNEL__) |
| 50 | |
| 51 | /* Definition of types */ |
| 52 | @@ -33,103 +35,6 @@ typedef unsigned __u32; |
| 53 | |
| 54 | #endif |
| 55 | |
| 56 | -/* |
| 57 | - * This is a simple doubly linked list implementation that matches the |
| 58 | - * way the Linux kernel doubly linked list implementation works. |
| 59 | - */ |
| 60 | - |
| 61 | -struct ylist_head { |
| 62 | - struct ylist_head *next; /* next in chain */ |
| 63 | - struct ylist_head *prev; /* previous in chain */ |
| 64 | -}; |
| 65 | - |
| 66 | - |
| 67 | -/* Initialise a static list */ |
| 68 | -#define YLIST_HEAD(name) \ |
| 69 | -struct ylist_head name = { &(name), &(name)} |
| 70 | - |
| 71 | - |
| 72 | - |
| 73 | -/* Initialise a list head to an empty list */ |
| 74 | -#define YINIT_LIST_HEAD(p) \ |
| 75 | -do { \ |
| 76 | - (p)->next = (p);\ |
| 77 | - (p)->prev = (p); \ |
| 78 | -} while (0) |
| 79 | - |
| 80 | - |
| 81 | -/* Add an element to a list */ |
| 82 | -static __inline__ void ylist_add(struct ylist_head *newEntry, |
| 83 | - struct ylist_head *list) |
| 84 | -{ |
| 85 | - struct ylist_head *listNext = list->next; |
| 86 | - |
| 87 | - list->next = newEntry; |
| 88 | - newEntry->prev = list; |
| 89 | - newEntry->next = listNext; |
| 90 | - listNext->prev = newEntry; |
| 91 | - |
| 92 | -} |
| 93 | - |
| 94 | -static __inline__ void ylist_add_tail(struct ylist_head *newEntry, |
| 95 | - struct ylist_head *list) |
| 96 | -{ |
| 97 | - struct ylist_head *listPrev = list->prev; |
| 98 | - |
| 99 | - list->prev = newEntry; |
| 100 | - newEntry->next = list; |
| 101 | - newEntry->prev = listPrev; |
| 102 | - listPrev->next = newEntry; |
| 103 | - |
| 104 | -} |
| 105 | - |
| 106 | - |
| 107 | -/* Take an element out of its current list, with or without |
| 108 | - * reinitialising the links.of the entry*/ |
| 109 | -static __inline__ void ylist_del(struct ylist_head *entry) |
| 110 | -{ |
| 111 | - struct ylist_head *listNext = entry->next; |
| 112 | - struct ylist_head *listPrev = entry->prev; |
| 113 | - |
| 114 | - listNext->prev = listPrev; |
| 115 | - listPrev->next = listNext; |
| 116 | - |
| 117 | -} |
| 118 | - |
| 119 | -static __inline__ void ylist_del_init(struct ylist_head *entry) |
| 120 | -{ |
| 121 | - ylist_del(entry); |
| 122 | - entry->next = entry->prev = entry; |
| 123 | -} |
| 124 | - |
| 125 | - |
| 126 | -/* Test if the list is empty */ |
| 127 | -static __inline__ int ylist_empty(struct ylist_head *entry) |
| 128 | -{ |
| 129 | - return (entry->next == entry); |
| 130 | -} |
| 131 | - |
| 132 | - |
| 133 | -/* ylist_entry takes a pointer to a list entry and offsets it to that |
| 134 | - * we can find a pointer to the object it is embedded in. |
| 135 | - */ |
| 136 | - |
| 137 | - |
| 138 | -#define ylist_entry(entry, type, member) \ |
| 139 | - ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) |
| 140 | - |
| 141 | - |
| 142 | -/* ylist_for_each and list_for_each_safe iterate over lists. |
| 143 | - * ylist_for_each_safe uses temporary storage to make the list delete safe |
| 144 | - */ |
| 145 | - |
| 146 | -#define ylist_for_each(itervar, list) \ |
| 147 | - for (itervar = (list)->next; itervar != (list); itervar = itervar->next) |
| 148 | - |
| 149 | -#define ylist_for_each_safe(itervar, saveVar, list) \ |
| 150 | - for (itervar = (list)->next, saveVar = (list)->next->next; \ |
| 151 | - itervar != (list); itervar = saveVar, saveVar = saveVar->next) |
| 152 | - |
| 153 | |
| 154 | #if !(defined __KERNEL__) |
| 155 | |
| 156 | --- a/fs/yaffs2/Kconfig |
| 157 | +++ b/fs/yaffs2/Kconfig |
| 158 | @@ -90,23 +90,15 @@ config YAFFS_AUTO_YAFFS2 |
| 159 | |
| 160 | If unsure, say Y. |
| 161 | |
| 162 | -config YAFFS_DISABLE_LAZY_LOAD |
| 163 | - bool "Disable lazy loading" |
| 164 | - depends on YAFFS_YAFFS2 |
| 165 | +config YAFFS_DISABLE_TAGS_ECC |
| 166 | + bool "Disable YAFFS from doing ECC on tags by default" |
| 167 | + depends on YAFFS_FS && YAFFS_YAFFS2 |
| 168 | default n |
| 169 | help |
| 170 | - "Lazy loading" defers loading file details until they are |
| 171 | - required. This saves mount time, but makes the first look-up |
| 172 | - a bit longer. |
| 173 | - |
| 174 | - Lazy loading will only happen if enabled by this option being 'n' |
| 175 | - and if the appropriate tags are available, else yaffs2 will |
| 176 | - automatically fall back to immediate loading and do the right |
| 177 | - thing. |
| 178 | - |
| 179 | - Lazy laoding will be required by checkpointing. |
| 180 | - |
| 181 | - Setting this to 'y' will disable lazy loading. |
| 182 | + This defaults Yaffs to using its own ECC calculations on tags instead of |
| 183 | + just relying on the MTD. |
| 184 | + This behavior can also be overridden with tags_ecc_on and |
| 185 | + tags_ecc_off mount options. |
| 186 | |
| 187 | If unsure, say N. |
| 188 | |
| 189 | @@ -154,3 +146,45 @@ config YAFFS_SHORT_NAMES_IN_RAM |
| 190 | but makes look-ups faster. |
| 191 | |
| 192 | If unsure, say Y. |
| 193 | + |
| 194 | +config YAFFS_EMPTY_LOST_AND_FOUND |
| 195 | + bool "Empty lost and found on boot" |
| 196 | + depends on YAFFS_FS |
| 197 | + default n |
| 198 | + help |
| 199 | + If this is enabled then the contents of lost and found is |
| 200 | + automatically dumped at mount. |
| 201 | + |
| 202 | + If unsure, say N. |
| 203 | + |
| 204 | +config YAFFS_DISABLE_BLOCK_REFRESHING |
| 205 | + bool "Disable yaffs2 block refreshing" |
| 206 | + depends on YAFFS_FS |
| 207 | + default n |
| 208 | + help |
| 209 | + If this is set, then block refreshing is disabled. |
| 210 | + Block refreshing infrequently refreshes the oldest block in |
| 211 | + a yaffs2 file system. This mechanism helps to refresh flash to |
| 212 | + mitigate against data loss. This is particularly useful for MLC. |
| 213 | + |
| 214 | + If unsure, say N. |
| 215 | + |
| 216 | +config YAFFS_DISABLE_BACKGROUND |
| 217 | + bool "Disable yaffs2 background processing" |
| 218 | + depends on YAFFS_FS |
| 219 | + default n |
| 220 | + help |
| 221 | + If this is set, then background processing is disabled. |
| 222 | + Background processing makes many foreground activities faster. |
| 223 | + |
| 224 | + If unsure, say N. |
| 225 | + |
| 226 | +config YAFFS_XATTR |
| 227 | + bool "Enable yaffs2 xattr support" |
| 228 | + depends on YAFFS_FS |
| 229 | + default y |
| 230 | + help |
| 231 | + If this is set then yaffs2 will provide xattr support. |
| 232 | + If unsure, say Y. |
| 233 | + |
| 234 | + |
| 235 | --- a/fs/yaffs2/Makefile |
| 236 | +++ b/fs/yaffs2/Makefile |
| 237 | @@ -4,7 +4,14 @@ |
| 238 | |
| 239 | obj-$(CONFIG_YAFFS_FS) += yaffs.o |
| 240 | |
| 241 | -yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o |
| 242 | -yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o |
| 243 | +yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o |
| 244 | +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o |
| 245 | yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o |
| 246 | yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o |
| 247 | +yaffs-y += yaffs_nameval.o |
| 248 | +yaffs-y += yaffs_allocator.o |
| 249 | +yaffs-y += yaffs_yaffs1.o |
| 250 | +yaffs-y += yaffs_yaffs2.o |
| 251 | +yaffs-y += yaffs_bitmap.o |
| 252 | +yaffs-y += yaffs_verify.o |
| 253 | + |
| 254 | --- a/fs/yaffs2/moduleconfig.h |
| 255 | +++ b/fs/yaffs2/moduleconfig.h |
| 256 | @@ -1,7 +1,7 @@ |
| 257 | /* |
| 258 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 259 | * |
| 260 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 261 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 262 | * for Toby Churchill Ltd and Brightstar Engineering |
| 263 | * |
| 264 | * Created by Martin Fouts <Martin.Fouts@palmsource.com> |
| 265 | @@ -29,25 +29,46 @@ |
| 266 | /* Meaning: Yaffs does its own ECC, rather than using MTD ECC */ |
| 267 | /* #define CONFIG_YAFFS_DOES_ECC */ |
| 268 | |
| 269 | +/* Default: Selected */ |
| 270 | +/* Meaning: Yaffs does its own ECC on tags for packed tags rather than use mtd */ |
| 271 | +#define CONFIG_YAFFS_DOES_TAGS_ECC |
| 272 | + |
| 273 | /* Default: Not selected */ |
| 274 | /* Meaning: ECC byte order is 'wrong'. Only meaningful if */ |
| 275 | /* CONFIG_YAFFS_DOES_ECC is set */ |
| 276 | /* #define CONFIG_YAFFS_ECC_WRONG_ORDER */ |
| 277 | |
| 278 | -/* Default: Selected */ |
| 279 | -/* Meaning: Disables testing whether chunks are erased before writing to them*/ |
| 280 | -#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK |
| 281 | +/* Default: Not selected */ |
| 282 | +/* Meaning: Always test whether chunks are erased before writing to them. |
| 283 | + Use during mtd debugging and init. */ |
| 284 | +/* #define CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED */ |
| 285 | + |
| 286 | +/* Default: Not Selected */ |
| 287 | +/* Meaning: At mount automatically empty all files from lost and found. */ |
| 288 | +/* This is done to fix an old problem where rmdir was not checking for an */ |
| 289 | +/* empty directory. This can also be achieved with a mount option. */ |
| 290 | +#define CONFIG_YAFFS_EMPTY_LOST_AND_FOUND |
| 291 | |
| 292 | /* Default: Selected */ |
| 293 | /* Meaning: Cache short names, taking more RAM, but faster look-ups */ |
| 294 | #define CONFIG_YAFFS_SHORT_NAMES_IN_RAM |
| 295 | |
| 296 | -/* Default: 10 */ |
| 297 | -/* Meaning: set the count of blocks to reserve for checkpointing */ |
| 298 | -#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10 |
| 299 | +/* Default: Unselected */ |
| 300 | +/* Meaning: Select to disable block refreshing. */ |
| 301 | +/* Block Refreshing periodically rewrites the oldest block. */ |
| 302 | +/* #define CONFIG_DISABLE_BLOCK_REFRESHING */ |
| 303 | + |
| 304 | +/* Default: Unselected */ |
| 305 | +/* Meaning: Select to disable background processing */ |
| 306 | +/* #define CONFIG_DISABLE_BACKGROUND */ |
| 307 | + |
| 308 | + |
| 309 | +/* Default: Selected */ |
| 310 | +/* Meaning: Enable XATTR support */ |
| 311 | +#define CONFIG_YAFFS_XATTR |
| 312 | |
| 313 | /* |
| 314 | -Older-style on-NAND data format has a "pageStatus" byte to record |
| 315 | +Older-style on-NAND data format has a "page_status" byte to record |
| 316 | chunk/page state. This byte is zeroed when the page is discarded. |
| 317 | Choose this option if you have existing on-NAND data in this format |
| 318 | that you need to continue to support. New data written also uses the |
| 319 | @@ -57,7 +78,7 @@ adjusted to use the older-style format. |
| 320 | MTD versions in yaffs_mtdif1.c. |
| 321 | */ |
| 322 | /* Default: Not selected */ |
| 323 | -/* Meaning: Use older-style on-NAND data format with pageStatus byte */ |
| 324 | +/* Meaning: Use older-style on-NAND data format with page_status byte */ |
| 325 | /* #define CONFIG_YAFFS_9BYTE_TAGS */ |
| 326 | |
| 327 | #endif /* YAFFS_OUT_OF_TREE */ |
| 328 | --- /dev/null |
| 329 | +++ b/fs/yaffs2/yaffs_allocator.c |
| 330 | @@ -0,0 +1,409 @@ |
| 331 | +/* |
| 332 | + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 333 | + * |
| 334 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 335 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 336 | + * |
| 337 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 338 | + * |
| 339 | + * This program is free software; you can redistribute it and/or modify |
| 340 | + * it under the terms of the GNU Lesser General Public License version 2.1 as |
| 341 | + * published by the Free Software Foundation. |
| 342 | + * |
| 343 | + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| 344 | + */ |
| 345 | + |
| 346 | + |
| 347 | +#include "yaffs_allocator.h" |
| 348 | +#include "yaffs_guts.h" |
| 349 | +#include "yaffs_trace.h" |
| 350 | +#include "yportenv.h" |
| 351 | + |
| 352 | +#ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR |
| 353 | + |
| 354 | +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev) |
| 355 | +{ |
| 356 | + dev = dev; |
| 357 | +} |
| 358 | + |
| 359 | +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev) |
| 360 | +{ |
| 361 | + dev = dev; |
| 362 | +} |
| 363 | + |
| 364 | +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev) |
| 365 | +{ |
| 366 | + return (yaffs_tnode_t *)YMALLOC(dev->tnode_size); |
| 367 | +} |
| 368 | + |
| 369 | +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn) |
| 370 | +{ |
| 371 | + dev = dev; |
| 372 | + YFREE(tn); |
| 373 | +} |
| 374 | + |
| 375 | +void yaffs_init_raw_objs(yaffs_dev_t *dev) |
| 376 | +{ |
| 377 | + dev = dev; |
| 378 | +} |
| 379 | + |
| 380 | +void yaffs_deinit_raw_objs(yaffs_dev_t *dev) |
| 381 | +{ |
| 382 | + dev = dev; |
| 383 | +} |
| 384 | + |
| 385 | +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev) |
| 386 | +{ |
| 387 | + dev = dev; |
| 388 | + return (yaffs_obj_t *) YMALLOC(sizeof(yaffs_obj_t)); |
| 389 | +} |
| 390 | + |
| 391 | + |
| 392 | +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj) |
| 393 | +{ |
| 394 | + |
| 395 | + dev = dev; |
| 396 | + YFREE(obj); |
| 397 | +} |
| 398 | + |
| 399 | +#else |
| 400 | + |
| 401 | +struct yaffs_tnode_list { |
| 402 | + struct yaffs_tnode_list *next; |
| 403 | + yaffs_tnode_t *tnodes; |
| 404 | +}; |
| 405 | + |
| 406 | +typedef struct yaffs_tnode_list yaffs_tnodelist_t; |
| 407 | + |
| 408 | +struct yaffs_obj_tList_struct { |
| 409 | + yaffs_obj_t *objects; |
| 410 | + struct yaffs_obj_tList_struct *next; |
| 411 | +}; |
| 412 | + |
| 413 | +typedef struct yaffs_obj_tList_struct yaffs_obj_tList; |
| 414 | + |
| 415 | + |
| 416 | +struct yaffs_AllocatorStruct { |
| 417 | + int n_tnodesCreated; |
| 418 | + yaffs_tnode_t *freeTnodes; |
| 419 | + int nFreeTnodes; |
| 420 | + yaffs_tnodelist_t *allocatedTnodeList; |
| 421 | + |
| 422 | + int n_objCreated; |
| 423 | + yaffs_obj_t *freeObjects; |
| 424 | + int nFreeObjects; |
| 425 | + |
| 426 | + yaffs_obj_tList *allocatedObjectList; |
| 427 | +}; |
| 428 | + |
| 429 | +typedef struct yaffs_AllocatorStruct yaffs_Allocator; |
| 430 | + |
| 431 | + |
| 432 | +static void yaffs_deinit_raw_tnodes(yaffs_dev_t *dev) |
| 433 | +{ |
| 434 | + |
| 435 | + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; |
| 436 | + |
| 437 | + yaffs_tnodelist_t *tmp; |
| 438 | + |
| 439 | + if(!allocator){ |
| 440 | + YBUG(); |
| 441 | + return; |
| 442 | + } |
| 443 | + |
| 444 | + while (allocator->allocatedTnodeList) { |
| 445 | + tmp = allocator->allocatedTnodeList->next; |
| 446 | + |
| 447 | + YFREE(allocator->allocatedTnodeList->tnodes); |
| 448 | + YFREE(allocator->allocatedTnodeList); |
| 449 | + allocator->allocatedTnodeList = tmp; |
| 450 | + |
| 451 | + } |
| 452 | + |
| 453 | + allocator->freeTnodes = NULL; |
| 454 | + allocator->nFreeTnodes = 0; |
| 455 | + allocator->n_tnodesCreated = 0; |
| 456 | +} |
| 457 | + |
| 458 | +static void yaffs_init_raw_tnodes(yaffs_dev_t *dev) |
| 459 | +{ |
| 460 | + yaffs_Allocator *allocator = dev->allocator; |
| 461 | + |
| 462 | + if(allocator){ |
| 463 | + allocator->allocatedTnodeList = NULL; |
| 464 | + allocator->freeTnodes = NULL; |
| 465 | + allocator->nFreeTnodes = 0; |
| 466 | + allocator->n_tnodesCreated = 0; |
| 467 | + } else |
| 468 | + YBUG(); |
| 469 | +} |
| 470 | + |
| 471 | +static int yaffs_create_tnodes(yaffs_dev_t *dev, int n_tnodes) |
| 472 | +{ |
| 473 | + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; |
| 474 | + int i; |
| 475 | + yaffs_tnode_t *newTnodes; |
| 476 | + __u8 *mem; |
| 477 | + yaffs_tnode_t *curr; |
| 478 | + yaffs_tnode_t *next; |
| 479 | + yaffs_tnodelist_t *tnl; |
| 480 | + |
| 481 | + if(!allocator){ |
| 482 | + YBUG(); |
| 483 | + return YAFFS_FAIL; |
| 484 | + } |
| 485 | + |
| 486 | + if (n_tnodes < 1) |
| 487 | + return YAFFS_OK; |
| 488 | + |
| 489 | + |
| 490 | + /* make these things */ |
| 491 | + |
| 492 | + newTnodes = YMALLOC(n_tnodes * dev->tnode_size); |
| 493 | + mem = (__u8 *)newTnodes; |
| 494 | + |
| 495 | + if (!newTnodes) { |
| 496 | + T(YAFFS_TRACE_ERROR, |
| 497 | + (TSTR("yaffs: Could not allocate Tnodes" TENDSTR))); |
| 498 | + return YAFFS_FAIL; |
| 499 | + } |
| 500 | + |
| 501 | + /* New hookup for wide tnodes */ |
| 502 | + for (i = 0; i < n_tnodes - 1; i++) { |
| 503 | + curr = (yaffs_tnode_t *) &mem[i * dev->tnode_size]; |
| 504 | + next = (yaffs_tnode_t *) &mem[(i+1) * dev->tnode_size]; |
| 505 | + curr->internal[0] = next; |
| 506 | + } |
| 507 | + |
| 508 | + curr = (yaffs_tnode_t *) &mem[(n_tnodes - 1) * dev->tnode_size]; |
| 509 | + curr->internal[0] = allocator->freeTnodes; |
| 510 | + allocator->freeTnodes = (yaffs_tnode_t *)mem; |
| 511 | + |
| 512 | + allocator->nFreeTnodes += n_tnodes; |
| 513 | + allocator->n_tnodesCreated += n_tnodes; |
| 514 | + |
| 515 | + /* Now add this bunch of tnodes to a list for freeing up. |
| 516 | + * NB If we can't add this to the management list it isn't fatal |
| 517 | + * but it just means we can't free this bunch of tnodes later. |
| 518 | + */ |
| 519 | + |
| 520 | + tnl = YMALLOC(sizeof(yaffs_tnodelist_t)); |
| 521 | + if (!tnl) { |
| 522 | + T(YAFFS_TRACE_ERROR, |
| 523 | + (TSTR |
| 524 | + ("yaffs: Could not add tnodes to management list" TENDSTR))); |
| 525 | + return YAFFS_FAIL; |
| 526 | + } else { |
| 527 | + tnl->tnodes = newTnodes; |
| 528 | + tnl->next = allocator->allocatedTnodeList; |
| 529 | + allocator->allocatedTnodeList = tnl; |
| 530 | + } |
| 531 | + |
| 532 | + T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR))); |
| 533 | + |
| 534 | + return YAFFS_OK; |
| 535 | +} |
| 536 | + |
| 537 | + |
| 538 | +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev) |
| 539 | +{ |
| 540 | + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; |
| 541 | + yaffs_tnode_t *tn = NULL; |
| 542 | + |
| 543 | + if(!allocator){ |
| 544 | + YBUG(); |
| 545 | + return NULL; |
| 546 | + } |
| 547 | + |
| 548 | + /* If there are none left make more */ |
| 549 | + if (!allocator->freeTnodes) |
| 550 | + yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES); |
| 551 | + |
| 552 | + if (allocator->freeTnodes) { |
| 553 | + tn = allocator->freeTnodes; |
| 554 | + allocator->freeTnodes = allocator->freeTnodes->internal[0]; |
| 555 | + allocator->nFreeTnodes--; |
| 556 | + } |
| 557 | + |
| 558 | + return tn; |
| 559 | +} |
| 560 | + |
| 561 | +/* FreeTnode frees up a tnode and puts it back on the free list */ |
| 562 | +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn) |
| 563 | +{ |
| 564 | + yaffs_Allocator *allocator = dev->allocator; |
| 565 | + |
| 566 | + if(!allocator){ |
| 567 | + YBUG(); |
| 568 | + return; |
| 569 | + } |
| 570 | + |
| 571 | + if (tn) { |
| 572 | + tn->internal[0] = allocator->freeTnodes; |
| 573 | + allocator->freeTnodes = tn; |
| 574 | + allocator->nFreeTnodes++; |
| 575 | + } |
| 576 | + dev->checkpoint_blocks_required = 0; /* force recalculation*/ |
| 577 | +} |
| 578 | + |
| 579 | + |
| 580 | + |
| 581 | +static void yaffs_init_raw_objs(yaffs_dev_t *dev) |
| 582 | +{ |
| 583 | + yaffs_Allocator *allocator = dev->allocator; |
| 584 | + |
| 585 | + if(allocator) { |
| 586 | + allocator->allocatedObjectList = NULL; |
| 587 | + allocator->freeObjects = NULL; |
| 588 | + allocator->nFreeObjects = 0; |
| 589 | + } else |
| 590 | + YBUG(); |
| 591 | +} |
| 592 | + |
| 593 | +static void yaffs_deinit_raw_objs(yaffs_dev_t *dev) |
| 594 | +{ |
| 595 | + yaffs_Allocator *allocator = dev->allocator; |
| 596 | + yaffs_obj_tList *tmp; |
| 597 | + |
| 598 | + if(!allocator){ |
| 599 | + YBUG(); |
| 600 | + return; |
| 601 | + } |
| 602 | + |
| 603 | + while (allocator->allocatedObjectList) { |
| 604 | + tmp = allocator->allocatedObjectList->next; |
| 605 | + YFREE(allocator->allocatedObjectList->objects); |
| 606 | + YFREE(allocator->allocatedObjectList); |
| 607 | + |
| 608 | + allocator->allocatedObjectList = tmp; |
| 609 | + } |
| 610 | + |
| 611 | + allocator->freeObjects = NULL; |
| 612 | + allocator->nFreeObjects = 0; |
| 613 | + allocator->n_objCreated = 0; |
| 614 | +} |
| 615 | + |
| 616 | + |
| 617 | +static int yaffs_create_free_objs(yaffs_dev_t *dev, int n_obj) |
| 618 | +{ |
| 619 | + yaffs_Allocator *allocator = dev->allocator; |
| 620 | + |
| 621 | + int i; |
| 622 | + yaffs_obj_t *newObjects; |
| 623 | + yaffs_obj_tList *list; |
| 624 | + |
| 625 | + if(!allocator){ |
| 626 | + YBUG(); |
| 627 | + return YAFFS_FAIL; |
| 628 | + } |
| 629 | + |
| 630 | + if (n_obj < 1) |
| 631 | + return YAFFS_OK; |
| 632 | + |
| 633 | + /* make these things */ |
| 634 | + newObjects = YMALLOC(n_obj * sizeof(yaffs_obj_t)); |
| 635 | + list = YMALLOC(sizeof(yaffs_obj_tList)); |
| 636 | + |
| 637 | + if (!newObjects || !list) { |
| 638 | + if (newObjects){ |
| 639 | + YFREE(newObjects); |
| 640 | + newObjects = NULL; |
| 641 | + } |
| 642 | + if (list){ |
| 643 | + YFREE(list); |
| 644 | + list = NULL; |
| 645 | + } |
| 646 | + T(YAFFS_TRACE_ALLOCATE, |
| 647 | + (TSTR("yaffs: Could not allocate more objects" TENDSTR))); |
| 648 | + return YAFFS_FAIL; |
| 649 | + } |
| 650 | + |
| 651 | + /* Hook them into the free list */ |
| 652 | + for (i = 0; i < n_obj - 1; i++) { |
| 653 | + newObjects[i].siblings.next = |
| 654 | + (struct ylist_head *)(&newObjects[i + 1]); |
| 655 | + } |
| 656 | + |
| 657 | + newObjects[n_obj - 1].siblings.next = (void *)allocator->freeObjects; |
| 658 | + allocator->freeObjects = newObjects; |
| 659 | + allocator->nFreeObjects += n_obj; |
| 660 | + allocator->n_objCreated += n_obj; |
| 661 | + |
| 662 | + /* Now add this bunch of Objects to a list for freeing up. */ |
| 663 | + |
| 664 | + list->objects = newObjects; |
| 665 | + list->next = allocator->allocatedObjectList; |
| 666 | + allocator->allocatedObjectList = list; |
| 667 | + |
| 668 | + return YAFFS_OK; |
| 669 | +} |
| 670 | + |
| 671 | +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev) |
| 672 | +{ |
| 673 | + yaffs_obj_t *obj = NULL; |
| 674 | + yaffs_Allocator *allocator = dev->allocator; |
| 675 | + |
| 676 | + if(!allocator) { |
| 677 | + YBUG(); |
| 678 | + return obj; |
| 679 | + } |
| 680 | + |
| 681 | + /* If there are none left make more */ |
| 682 | + if (!allocator->freeObjects) |
| 683 | + yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS); |
| 684 | + |
| 685 | + if (allocator->freeObjects) { |
| 686 | + obj = allocator->freeObjects; |
| 687 | + allocator->freeObjects = |
| 688 | + (yaffs_obj_t *) (allocator->freeObjects->siblings.next); |
| 689 | + allocator->nFreeObjects--; |
| 690 | + } |
| 691 | + |
| 692 | + return obj; |
| 693 | +} |
| 694 | + |
| 695 | + |
| 696 | +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj) |
| 697 | +{ |
| 698 | + |
| 699 | + yaffs_Allocator *allocator = dev->allocator; |
| 700 | + |
| 701 | + if(!allocator) |
| 702 | + YBUG(); |
| 703 | + else { |
| 704 | + /* Link into the free list. */ |
| 705 | + obj->siblings.next = (struct ylist_head *)(allocator->freeObjects); |
| 706 | + allocator->freeObjects = obj; |
| 707 | + allocator->nFreeObjects++; |
| 708 | + } |
| 709 | +} |
| 710 | + |
| 711 | +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev) |
| 712 | +{ |
| 713 | + if(dev->allocator){ |
| 714 | + yaffs_deinit_raw_tnodes(dev); |
| 715 | + yaffs_deinit_raw_objs(dev); |
| 716 | + |
| 717 | + YFREE(dev->allocator); |
| 718 | + dev->allocator=NULL; |
| 719 | + } else |
| 720 | + YBUG(); |
| 721 | +} |
| 722 | + |
| 723 | +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev) |
| 724 | +{ |
| 725 | + yaffs_Allocator *allocator; |
| 726 | + |
| 727 | + if(!dev->allocator){ |
| 728 | + allocator = YMALLOC(sizeof(yaffs_Allocator)); |
| 729 | + if(allocator){ |
| 730 | + dev->allocator = allocator; |
| 731 | + yaffs_init_raw_tnodes(dev); |
| 732 | + yaffs_init_raw_objs(dev); |
| 733 | + } |
| 734 | + } else |
| 735 | + YBUG(); |
| 736 | +} |
| 737 | + |
| 738 | + |
| 739 | +#endif |
| 740 | --- /dev/null |
| 741 | +++ b/fs/yaffs2/yaffs_allocator.h |
| 742 | @@ -0,0 +1,30 @@ |
| 743 | +/* |
| 744 | + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 745 | + * |
| 746 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 747 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 748 | + * |
| 749 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 750 | + * |
| 751 | + * This program is free software; you can redistribute it and/or modify |
| 752 | + * it under the terms of the GNU Lesser General Public License version 2.1 as |
| 753 | + * published by the Free Software Foundation. |
| 754 | + * |
| 755 | + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| 756 | + */ |
| 757 | + |
| 758 | +#ifndef __YAFFS_ALLOCATOR_H__ |
| 759 | +#define __YAFFS_ALLOCATOR_H__ |
| 760 | + |
| 761 | +#include "yaffs_guts.h" |
| 762 | + |
| 763 | +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev); |
| 764 | +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev); |
| 765 | + |
| 766 | +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev); |
| 767 | +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn); |
| 768 | + |
| 769 | +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev); |
| 770 | +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj); |
| 771 | + |
| 772 | +#endif |
| 773 | --- /dev/null |
| 774 | +++ b/fs/yaffs2/yaffs_bitmap.c |
| 775 | @@ -0,0 +1,105 @@ |
| 776 | +/* |
| 777 | + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 778 | + * |
| 779 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 780 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 781 | + * |
| 782 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 783 | + * |
| 784 | + * This program is free software; you can redistribute it and/or modify |
| 785 | + * it under the terms of the GNU General Public License version 2 as |
| 786 | + * published by the Free Software Foundation. |
| 787 | + */ |
| 788 | + |
| 789 | +#include "yaffs_bitmap.h" |
| 790 | +#include "yaffs_trace.h" |
| 791 | +/* |
| 792 | + * Chunk bitmap manipulations |
| 793 | + */ |
| 794 | + |
| 795 | +static Y_INLINE __u8 *yaffs_BlockBits(yaffs_dev_t *dev, int blk) |
| 796 | +{ |
| 797 | + if (blk < dev->internal_start_block || blk > dev->internal_end_block) { |
| 798 | + T(YAFFS_TRACE_ERROR, |
| 799 | + (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), |
| 800 | + blk)); |
| 801 | + YBUG(); |
| 802 | + } |
| 803 | + return dev->chunk_bits + |
| 804 | + (dev->chunk_bit_stride * (blk - dev->internal_start_block)); |
| 805 | +} |
| 806 | + |
| 807 | +void yaffs_verify_chunk_bit_id(yaffs_dev_t *dev, int blk, int chunk) |
| 808 | +{ |
| 809 | + if (blk < dev->internal_start_block || blk > dev->internal_end_block || |
| 810 | + chunk < 0 || chunk >= dev->param.chunks_per_block) { |
| 811 | + T(YAFFS_TRACE_ERROR, |
| 812 | + (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR), |
| 813 | + blk, chunk)); |
| 814 | + YBUG(); |
| 815 | + } |
| 816 | +} |
| 817 | + |
| 818 | +void yaffs_clear_chunk_bits(yaffs_dev_t *dev, int blk) |
| 819 | +{ |
| 820 | + __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 821 | + |
| 822 | + memset(blkBits, 0, dev->chunk_bit_stride); |
| 823 | +} |
| 824 | + |
| 825 | +void yaffs_clear_chunk_bit(yaffs_dev_t *dev, int blk, int chunk) |
| 826 | +{ |
| 827 | + __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 828 | + |
| 829 | + yaffs_verify_chunk_bit_id(dev, blk, chunk); |
| 830 | + |
| 831 | + blkBits[chunk / 8] &= ~(1 << (chunk & 7)); |
| 832 | +} |
| 833 | + |
| 834 | +void yaffs_set_chunk_bit(yaffs_dev_t *dev, int blk, int chunk) |
| 835 | +{ |
| 836 | + __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 837 | + |
| 838 | + yaffs_verify_chunk_bit_id(dev, blk, chunk); |
| 839 | + |
| 840 | + blkBits[chunk / 8] |= (1 << (chunk & 7)); |
| 841 | +} |
| 842 | + |
| 843 | +int yaffs_check_chunk_bit(yaffs_dev_t *dev, int blk, int chunk) |
| 844 | +{ |
| 845 | + __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 846 | + yaffs_verify_chunk_bit_id(dev, blk, chunk); |
| 847 | + |
| 848 | + return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; |
| 849 | +} |
| 850 | + |
| 851 | +int yaffs_still_some_chunks(yaffs_dev_t *dev, int blk) |
| 852 | +{ |
| 853 | + __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 854 | + int i; |
| 855 | + for (i = 0; i < dev->chunk_bit_stride; i++) { |
| 856 | + if (*blkBits) |
| 857 | + return 1; |
| 858 | + blkBits++; |
| 859 | + } |
| 860 | + return 0; |
| 861 | +} |
| 862 | + |
| 863 | +int yaffs_count_chunk_bits(yaffs_dev_t *dev, int blk) |
| 864 | +{ |
| 865 | + __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 866 | + int i; |
| 867 | + int n = 0; |
| 868 | + for (i = 0; i < dev->chunk_bit_stride; i++) { |
| 869 | + __u8 x = *blkBits; |
| 870 | + while (x) { |
| 871 | + if (x & 1) |
| 872 | + n++; |
| 873 | + x >>= 1; |
| 874 | + } |
| 875 | + |
| 876 | + blkBits++; |
| 877 | + } |
| 878 | + return n; |
| 879 | +} |
| 880 | + |
| 881 | --- /dev/null |
| 882 | +++ b/fs/yaffs2/yaffs_bitmap.h |
| 883 | @@ -0,0 +1,31 @@ |
| 884 | +/* |
| 885 | + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 886 | + * |
| 887 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 888 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 889 | + * |
| 890 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 891 | + * |
| 892 | + * This program is free software; you can redistribute it and/or modify |
| 893 | + * it under the terms of the GNU General Public License version 2 as |
| 894 | + * published by the Free Software Foundation. |
| 895 | + */ |
| 896 | + |
| 897 | +/* |
| 898 | + * Chunk bitmap manipulations |
| 899 | + */ |
| 900 | + |
| 901 | +#ifndef __YAFFS_BITMAP_H__ |
| 902 | +#define __YAFFS_BITMAP_H__ |
| 903 | + |
| 904 | +#include "yaffs_guts.h" |
| 905 | + |
| 906 | +void yaffs_verify_chunk_bit_id(yaffs_dev_t *dev, int blk, int chunk); |
| 907 | +void yaffs_clear_chunk_bits(yaffs_dev_t *dev, int blk); |
| 908 | +void yaffs_clear_chunk_bit(yaffs_dev_t *dev, int blk, int chunk); |
| 909 | +void yaffs_set_chunk_bit(yaffs_dev_t *dev, int blk, int chunk); |
| 910 | +int yaffs_check_chunk_bit(yaffs_dev_t *dev, int blk, int chunk); |
| 911 | +int yaffs_still_some_chunks(yaffs_dev_t *dev, int blk); |
| 912 | +int yaffs_count_chunk_bits(yaffs_dev_t *dev, int blk); |
| 913 | + |
| 914 | +#endif |
| 915 | --- a/fs/yaffs2/yaffs_checkptrw.c |
| 916 | +++ b/fs/yaffs2/yaffs_checkptrw.c |
| 917 | @@ -1,7 +1,7 @@ |
| 918 | /* |
| 919 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 920 | * |
| 921 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 922 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 923 | * for Toby Churchill Ltd and Brightstar Engineering |
| 924 | * |
| 925 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 926 | @@ -11,16 +11,12 @@ |
| 927 | * published by the Free Software Foundation. |
| 928 | */ |
| 929 | |
| 930 | -const char *yaffs_checkptrw_c_version = |
| 931 | - "$Id: yaffs_checkptrw.c,v 1.18 2009-03-06 17:20:49 wookey Exp $"; |
| 932 | - |
| 933 | - |
| 934 | #include "yaffs_checkptrw.h" |
| 935 | #include "yaffs_getblockinfo.h" |
| 936 | |
| 937 | -static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) |
| 938 | +static int yaffs2_checkpt_space_ok(yaffs_dev_t *dev) |
| 939 | { |
| 940 | - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; |
| 941 | + int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks; |
| 942 | |
| 943 | T(YAFFS_TRACE_CHECKPOINT, |
| 944 | (TSTR("checkpt blocks available = %d" TENDSTR), |
| 945 | @@ -30,53 +26,56 @@ static int yaffs_CheckpointSpaceOk(yaffs |
| 946 | } |
| 947 | |
| 948 | |
| 949 | -static int yaffs_CheckpointErase(yaffs_Device *dev) |
| 950 | +static int yaffs_checkpt_erase(yaffs_dev_t *dev) |
| 951 | { |
| 952 | int i; |
| 953 | |
| 954 | - if (!dev->eraseBlockInNAND) |
| 955 | + if (!dev->param.erase_fn) |
| 956 | return 0; |
| 957 | T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR), |
| 958 | - dev->internalStartBlock, dev->internalEndBlock)); |
| 959 | + dev->internal_start_block, dev->internal_end_block)); |
| 960 | |
| 961 | - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { |
| 962 | - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); |
| 963 | - if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) { |
| 964 | + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { |
| 965 | + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i); |
| 966 | + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { |
| 967 | T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i)); |
| 968 | - if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) { |
| 969 | - bi->blockState = YAFFS_BLOCK_STATE_EMPTY; |
| 970 | - dev->nErasedBlocks++; |
| 971 | - dev->nFreeChunks += dev->nChunksPerBlock; |
| 972 | + |
| 973 | + dev->n_erasures++; |
| 974 | + |
| 975 | + if (dev->param.erase_fn(dev, i - dev->block_offset /* realign */)) { |
| 976 | + bi->block_state = YAFFS_BLOCK_STATE_EMPTY; |
| 977 | + dev->n_erased_blocks++; |
| 978 | + dev->n_free_chunks += dev->param.chunks_per_block; |
| 979 | } else { |
| 980 | - dev->markNANDBlockBad(dev, i); |
| 981 | - bi->blockState = YAFFS_BLOCK_STATE_DEAD; |
| 982 | + dev->param.bad_block_fn(dev, i); |
| 983 | + bi->block_state = YAFFS_BLOCK_STATE_DEAD; |
| 984 | } |
| 985 | } |
| 986 | } |
| 987 | |
| 988 | - dev->blocksInCheckpoint = 0; |
| 989 | + dev->blocks_in_checkpt = 0; |
| 990 | |
| 991 | return 1; |
| 992 | } |
| 993 | |
| 994 | |
| 995 | -static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev) |
| 996 | +static void yaffs2_checkpt_find_erased_block(yaffs_dev_t *dev) |
| 997 | { |
| 998 | int i; |
| 999 | - int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; |
| 1000 | + int blocksAvailable = dev->n_erased_blocks - dev->param.n_reserved_blocks; |
| 1001 | T(YAFFS_TRACE_CHECKPOINT, |
| 1002 | (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), |
| 1003 | - dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock)); |
| 1004 | + dev->n_erased_blocks, dev->param.n_reserved_blocks, blocksAvailable, dev->checkpt_next_block)); |
| 1005 | |
| 1006 | - if (dev->checkpointNextBlock >= 0 && |
| 1007 | - dev->checkpointNextBlock <= dev->internalEndBlock && |
| 1008 | + if (dev->checkpt_next_block >= 0 && |
| 1009 | + dev->checkpt_next_block <= dev->internal_end_block && |
| 1010 | blocksAvailable > 0) { |
| 1011 | |
| 1012 | - for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) { |
| 1013 | - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); |
| 1014 | - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { |
| 1015 | - dev->checkpointNextBlock = i + 1; |
| 1016 | - dev->checkpointCurrentBlock = i; |
| 1017 | + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) { |
| 1018 | + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i); |
| 1019 | + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { |
| 1020 | + dev->checkpt_next_block = i + 1; |
| 1021 | + dev->checkpt_cur_block = i; |
| 1022 | T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i)); |
| 1023 | return; |
| 1024 | } |
| 1025 | @@ -84,34 +83,34 @@ static void yaffs_CheckpointFindNextEras |
| 1026 | } |
| 1027 | T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR))); |
| 1028 | |
| 1029 | - dev->checkpointNextBlock = -1; |
| 1030 | - dev->checkpointCurrentBlock = -1; |
| 1031 | + dev->checkpt_next_block = -1; |
| 1032 | + dev->checkpt_cur_block = -1; |
| 1033 | } |
| 1034 | |
| 1035 | -static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) |
| 1036 | +static void yaffs2_checkpt_find_block(yaffs_dev_t *dev) |
| 1037 | { |
| 1038 | int i; |
| 1039 | - yaffs_ExtendedTags tags; |
| 1040 | + yaffs_ext_tags tags; |
| 1041 | |
| 1042 | T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR), |
| 1043 | - dev->blocksInCheckpoint, dev->checkpointNextBlock)); |
| 1044 | + dev->blocks_in_checkpt, dev->checkpt_next_block)); |
| 1045 | |
| 1046 | - if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks) |
| 1047 | - for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) { |
| 1048 | - int chunk = i * dev->nChunksPerBlock; |
| 1049 | - int realignedChunk = chunk - dev->chunkOffset; |
| 1050 | + if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) |
| 1051 | + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) { |
| 1052 | + int chunk = i * dev->param.chunks_per_block; |
| 1053 | + int realignedChunk = chunk - dev->chunk_offset; |
| 1054 | |
| 1055 | - dev->readChunkWithTagsFromNAND(dev, realignedChunk, |
| 1056 | + dev->param.read_chunk_tags_fn(dev, realignedChunk, |
| 1057 | NULL, &tags); |
| 1058 | T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR), |
| 1059 | - i, tags.objectId, tags.sequenceNumber, tags.eccResult)); |
| 1060 | + i, tags.obj_id, tags.seq_number, tags.ecc_result)); |
| 1061 | |
| 1062 | - if (tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) { |
| 1063 | + if (tags.seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) { |
| 1064 | /* Right kind of block */ |
| 1065 | - dev->checkpointNextBlock = tags.objectId; |
| 1066 | - dev->checkpointCurrentBlock = i; |
| 1067 | - dev->checkpointBlockList[dev->blocksInCheckpoint] = i; |
| 1068 | - dev->blocksInCheckpoint++; |
| 1069 | + dev->checkpt_next_block = tags.obj_id; |
| 1070 | + dev->checkpt_cur_block = i; |
| 1071 | + dev->checkpt_block_list[dev->blocks_in_checkpt] = i; |
| 1072 | + dev->blocks_in_checkpt++; |
| 1073 | T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i)); |
| 1074 | return; |
| 1075 | } |
| 1076 | @@ -119,122 +118,127 @@ static void yaffs_CheckpointFindNextChec |
| 1077 | |
| 1078 | T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR))); |
| 1079 | |
| 1080 | - dev->checkpointNextBlock = -1; |
| 1081 | - dev->checkpointCurrentBlock = -1; |
| 1082 | + dev->checkpt_next_block = -1; |
| 1083 | + dev->checkpt_cur_block = -1; |
| 1084 | } |
| 1085 | |
| 1086 | |
| 1087 | -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) |
| 1088 | +int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting) |
| 1089 | { |
| 1090 | |
| 1091 | + |
| 1092 | + dev->checkpt_open_write = forWriting; |
| 1093 | + |
| 1094 | /* Got the functions we need? */ |
| 1095 | - if (!dev->writeChunkWithTagsToNAND || |
| 1096 | - !dev->readChunkWithTagsFromNAND || |
| 1097 | - !dev->eraseBlockInNAND || |
| 1098 | - !dev->markNANDBlockBad) |
| 1099 | + if (!dev->param.write_chunk_tags_fn || |
| 1100 | + !dev->param.read_chunk_tags_fn || |
| 1101 | + !dev->param.erase_fn || |
| 1102 | + !dev->param.bad_block_fn) |
| 1103 | return 0; |
| 1104 | |
| 1105 | - if (forWriting && !yaffs_CheckpointSpaceOk(dev)) |
| 1106 | + if (forWriting && !yaffs2_checkpt_space_ok(dev)) |
| 1107 | return 0; |
| 1108 | |
| 1109 | - if (!dev->checkpointBuffer) |
| 1110 | - dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk); |
| 1111 | - if (!dev->checkpointBuffer) |
| 1112 | + if (!dev->checkpt_buffer) |
| 1113 | + dev->checkpt_buffer = YMALLOC_DMA(dev->param.total_bytes_per_chunk); |
| 1114 | + if (!dev->checkpt_buffer) |
| 1115 | return 0; |
| 1116 | |
| 1117 | |
| 1118 | - dev->checkpointPageSequence = 0; |
| 1119 | - |
| 1120 | - dev->checkpointOpenForWrite = forWriting; |
| 1121 | - |
| 1122 | - dev->checkpointByteCount = 0; |
| 1123 | - dev->checkpointSum = 0; |
| 1124 | - dev->checkpointXor = 0; |
| 1125 | - dev->checkpointCurrentBlock = -1; |
| 1126 | - dev->checkpointCurrentChunk = -1; |
| 1127 | - dev->checkpointNextBlock = dev->internalStartBlock; |
| 1128 | + dev->checkpt_page_seq = 0; |
| 1129 | + dev->checkpt_byte_count = 0; |
| 1130 | + dev->checkpt_sum = 0; |
| 1131 | + dev->checkpt_xor = 0; |
| 1132 | + dev->checkpt_cur_block = -1; |
| 1133 | + dev->checkpt_cur_chunk = -1; |
| 1134 | + dev->checkpt_next_block = dev->internal_start_block; |
| 1135 | |
| 1136 | /* Erase all the blocks in the checkpoint area */ |
| 1137 | if (forWriting) { |
| 1138 | - memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk); |
| 1139 | - dev->checkpointByteOffset = 0; |
| 1140 | - return yaffs_CheckpointErase(dev); |
| 1141 | + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); |
| 1142 | + dev->checkpt_byte_offs = 0; |
| 1143 | + return yaffs_checkpt_erase(dev); |
| 1144 | } else { |
| 1145 | int i; |
| 1146 | /* Set to a value that will kick off a read */ |
| 1147 | - dev->checkpointByteOffset = dev->nDataBytesPerChunk; |
| 1148 | + dev->checkpt_byte_offs = dev->data_bytes_per_chunk; |
| 1149 | /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully) |
| 1150 | * going to be way more than we need */ |
| 1151 | - dev->blocksInCheckpoint = 0; |
| 1152 | - dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2; |
| 1153 | - dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks); |
| 1154 | - for (i = 0; i < dev->checkpointMaxBlocks; i++) |
| 1155 | - dev->checkpointBlockList[i] = -1; |
| 1156 | + dev->blocks_in_checkpt = 0; |
| 1157 | + dev->checkpt_max_blocks = (dev->internal_end_block - dev->internal_start_block)/16 + 2; |
| 1158 | + dev->checkpt_block_list = YMALLOC(sizeof(int) * dev->checkpt_max_blocks); |
| 1159 | + if(!dev->checkpt_block_list) |
| 1160 | + return 0; |
| 1161 | + |
| 1162 | + for (i = 0; i < dev->checkpt_max_blocks; i++) |
| 1163 | + dev->checkpt_block_list[i] = -1; |
| 1164 | } |
| 1165 | |
| 1166 | return 1; |
| 1167 | } |
| 1168 | |
| 1169 | -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) |
| 1170 | +int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum) |
| 1171 | { |
| 1172 | __u32 compositeSum; |
| 1173 | - compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); |
| 1174 | + compositeSum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xFF); |
| 1175 | *sum = compositeSum; |
| 1176 | return 1; |
| 1177 | } |
| 1178 | |
| 1179 | -static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) |
| 1180 | +static int yaffs2_checkpt_flush_buffer(yaffs_dev_t *dev) |
| 1181 | { |
| 1182 | int chunk; |
| 1183 | int realignedChunk; |
| 1184 | |
| 1185 | - yaffs_ExtendedTags tags; |
| 1186 | + yaffs_ext_tags tags; |
| 1187 | |
| 1188 | - if (dev->checkpointCurrentBlock < 0) { |
| 1189 | - yaffs_CheckpointFindNextErasedBlock(dev); |
| 1190 | - dev->checkpointCurrentChunk = 0; |
| 1191 | + if (dev->checkpt_cur_block < 0) { |
| 1192 | + yaffs2_checkpt_find_erased_block(dev); |
| 1193 | + dev->checkpt_cur_chunk = 0; |
| 1194 | } |
| 1195 | |
| 1196 | - if (dev->checkpointCurrentBlock < 0) |
| 1197 | + if (dev->checkpt_cur_block < 0) |
| 1198 | return 0; |
| 1199 | |
| 1200 | - tags.chunkDeleted = 0; |
| 1201 | - tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */ |
| 1202 | - tags.chunkId = dev->checkpointPageSequence + 1; |
| 1203 | - tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA; |
| 1204 | - tags.byteCount = dev->nDataBytesPerChunk; |
| 1205 | - if (dev->checkpointCurrentChunk == 0) { |
| 1206 | + tags.is_deleted = 0; |
| 1207 | + tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */ |
| 1208 | + tags.chunk_id = dev->checkpt_page_seq + 1; |
| 1209 | + tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA; |
| 1210 | + tags.n_bytes = dev->data_bytes_per_chunk; |
| 1211 | + if (dev->checkpt_cur_chunk == 0) { |
| 1212 | /* First chunk we write for the block? Set block state to |
| 1213 | checkpoint */ |
| 1214 | - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock); |
| 1215 | - bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; |
| 1216 | - dev->blocksInCheckpoint++; |
| 1217 | + yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->checkpt_cur_block); |
| 1218 | + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; |
| 1219 | + dev->blocks_in_checkpt++; |
| 1220 | } |
| 1221 | |
| 1222 | - chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; |
| 1223 | + chunk = dev->checkpt_cur_block * dev->param.chunks_per_block + dev->checkpt_cur_chunk; |
| 1224 | |
| 1225 | |
| 1226 | T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), |
| 1227 | - chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk, tags.objectId, tags.chunkId)); |
| 1228 | + chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, tags.obj_id, tags.chunk_id)); |
| 1229 | |
| 1230 | - realignedChunk = chunk - dev->chunkOffset; |
| 1231 | + realignedChunk = chunk - dev->chunk_offset; |
| 1232 | |
| 1233 | - dev->writeChunkWithTagsToNAND(dev, realignedChunk, |
| 1234 | - dev->checkpointBuffer, &tags); |
| 1235 | - dev->checkpointByteOffset = 0; |
| 1236 | - dev->checkpointPageSequence++; |
| 1237 | - dev->checkpointCurrentChunk++; |
| 1238 | - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) { |
| 1239 | - dev->checkpointCurrentChunk = 0; |
| 1240 | - dev->checkpointCurrentBlock = -1; |
| 1241 | + dev->n_page_writes++; |
| 1242 | + |
| 1243 | + dev->param.write_chunk_tags_fn(dev, realignedChunk, |
| 1244 | + dev->checkpt_buffer, &tags); |
| 1245 | + dev->checkpt_byte_offs = 0; |
| 1246 | + dev->checkpt_page_seq++; |
| 1247 | + dev->checkpt_cur_chunk++; |
| 1248 | + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) { |
| 1249 | + dev->checkpt_cur_chunk = 0; |
| 1250 | + dev->checkpt_cur_block = -1; |
| 1251 | } |
| 1252 | - memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk); |
| 1253 | + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); |
| 1254 | |
| 1255 | return 1; |
| 1256 | } |
| 1257 | |
| 1258 | |
| 1259 | -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes) |
| 1260 | +int yaffs2_checkpt_wr(yaffs_dev_t *dev, const void *data, int n_bytes) |
| 1261 | { |
| 1262 | int i = 0; |
| 1263 | int ok = 1; |
| 1264 | @@ -244,36 +248,36 @@ int yaffs_CheckpointWrite(yaffs_Device * |
| 1265 | |
| 1266 | |
| 1267 | |
| 1268 | - if (!dev->checkpointBuffer) |
| 1269 | + if (!dev->checkpt_buffer) |
| 1270 | return 0; |
| 1271 | |
| 1272 | - if (!dev->checkpointOpenForWrite) |
| 1273 | + if (!dev->checkpt_open_write) |
| 1274 | return -1; |
| 1275 | |
| 1276 | - while (i < nBytes && ok) { |
| 1277 | - dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes; |
| 1278 | - dev->checkpointSum += *dataBytes; |
| 1279 | - dev->checkpointXor ^= *dataBytes; |
| 1280 | + while (i < n_bytes && ok) { |
| 1281 | + dev->checkpt_buffer[dev->checkpt_byte_offs] = *dataBytes; |
| 1282 | + dev->checkpt_sum += *dataBytes; |
| 1283 | + dev->checkpt_xor ^= *dataBytes; |
| 1284 | |
| 1285 | - dev->checkpointByteOffset++; |
| 1286 | + dev->checkpt_byte_offs++; |
| 1287 | i++; |
| 1288 | dataBytes++; |
| 1289 | - dev->checkpointByteCount++; |
| 1290 | + dev->checkpt_byte_count++; |
| 1291 | |
| 1292 | |
| 1293 | - if (dev->checkpointByteOffset < 0 || |
| 1294 | - dev->checkpointByteOffset >= dev->nDataBytesPerChunk) |
| 1295 | - ok = yaffs_CheckpointFlushBuffer(dev); |
| 1296 | + if (dev->checkpt_byte_offs < 0 || |
| 1297 | + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) |
| 1298 | + ok = yaffs2_checkpt_flush_buffer(dev); |
| 1299 | } |
| 1300 | |
| 1301 | return i; |
| 1302 | } |
| 1303 | |
| 1304 | -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) |
| 1305 | +int yaffs2_checkpt_rd(yaffs_dev_t *dev, void *data, int n_bytes) |
| 1306 | { |
| 1307 | int i = 0; |
| 1308 | int ok = 1; |
| 1309 | - yaffs_ExtendedTags tags; |
| 1310 | + yaffs_ext_tags tags; |
| 1311 | |
| 1312 | |
| 1313 | int chunk; |
| 1314 | @@ -281,113 +285,116 @@ int yaffs_CheckpointRead(yaffs_Device *d |
| 1315 | |
| 1316 | __u8 *dataBytes = (__u8 *)data; |
| 1317 | |
| 1318 | - if (!dev->checkpointBuffer) |
| 1319 | + if (!dev->checkpt_buffer) |
| 1320 | return 0; |
| 1321 | |
| 1322 | - if (dev->checkpointOpenForWrite) |
| 1323 | + if (dev->checkpt_open_write) |
| 1324 | return -1; |
| 1325 | |
| 1326 | - while (i < nBytes && ok) { |
| 1327 | + while (i < n_bytes && ok) { |
| 1328 | |
| 1329 | |
| 1330 | - if (dev->checkpointByteOffset < 0 || |
| 1331 | - dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { |
| 1332 | + if (dev->checkpt_byte_offs < 0 || |
| 1333 | + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) { |
| 1334 | |
| 1335 | - if (dev->checkpointCurrentBlock < 0) { |
| 1336 | - yaffs_CheckpointFindNextCheckpointBlock(dev); |
| 1337 | - dev->checkpointCurrentChunk = 0; |
| 1338 | + if (dev->checkpt_cur_block < 0) { |
| 1339 | + yaffs2_checkpt_find_block(dev); |
| 1340 | + dev->checkpt_cur_chunk = 0; |
| 1341 | } |
| 1342 | |
| 1343 | - if (dev->checkpointCurrentBlock < 0) |
| 1344 | + if (dev->checkpt_cur_block < 0) |
| 1345 | ok = 0; |
| 1346 | else { |
| 1347 | - chunk = dev->checkpointCurrentBlock * |
| 1348 | - dev->nChunksPerBlock + |
| 1349 | - dev->checkpointCurrentChunk; |
| 1350 | - |
| 1351 | - realignedChunk = chunk - dev->chunkOffset; |
| 1352 | + chunk = dev->checkpt_cur_block * |
| 1353 | + dev->param.chunks_per_block + |
| 1354 | + dev->checkpt_cur_chunk; |
| 1355 | + |
| 1356 | + realignedChunk = chunk - dev->chunk_offset; |
| 1357 | + |
| 1358 | + dev->n_page_reads++; |
| 1359 | |
| 1360 | /* read in the next chunk */ |
| 1361 | /* printf("read checkpoint page %d\n",dev->checkpointPage); */ |
| 1362 | - dev->readChunkWithTagsFromNAND(dev, |
| 1363 | + dev->param.read_chunk_tags_fn(dev, |
| 1364 | realignedChunk, |
| 1365 | - dev->checkpointBuffer, |
| 1366 | + dev->checkpt_buffer, |
| 1367 | &tags); |
| 1368 | |
| 1369 | - if (tags.chunkId != (dev->checkpointPageSequence + 1) || |
| 1370 | - tags.eccResult > YAFFS_ECC_RESULT_FIXED || |
| 1371 | - tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA) |
| 1372 | + if (tags.chunk_id != (dev->checkpt_page_seq + 1) || |
| 1373 | + tags.ecc_result > YAFFS_ECC_RESULT_FIXED || |
| 1374 | + tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) |
| 1375 | ok = 0; |
| 1376 | |
| 1377 | - dev->checkpointByteOffset = 0; |
| 1378 | - dev->checkpointPageSequence++; |
| 1379 | - dev->checkpointCurrentChunk++; |
| 1380 | + dev->checkpt_byte_offs = 0; |
| 1381 | + dev->checkpt_page_seq++; |
| 1382 | + dev->checkpt_cur_chunk++; |
| 1383 | |
| 1384 | - if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) |
| 1385 | - dev->checkpointCurrentBlock = -1; |
| 1386 | + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) |
| 1387 | + dev->checkpt_cur_block = -1; |
| 1388 | } |
| 1389 | } |
| 1390 | |
| 1391 | if (ok) { |
| 1392 | - *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset]; |
| 1393 | - dev->checkpointSum += *dataBytes; |
| 1394 | - dev->checkpointXor ^= *dataBytes; |
| 1395 | - dev->checkpointByteOffset++; |
| 1396 | + *dataBytes = dev->checkpt_buffer[dev->checkpt_byte_offs]; |
| 1397 | + dev->checkpt_sum += *dataBytes; |
| 1398 | + dev->checkpt_xor ^= *dataBytes; |
| 1399 | + dev->checkpt_byte_offs++; |
| 1400 | i++; |
| 1401 | dataBytes++; |
| 1402 | - dev->checkpointByteCount++; |
| 1403 | + dev->checkpt_byte_count++; |
| 1404 | } |
| 1405 | } |
| 1406 | |
| 1407 | return i; |
| 1408 | } |
| 1409 | |
| 1410 | -int yaffs_CheckpointClose(yaffs_Device *dev) |
| 1411 | +int yaffs_checkpt_close(yaffs_dev_t *dev) |
| 1412 | { |
| 1413 | |
| 1414 | - if (dev->checkpointOpenForWrite) { |
| 1415 | - if (dev->checkpointByteOffset != 0) |
| 1416 | - yaffs_CheckpointFlushBuffer(dev); |
| 1417 | - } else { |
| 1418 | + if (dev->checkpt_open_write) { |
| 1419 | + if (dev->checkpt_byte_offs != 0) |
| 1420 | + yaffs2_checkpt_flush_buffer(dev); |
| 1421 | + } else if(dev->checkpt_block_list){ |
| 1422 | int i; |
| 1423 | - for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) { |
| 1424 | - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]); |
| 1425 | - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) |
| 1426 | - bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; |
| 1427 | + for (i = 0; i < dev->blocks_in_checkpt && dev->checkpt_block_list[i] >= 0; i++) { |
| 1428 | + int blk = dev->checkpt_block_list[i]; |
| 1429 | + yaffs_block_info_t *bi = NULL; |
| 1430 | + if( dev->internal_start_block <= blk && blk <= dev->internal_end_block) |
| 1431 | + bi = yaffs_get_block_info(dev, blk); |
| 1432 | + if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY) |
| 1433 | + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; |
| 1434 | else { |
| 1435 | /* Todo this looks odd... */ |
| 1436 | } |
| 1437 | } |
| 1438 | - YFREE(dev->checkpointBlockList); |
| 1439 | - dev->checkpointBlockList = NULL; |
| 1440 | + YFREE(dev->checkpt_block_list); |
| 1441 | + dev->checkpt_block_list = NULL; |
| 1442 | } |
| 1443 | |
| 1444 | - dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; |
| 1445 | - dev->nErasedBlocks -= dev->blocksInCheckpoint; |
| 1446 | + dev->n_free_chunks -= dev->blocks_in_checkpt * dev->param.chunks_per_block; |
| 1447 | + dev->n_erased_blocks -= dev->blocks_in_checkpt; |
| 1448 | |
| 1449 | |
| 1450 | T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR), |
| 1451 | - dev->checkpointByteCount)); |
| 1452 | + dev->checkpt_byte_count)); |
| 1453 | |
| 1454 | - if (dev->checkpointBuffer) { |
| 1455 | + if (dev->checkpt_buffer) { |
| 1456 | /* free the buffer */ |
| 1457 | - YFREE(dev->checkpointBuffer); |
| 1458 | - dev->checkpointBuffer = NULL; |
| 1459 | + YFREE(dev->checkpt_buffer); |
| 1460 | + dev->checkpt_buffer = NULL; |
| 1461 | return 1; |
| 1462 | } else |
| 1463 | return 0; |
| 1464 | } |
| 1465 | |
| 1466 | -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) |
| 1467 | +int yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev) |
| 1468 | { |
| 1469 | - /* Erase the first checksum block */ |
| 1470 | - |
| 1471 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR))); |
| 1472 | + /* Erase the checkpoint data */ |
| 1473 | |
| 1474 | - if (!yaffs_CheckpointSpaceOk(dev)) |
| 1475 | - return 0; |
| 1476 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR), |
| 1477 | + dev->blocks_in_checkpt)); |
| 1478 | |
| 1479 | - return yaffs_CheckpointErase(dev); |
| 1480 | + return yaffs_checkpt_erase(dev); |
| 1481 | } |
| 1482 | |
| 1483 | |
| 1484 | --- a/fs/yaffs2/yaffs_checkptrw.h |
| 1485 | +++ b/fs/yaffs2/yaffs_checkptrw.h |
| 1486 | @@ -1,7 +1,7 @@ |
| 1487 | /* |
| 1488 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 1489 | * |
| 1490 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 1491 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 1492 | * for Toby Churchill Ltd and Brightstar Engineering |
| 1493 | * |
| 1494 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 1495 | @@ -18,18 +18,17 @@ |
| 1496 | |
| 1497 | #include "yaffs_guts.h" |
| 1498 | |
| 1499 | -int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting); |
| 1500 | +int yaffs2_checkpt_open(yaffs_dev_t *dev, int forWriting); |
| 1501 | |
| 1502 | -int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes); |
| 1503 | +int yaffs2_checkpt_wr(yaffs_dev_t *dev, const void *data, int n_bytes); |
| 1504 | |
| 1505 | -int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes); |
| 1506 | +int yaffs2_checkpt_rd(yaffs_dev_t *dev, void *data, int n_bytes); |
| 1507 | |
| 1508 | -int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); |
| 1509 | +int yaffs2_get_checkpt_sum(yaffs_dev_t *dev, __u32 *sum); |
| 1510 | |
| 1511 | -int yaffs_CheckpointClose(yaffs_Device *dev); |
| 1512 | +int yaffs_checkpt_close(yaffs_dev_t *dev); |
| 1513 | |
| 1514 | -int yaffs_CheckpointInvalidateStream(yaffs_Device *dev); |
| 1515 | +int yaffs2_checkpt_invalidate_stream(yaffs_dev_t *dev); |
| 1516 | |
| 1517 | |
| 1518 | #endif |
| 1519 | - |
| 1520 | --- a/fs/yaffs2/yaffs_ecc.c |
| 1521 | +++ b/fs/yaffs2/yaffs_ecc.c |
| 1522 | @@ -1,7 +1,7 @@ |
| 1523 | /* |
| 1524 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 1525 | * |
| 1526 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 1527 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 1528 | * for Toby Churchill Ltd and Brightstar Engineering |
| 1529 | * |
| 1530 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 1531 | @@ -28,9 +28,6 @@ |
| 1532 | * this bytes influence on the line parity. |
| 1533 | */ |
| 1534 | |
| 1535 | -const char *yaffs_ecc_c_version = |
| 1536 | - "$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $"; |
| 1537 | - |
| 1538 | #include "yportenv.h" |
| 1539 | |
| 1540 | #include "yaffs_ecc.h" |
| 1541 | @@ -72,7 +69,7 @@ static const unsigned char column_parity |
| 1542 | |
| 1543 | /* Count the bits in an unsigned char or a U32 */ |
| 1544 | |
| 1545 | -static int yaffs_CountBits(unsigned char x) |
| 1546 | +static int yaffs_count_bits(unsigned char x) |
| 1547 | { |
| 1548 | int r = 0; |
| 1549 | while (x) { |
| 1550 | @@ -83,7 +80,7 @@ static int yaffs_CountBits(unsigned char |
| 1551 | return r; |
| 1552 | } |
| 1553 | |
| 1554 | -static int yaffs_CountBits32(unsigned x) |
| 1555 | +static int yaffs_count_bits32(unsigned x) |
| 1556 | { |
| 1557 | int r = 0; |
| 1558 | while (x) { |
| 1559 | @@ -95,7 +92,7 @@ static int yaffs_CountBits32(unsigned x) |
| 1560 | } |
| 1561 | |
| 1562 | /* Calculate the ECC for a 256-byte block of data */ |
| 1563 | -void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc) |
| 1564 | +void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc) |
| 1565 | { |
| 1566 | unsigned int i; |
| 1567 | |
| 1568 | @@ -166,7 +163,7 @@ void yaffs_ECCCalculate(const unsigned c |
| 1569 | |
| 1570 | /* Correct the ECC on a 256 byte block of data */ |
| 1571 | |
| 1572 | -int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, |
| 1573 | +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, |
| 1574 | const unsigned char *test_ecc) |
| 1575 | { |
| 1576 | unsigned char d0, d1, d2; /* deltas */ |
| 1577 | @@ -226,9 +223,9 @@ int yaffs_ECCCorrect(unsigned char *data |
| 1578 | return 1; /* Corrected the error */ |
| 1579 | } |
| 1580 | |
| 1581 | - if ((yaffs_CountBits(d0) + |
| 1582 | - yaffs_CountBits(d1) + |
| 1583 | - yaffs_CountBits(d2)) == 1) { |
| 1584 | + if ((yaffs_count_bits(d0) + |
| 1585 | + yaffs_count_bits(d1) + |
| 1586 | + yaffs_count_bits(d2)) == 1) { |
| 1587 | /* Reccoverable error in ecc */ |
| 1588 | |
| 1589 | read_ecc[0] = test_ecc[0]; |
| 1590 | @@ -248,7 +245,7 @@ int yaffs_ECCCorrect(unsigned char *data |
| 1591 | /* |
| 1592 | * ECCxxxOther does ECC calcs on arbitrary n bytes of data |
| 1593 | */ |
| 1594 | -void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, |
| 1595 | +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, |
| 1596 | yaffs_ECCOther *eccOther) |
| 1597 | { |
| 1598 | unsigned int i; |
| 1599 | @@ -258,7 +255,7 @@ void yaffs_ECCCalculateOther(const unsig |
| 1600 | unsigned line_parity_prime = 0; |
| 1601 | unsigned char b; |
| 1602 | |
| 1603 | - for (i = 0; i < nBytes; i++) { |
| 1604 | + for (i = 0; i < n_bytes; i++) { |
| 1605 | b = column_parity_table[*data++]; |
| 1606 | col_parity ^= b; |
| 1607 | |
| 1608 | @@ -275,7 +272,7 @@ void yaffs_ECCCalculateOther(const unsig |
| 1609 | eccOther->lineParityPrime = line_parity_prime; |
| 1610 | } |
| 1611 | |
| 1612 | -int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, |
| 1613 | +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, |
| 1614 | yaffs_ECCOther *read_ecc, |
| 1615 | const yaffs_ECCOther *test_ecc) |
| 1616 | { |
| 1617 | @@ -304,7 +301,7 @@ int yaffs_ECCCorrectOther(unsigned char |
| 1618 | if (cDelta & 0x02) |
| 1619 | bit |= 0x01; |
| 1620 | |
| 1621 | - if (lDelta >= nBytes) |
| 1622 | + if (lDelta >= n_bytes) |
| 1623 | return -1; |
| 1624 | |
| 1625 | data[lDelta] ^= (1 << bit); |
| 1626 | @@ -312,8 +309,8 @@ int yaffs_ECCCorrectOther(unsigned char |
| 1627 | return 1; /* corrected */ |
| 1628 | } |
| 1629 | |
| 1630 | - if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) + |
| 1631 | - yaffs_CountBits(cDelta)) == 1) { |
| 1632 | + if ((yaffs_count_bits32(lDelta) + yaffs_count_bits32(lDeltaPrime) + |
| 1633 | + yaffs_count_bits(cDelta)) == 1) { |
| 1634 | /* Reccoverable error in ecc */ |
| 1635 | |
| 1636 | *read_ecc = *test_ecc; |
| 1637 | --- a/fs/yaffs2/yaffs_ecc.h |
| 1638 | +++ b/fs/yaffs2/yaffs_ecc.h |
| 1639 | @@ -1,7 +1,7 @@ |
| 1640 | /* |
| 1641 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 1642 | * |
| 1643 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 1644 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 1645 | * for Toby Churchill Ltd and Brightstar Engineering |
| 1646 | * |
| 1647 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 1648 | @@ -32,13 +32,13 @@ typedef struct { |
| 1649 | unsigned lineParityPrime; |
| 1650 | } yaffs_ECCOther; |
| 1651 | |
| 1652 | -void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc); |
| 1653 | -int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, |
| 1654 | +void yaffs_ecc_cacl(const unsigned char *data, unsigned char *ecc); |
| 1655 | +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, |
| 1656 | const unsigned char *test_ecc); |
| 1657 | |
| 1658 | -void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, |
| 1659 | +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, |
| 1660 | yaffs_ECCOther *ecc); |
| 1661 | -int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, |
| 1662 | +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, |
| 1663 | yaffs_ECCOther *read_ecc, |
| 1664 | const yaffs_ECCOther *test_ecc); |
| 1665 | #endif |
| 1666 | --- a/fs/yaffs2/yaffs_fs.c |
| 1667 | +++ /dev/null |
| 1668 | @@ -1,2529 +0,0 @@ |
| 1669 | -/* |
| 1670 | - * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 1671 | - * |
| 1672 | - * Copyright (C) 2002-2009 Aleph One Ltd. |
| 1673 | - * for Toby Churchill Ltd and Brightstar Engineering |
| 1674 | - * |
| 1675 | - * Created by Charles Manning <charles@aleph1.co.uk> |
| 1676 | - * Acknowledgements: |
| 1677 | - * Luc van OostenRyck for numerous patches. |
| 1678 | - * Nick Bane for numerous patches. |
| 1679 | - * Nick Bane for 2.5/2.6 integration. |
| 1680 | - * Andras Toth for mknod rdev issue. |
| 1681 | - * Michael Fischer for finding the problem with inode inconsistency. |
| 1682 | - * Some code bodily lifted from JFFS |
| 1683 | - * |
| 1684 | - * This program is free software; you can redistribute it and/or modify |
| 1685 | - * it under the terms of the GNU General Public License version 2 as |
| 1686 | - * published by the Free Software Foundation. |
| 1687 | - */ |
| 1688 | - |
| 1689 | -/* |
| 1690 | - * |
| 1691 | - * This is the file system front-end to YAFFS that hooks it up to |
| 1692 | - * the VFS. |
| 1693 | - * |
| 1694 | - * Special notes: |
| 1695 | - * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with |
| 1696 | - * this superblock |
| 1697 | - * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this |
| 1698 | - * superblock |
| 1699 | - * >> inode->u.generic_ip points to the associated yaffs_Object. |
| 1700 | - */ |
| 1701 | - |
| 1702 | -const char *yaffs_fs_c_version = |
| 1703 | - "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $"; |
| 1704 | -extern const char *yaffs_guts_c_version; |
| 1705 | - |
| 1706 | -#include <linux/version.h> |
| 1707 | -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) |
| 1708 | -#include <linux/config.h> |
| 1709 | -#endif |
| 1710 | -#include <linux/kernel.h> |
| 1711 | -#include <linux/module.h> |
| 1712 | -#include <linux/slab.h> |
| 1713 | -#include <linux/init.h> |
| 1714 | -#include <linux/fs.h> |
| 1715 | -#include <linux/proc_fs.h> |
| 1716 | -#include <linux/smp_lock.h> |
| 1717 | -#include <linux/pagemap.h> |
| 1718 | -#include <linux/mtd/mtd.h> |
| 1719 | -#include <linux/interrupt.h> |
| 1720 | -#include <linux/string.h> |
| 1721 | -#include <linux/ctype.h> |
| 1722 | - |
| 1723 | -#include "asm/div64.h" |
| 1724 | - |
| 1725 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 1726 | - |
| 1727 | -#include <linux/statfs.h> /* Added NCB 15-8-2003 */ |
| 1728 | -#include <linux/statfs.h> |
| 1729 | -#define UnlockPage(p) unlock_page(p) |
| 1730 | -#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) |
| 1731 | - |
| 1732 | -/* FIXME: use sb->s_id instead ? */ |
| 1733 | -#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf) |
| 1734 | - |
| 1735 | -#else |
| 1736 | - |
| 1737 | -#include <linux/locks.h> |
| 1738 | -#define BDEVNAME_SIZE 0 |
| 1739 | -#define yaffs_devname(sb, buf) kdevname(sb->s_dev) |
| 1740 | - |
| 1741 | -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)) |
| 1742 | -/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ |
| 1743 | -#define __user |
| 1744 | -#endif |
| 1745 | - |
| 1746 | -#endif |
| 1747 | - |
| 1748 | -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) |
| 1749 | -#define YPROC_ROOT (&proc_root) |
| 1750 | -#else |
| 1751 | -#define YPROC_ROOT NULL |
| 1752 | -#endif |
| 1753 | - |
| 1754 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 1755 | -#define WRITE_SIZE_STR "writesize" |
| 1756 | -#define WRITE_SIZE(mtd) ((mtd)->writesize) |
| 1757 | -#else |
| 1758 | -#define WRITE_SIZE_STR "oobblock" |
| 1759 | -#define WRITE_SIZE(mtd) ((mtd)->oobblock) |
| 1760 | -#endif |
| 1761 | - |
| 1762 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)) |
| 1763 | -#define YAFFS_USE_WRITE_BEGIN_END 1 |
| 1764 | -#else |
| 1765 | -#define YAFFS_USE_WRITE_BEGIN_END 0 |
| 1766 | -#endif |
| 1767 | - |
| 1768 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)) |
| 1769 | -static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) |
| 1770 | -{ |
| 1771 | - uint64_t result = partition_size; |
| 1772 | - do_div(result, block_size); |
| 1773 | - return (uint32_t)result; |
| 1774 | -} |
| 1775 | -#else |
| 1776 | -#define YCALCBLOCKS(s, b) ((s)/(b)) |
| 1777 | -#endif |
| 1778 | - |
| 1779 | -#include <linux/uaccess.h> |
| 1780 | - |
| 1781 | -#include "yportenv.h" |
| 1782 | -#include "yaffs_guts.h" |
| 1783 | - |
| 1784 | -#include <linux/mtd/mtd.h> |
| 1785 | -#include "yaffs_mtdif.h" |
| 1786 | -#include "yaffs_mtdif1.h" |
| 1787 | -#include "yaffs_mtdif2.h" |
| 1788 | - |
| 1789 | -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS; |
| 1790 | -unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; |
| 1791 | -unsigned int yaffs_auto_checkpoint = 1; |
| 1792 | - |
| 1793 | -/* Module Parameters */ |
| 1794 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 1795 | -module_param(yaffs_traceMask, uint, 0644); |
| 1796 | -module_param(yaffs_wr_attempts, uint, 0644); |
| 1797 | -module_param(yaffs_auto_checkpoint, uint, 0644); |
| 1798 | -#else |
| 1799 | -MODULE_PARM(yaffs_traceMask, "i"); |
| 1800 | -MODULE_PARM(yaffs_wr_attempts, "i"); |
| 1801 | -MODULE_PARM(yaffs_auto_checkpoint, "i"); |
| 1802 | -#endif |
| 1803 | - |
| 1804 | -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) |
| 1805 | -/* use iget and read_inode */ |
| 1806 | -#define Y_IGET(sb, inum) iget((sb), (inum)) |
| 1807 | -static void yaffs_read_inode(struct inode *inode); |
| 1808 | - |
| 1809 | -#else |
| 1810 | -/* Call local equivalent */ |
| 1811 | -#define YAFFS_USE_OWN_IGET |
| 1812 | -#define Y_IGET(sb, inum) yaffs_iget((sb), (inum)) |
| 1813 | - |
| 1814 | -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino); |
| 1815 | -#endif |
| 1816 | - |
| 1817 | -/*#define T(x) printk x */ |
| 1818 | - |
| 1819 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) |
| 1820 | -#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private) |
| 1821 | -#else |
| 1822 | -#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip) |
| 1823 | -#endif |
| 1824 | - |
| 1825 | -#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr))) |
| 1826 | -#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode) |
| 1827 | - |
| 1828 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 1829 | -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info) |
| 1830 | -#else |
| 1831 | -#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp) |
| 1832 | -#endif |
| 1833 | - |
| 1834 | -static void yaffs_put_super(struct super_block *sb); |
| 1835 | - |
| 1836 | -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, |
| 1837 | - loff_t *pos); |
| 1838 | -static ssize_t yaffs_hold_space(struct file *f); |
| 1839 | -static void yaffs_release_space(struct file *f); |
| 1840 | - |
| 1841 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 1842 | -static int yaffs_file_flush(struct file *file, fl_owner_t id); |
| 1843 | -#else |
| 1844 | -static int yaffs_file_flush(struct file *file); |
| 1845 | -#endif |
| 1846 | - |
| 1847 | -static int yaffs_sync_object(struct file *file, struct dentry *dentry, |
| 1848 | - int datasync); |
| 1849 | - |
| 1850 | -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir); |
| 1851 | - |
| 1852 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 1853 | -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, |
| 1854 | - struct nameidata *n); |
| 1855 | -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, |
| 1856 | - struct nameidata *n); |
| 1857 | -#else |
| 1858 | -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode); |
| 1859 | -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry); |
| 1860 | -#endif |
| 1861 | -static int yaffs_link(struct dentry *old_dentry, struct inode *dir, |
| 1862 | - struct dentry *dentry); |
| 1863 | -static int yaffs_unlink(struct inode *dir, struct dentry *dentry); |
| 1864 | -static int yaffs_symlink(struct inode *dir, struct dentry *dentry, |
| 1865 | - const char *symname); |
| 1866 | -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode); |
| 1867 | - |
| 1868 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 1869 | -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, |
| 1870 | - dev_t dev); |
| 1871 | -#else |
| 1872 | -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, |
| 1873 | - int dev); |
| 1874 | -#endif |
| 1875 | -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, |
| 1876 | - struct inode *new_dir, struct dentry *new_dentry); |
| 1877 | -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr); |
| 1878 | - |
| 1879 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 1880 | -static int yaffs_sync_fs(struct super_block *sb, int wait); |
| 1881 | -static void yaffs_write_super(struct super_block *sb); |
| 1882 | -#else |
| 1883 | -static int yaffs_sync_fs(struct super_block *sb); |
| 1884 | -static int yaffs_write_super(struct super_block *sb); |
| 1885 | -#endif |
| 1886 | - |
| 1887 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 1888 | -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf); |
| 1889 | -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 1890 | -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf); |
| 1891 | -#else |
| 1892 | -static int yaffs_statfs(struct super_block *sb, struct statfs *buf); |
| 1893 | -#endif |
| 1894 | - |
| 1895 | -#ifdef YAFFS_HAS_PUT_INODE |
| 1896 | -static void yaffs_put_inode(struct inode *inode); |
| 1897 | -#endif |
| 1898 | - |
| 1899 | -static void yaffs_delete_inode(struct inode *); |
| 1900 | -static void yaffs_clear_inode(struct inode *); |
| 1901 | - |
| 1902 | -static int yaffs_readpage(struct file *file, struct page *page); |
| 1903 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 1904 | -static int yaffs_writepage(struct page *page, struct writeback_control *wbc); |
| 1905 | -#else |
| 1906 | -static int yaffs_writepage(struct page *page); |
| 1907 | -#endif |
| 1908 | - |
| 1909 | - |
| 1910 | -#if (YAFFS_USE_WRITE_BEGIN_END != 0) |
| 1911 | -static int yaffs_write_begin(struct file *filp, struct address_space *mapping, |
| 1912 | - loff_t pos, unsigned len, unsigned flags, |
| 1913 | - struct page **pagep, void **fsdata); |
| 1914 | -static int yaffs_write_end(struct file *filp, struct address_space *mapping, |
| 1915 | - loff_t pos, unsigned len, unsigned copied, |
| 1916 | - struct page *pg, void *fsdadata); |
| 1917 | -#else |
| 1918 | -static int yaffs_prepare_write(struct file *f, struct page *pg, |
| 1919 | - unsigned offset, unsigned to); |
| 1920 | -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, |
| 1921 | - unsigned to); |
| 1922 | - |
| 1923 | -#endif |
| 1924 | - |
| 1925 | -static int yaffs_readlink(struct dentry *dentry, char __user *buffer, |
| 1926 | - int buflen); |
| 1927 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) |
| 1928 | -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); |
| 1929 | -#else |
| 1930 | -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); |
| 1931 | -#endif |
| 1932 | - |
| 1933 | -static struct address_space_operations yaffs_file_address_operations = { |
| 1934 | - .readpage = yaffs_readpage, |
| 1935 | - .writepage = yaffs_writepage, |
| 1936 | -#if (YAFFS_USE_WRITE_BEGIN_END > 0) |
| 1937 | - .write_begin = yaffs_write_begin, |
| 1938 | - .write_end = yaffs_write_end, |
| 1939 | -#else |
| 1940 | - .prepare_write = yaffs_prepare_write, |
| 1941 | - .commit_write = yaffs_commit_write, |
| 1942 | -#endif |
| 1943 | -}; |
| 1944 | - |
| 1945 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) |
| 1946 | -static const struct file_operations yaffs_file_operations = { |
| 1947 | - .read = do_sync_read, |
| 1948 | - .write = do_sync_write, |
| 1949 | - .aio_read = generic_file_aio_read, |
| 1950 | - .aio_write = generic_file_aio_write, |
| 1951 | - .mmap = generic_file_mmap, |
| 1952 | - .flush = yaffs_file_flush, |
| 1953 | - .fsync = yaffs_sync_object, |
| 1954 | - .splice_read = generic_file_splice_read, |
| 1955 | - .splice_write = generic_file_splice_write, |
| 1956 | - .llseek = generic_file_llseek, |
| 1957 | -}; |
| 1958 | - |
| 1959 | -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) |
| 1960 | - |
| 1961 | -static const struct file_operations yaffs_file_operations = { |
| 1962 | - .read = do_sync_read, |
| 1963 | - .write = do_sync_write, |
| 1964 | - .aio_read = generic_file_aio_read, |
| 1965 | - .aio_write = generic_file_aio_write, |
| 1966 | - .mmap = generic_file_mmap, |
| 1967 | - .flush = yaffs_file_flush, |
| 1968 | - .fsync = yaffs_sync_object, |
| 1969 | - .sendfile = generic_file_sendfile, |
| 1970 | -}; |
| 1971 | - |
| 1972 | -#else |
| 1973 | - |
| 1974 | -static const struct file_operations yaffs_file_operations = { |
| 1975 | - .read = generic_file_read, |
| 1976 | - .write = generic_file_write, |
| 1977 | - .mmap = generic_file_mmap, |
| 1978 | - .flush = yaffs_file_flush, |
| 1979 | - .fsync = yaffs_sync_object, |
| 1980 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 1981 | - .sendfile = generic_file_sendfile, |
| 1982 | -#endif |
| 1983 | -}; |
| 1984 | -#endif |
| 1985 | - |
| 1986 | -static const struct inode_operations yaffs_file_inode_operations = { |
| 1987 | - .setattr = yaffs_setattr, |
| 1988 | -}; |
| 1989 | - |
| 1990 | -static const struct inode_operations yaffs_symlink_inode_operations = { |
| 1991 | - .readlink = yaffs_readlink, |
| 1992 | - .follow_link = yaffs_follow_link, |
| 1993 | - .setattr = yaffs_setattr, |
| 1994 | -}; |
| 1995 | - |
| 1996 | -static const struct inode_operations yaffs_dir_inode_operations = { |
| 1997 | - .create = yaffs_create, |
| 1998 | - .lookup = yaffs_lookup, |
| 1999 | - .link = yaffs_link, |
| 2000 | - .unlink = yaffs_unlink, |
| 2001 | - .symlink = yaffs_symlink, |
| 2002 | - .mkdir = yaffs_mkdir, |
| 2003 | - .rmdir = yaffs_unlink, |
| 2004 | - .mknod = yaffs_mknod, |
| 2005 | - .rename = yaffs_rename, |
| 2006 | - .setattr = yaffs_setattr, |
| 2007 | -}; |
| 2008 | - |
| 2009 | -static const struct file_operations yaffs_dir_operations = { |
| 2010 | - .read = generic_read_dir, |
| 2011 | - .readdir = yaffs_readdir, |
| 2012 | - .fsync = yaffs_sync_object, |
| 2013 | -}; |
| 2014 | - |
| 2015 | -static const struct super_operations yaffs_super_ops = { |
| 2016 | - .statfs = yaffs_statfs, |
| 2017 | - |
| 2018 | -#ifndef YAFFS_USE_OWN_IGET |
| 2019 | - .read_inode = yaffs_read_inode, |
| 2020 | -#endif |
| 2021 | -#ifdef YAFFS_HAS_PUT_INODE |
| 2022 | - .put_inode = yaffs_put_inode, |
| 2023 | -#endif |
| 2024 | - .put_super = yaffs_put_super, |
| 2025 | - .delete_inode = yaffs_delete_inode, |
| 2026 | - .clear_inode = yaffs_clear_inode, |
| 2027 | - .sync_fs = yaffs_sync_fs, |
| 2028 | - .write_super = yaffs_write_super, |
| 2029 | -}; |
| 2030 | - |
| 2031 | -static void yaffs_GrossLock(yaffs_Device *dev) |
| 2032 | -{ |
| 2033 | - T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current)); |
| 2034 | - down(&dev->grossLock); |
| 2035 | - T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current)); |
| 2036 | -} |
| 2037 | - |
| 2038 | -static void yaffs_GrossUnlock(yaffs_Device *dev) |
| 2039 | -{ |
| 2040 | - T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current)); |
| 2041 | - up(&dev->grossLock); |
| 2042 | -} |
| 2043 | - |
| 2044 | -static int yaffs_readlink(struct dentry *dentry, char __user *buffer, |
| 2045 | - int buflen) |
| 2046 | -{ |
| 2047 | - unsigned char *alias; |
| 2048 | - int ret; |
| 2049 | - |
| 2050 | - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; |
| 2051 | - |
| 2052 | - yaffs_GrossLock(dev); |
| 2053 | - |
| 2054 | - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); |
| 2055 | - |
| 2056 | - yaffs_GrossUnlock(dev); |
| 2057 | - |
| 2058 | - if (!alias) |
| 2059 | - return -ENOMEM; |
| 2060 | - |
| 2061 | - ret = vfs_readlink(dentry, buffer, buflen, alias); |
| 2062 | - kfree(alias); |
| 2063 | - return ret; |
| 2064 | -} |
| 2065 | - |
| 2066 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) |
| 2067 | -static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) |
| 2068 | -#else |
| 2069 | -static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) |
| 2070 | -#endif |
| 2071 | -{ |
| 2072 | - unsigned char *alias; |
| 2073 | - int ret; |
| 2074 | - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; |
| 2075 | - |
| 2076 | - yaffs_GrossLock(dev); |
| 2077 | - |
| 2078 | - alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); |
| 2079 | - |
| 2080 | - yaffs_GrossUnlock(dev); |
| 2081 | - |
| 2082 | - if (!alias) { |
| 2083 | - ret = -ENOMEM; |
| 2084 | - goto out; |
| 2085 | - } |
| 2086 | - |
| 2087 | - ret = vfs_follow_link(nd, alias); |
| 2088 | - kfree(alias); |
| 2089 | -out: |
| 2090 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) |
| 2091 | - return ERR_PTR(ret); |
| 2092 | -#else |
| 2093 | - return ret; |
| 2094 | -#endif |
| 2095 | -} |
| 2096 | - |
| 2097 | -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, |
| 2098 | - yaffs_Object *obj); |
| 2099 | - |
| 2100 | -/* |
| 2101 | - * Lookup is used to find objects in the fs |
| 2102 | - */ |
| 2103 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 2104 | - |
| 2105 | -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, |
| 2106 | - struct nameidata *n) |
| 2107 | -#else |
| 2108 | -static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) |
| 2109 | -#endif |
| 2110 | -{ |
| 2111 | - yaffs_Object *obj; |
| 2112 | - struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */ |
| 2113 | - |
| 2114 | - yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev; |
| 2115 | - |
| 2116 | - yaffs_GrossLock(dev); |
| 2117 | - |
| 2118 | - T(YAFFS_TRACE_OS, |
| 2119 | - ("yaffs_lookup for %d:%s\n", |
| 2120 | - yaffs_InodeToObject(dir)->objectId, dentry->d_name.name)); |
| 2121 | - |
| 2122 | - obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir), |
| 2123 | - dentry->d_name.name); |
| 2124 | - |
| 2125 | - obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */ |
| 2126 | - |
| 2127 | - /* Can't hold gross lock when calling yaffs_get_inode() */ |
| 2128 | - yaffs_GrossUnlock(dev); |
| 2129 | - |
| 2130 | - if (obj) { |
| 2131 | - T(YAFFS_TRACE_OS, |
| 2132 | - ("yaffs_lookup found %d\n", obj->objectId)); |
| 2133 | - |
| 2134 | - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); |
| 2135 | - |
| 2136 | - if (inode) { |
| 2137 | - T(YAFFS_TRACE_OS, |
| 2138 | - ("yaffs_loookup dentry \n")); |
| 2139 | -/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to |
| 2140 | - * d_add even if NULL inode */ |
| 2141 | -#if 0 |
| 2142 | - /*dget(dentry); // try to solve directory bug */ |
| 2143 | - d_add(dentry, inode); |
| 2144 | - |
| 2145 | - /* return dentry; */ |
| 2146 | - return NULL; |
| 2147 | -#endif |
| 2148 | - } |
| 2149 | - |
| 2150 | - } else { |
| 2151 | - T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n")); |
| 2152 | - |
| 2153 | - } |
| 2154 | - |
| 2155 | -/* added NCB for 2.5/6 compatability - forces add even if inode is |
| 2156 | - * NULL which creates dentry hash */ |
| 2157 | - d_add(dentry, inode); |
| 2158 | - |
| 2159 | - return NULL; |
| 2160 | -} |
| 2161 | - |
| 2162 | - |
| 2163 | -#ifdef YAFFS_HAS_PUT_INODE |
| 2164 | - |
| 2165 | -/* For now put inode is just for debugging |
| 2166 | - * Put inode is called when the inode **structure** is put. |
| 2167 | - */ |
| 2168 | -static void yaffs_put_inode(struct inode *inode) |
| 2169 | -{ |
| 2170 | - T(YAFFS_TRACE_OS, |
| 2171 | - ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino, |
| 2172 | - atomic_read(&inode->i_count))); |
| 2173 | - |
| 2174 | -} |
| 2175 | -#endif |
| 2176 | - |
| 2177 | -/* clear is called to tell the fs to release any per-inode data it holds */ |
| 2178 | -static void yaffs_clear_inode(struct inode *inode) |
| 2179 | -{ |
| 2180 | - yaffs_Object *obj; |
| 2181 | - yaffs_Device *dev; |
| 2182 | - |
| 2183 | - obj = yaffs_InodeToObject(inode); |
| 2184 | - |
| 2185 | - T(YAFFS_TRACE_OS, |
| 2186 | - ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino, |
| 2187 | - atomic_read(&inode->i_count), |
| 2188 | - obj ? "object exists" : "null object")); |
| 2189 | - |
| 2190 | - if (obj) { |
| 2191 | - dev = obj->myDev; |
| 2192 | - yaffs_GrossLock(dev); |
| 2193 | - |
| 2194 | - /* Clear the association between the inode and |
| 2195 | - * the yaffs_Object. |
| 2196 | - */ |
| 2197 | - obj->myInode = NULL; |
| 2198 | - yaffs_InodeToObjectLV(inode) = NULL; |
| 2199 | - |
| 2200 | - /* If the object freeing was deferred, then the real |
| 2201 | - * free happens now. |
| 2202 | - * This should fix the inode inconsistency problem. |
| 2203 | - */ |
| 2204 | - |
| 2205 | - yaffs_HandleDeferedFree(obj); |
| 2206 | - |
| 2207 | - yaffs_GrossUnlock(dev); |
| 2208 | - } |
| 2209 | - |
| 2210 | -} |
| 2211 | - |
| 2212 | -/* delete is called when the link count is zero and the inode |
| 2213 | - * is put (ie. nobody wants to know about it anymore, time to |
| 2214 | - * delete the file). |
| 2215 | - * NB Must call clear_inode() |
| 2216 | - */ |
| 2217 | -static void yaffs_delete_inode(struct inode *inode) |
| 2218 | -{ |
| 2219 | - yaffs_Object *obj = yaffs_InodeToObject(inode); |
| 2220 | - yaffs_Device *dev; |
| 2221 | - |
| 2222 | - T(YAFFS_TRACE_OS, |
| 2223 | - ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino, |
| 2224 | - atomic_read(&inode->i_count), |
| 2225 | - obj ? "object exists" : "null object")); |
| 2226 | - |
| 2227 | - if (obj) { |
| 2228 | - dev = obj->myDev; |
| 2229 | - yaffs_GrossLock(dev); |
| 2230 | - yaffs_DeleteObject(obj); |
| 2231 | - yaffs_GrossUnlock(dev); |
| 2232 | - } |
| 2233 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) |
| 2234 | - truncate_inode_pages(&inode->i_data, 0); |
| 2235 | -#endif |
| 2236 | - clear_inode(inode); |
| 2237 | -} |
| 2238 | - |
| 2239 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 2240 | -static int yaffs_file_flush(struct file *file, fl_owner_t id) |
| 2241 | -#else |
| 2242 | -static int yaffs_file_flush(struct file *file) |
| 2243 | -#endif |
| 2244 | -{ |
| 2245 | - yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry); |
| 2246 | - |
| 2247 | - yaffs_Device *dev = obj->myDev; |
| 2248 | - |
| 2249 | - T(YAFFS_TRACE_OS, |
| 2250 | - ("yaffs_file_flush object %d (%s)\n", obj->objectId, |
| 2251 | - obj->dirty ? "dirty" : "clean")); |
| 2252 | - |
| 2253 | - yaffs_GrossLock(dev); |
| 2254 | - |
| 2255 | - yaffs_FlushFile(obj, 1); |
| 2256 | - |
| 2257 | - yaffs_GrossUnlock(dev); |
| 2258 | - |
| 2259 | - return 0; |
| 2260 | -} |
| 2261 | - |
| 2262 | -static int yaffs_readpage_nolock(struct file *f, struct page *pg) |
| 2263 | -{ |
| 2264 | - /* Lifted from jffs2 */ |
| 2265 | - |
| 2266 | - yaffs_Object *obj; |
| 2267 | - unsigned char *pg_buf; |
| 2268 | - int ret; |
| 2269 | - |
| 2270 | - yaffs_Device *dev; |
| 2271 | - |
| 2272 | - T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n", |
| 2273 | - (unsigned)(pg->index << PAGE_CACHE_SHIFT), |
| 2274 | - (unsigned)PAGE_CACHE_SIZE)); |
| 2275 | - |
| 2276 | - obj = yaffs_DentryToObject(f->f_dentry); |
| 2277 | - |
| 2278 | - dev = obj->myDev; |
| 2279 | - |
| 2280 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 2281 | - BUG_ON(!PageLocked(pg)); |
| 2282 | -#else |
| 2283 | - if (!PageLocked(pg)) |
| 2284 | - PAGE_BUG(pg); |
| 2285 | -#endif |
| 2286 | - |
| 2287 | - pg_buf = kmap(pg); |
| 2288 | - /* FIXME: Can kmap fail? */ |
| 2289 | - |
| 2290 | - yaffs_GrossLock(dev); |
| 2291 | - |
| 2292 | - ret = yaffs_ReadDataFromFile(obj, pg_buf, |
| 2293 | - pg->index << PAGE_CACHE_SHIFT, |
| 2294 | - PAGE_CACHE_SIZE); |
| 2295 | - |
| 2296 | - yaffs_GrossUnlock(dev); |
| 2297 | - |
| 2298 | - if (ret >= 0) |
| 2299 | - ret = 0; |
| 2300 | - |
| 2301 | - if (ret) { |
| 2302 | - ClearPageUptodate(pg); |
| 2303 | - SetPageError(pg); |
| 2304 | - } else { |
| 2305 | - SetPageUptodate(pg); |
| 2306 | - ClearPageError(pg); |
| 2307 | - } |
| 2308 | - |
| 2309 | - flush_dcache_page(pg); |
| 2310 | - kunmap(pg); |
| 2311 | - |
| 2312 | - T(YAFFS_TRACE_OS, ("yaffs_readpage done\n")); |
| 2313 | - return ret; |
| 2314 | -} |
| 2315 | - |
| 2316 | -static int yaffs_readpage_unlock(struct file *f, struct page *pg) |
| 2317 | -{ |
| 2318 | - int ret = yaffs_readpage_nolock(f, pg); |
| 2319 | - UnlockPage(pg); |
| 2320 | - return ret; |
| 2321 | -} |
| 2322 | - |
| 2323 | -static int yaffs_readpage(struct file *f, struct page *pg) |
| 2324 | -{ |
| 2325 | - return yaffs_readpage_unlock(f, pg); |
| 2326 | -} |
| 2327 | - |
| 2328 | -/* writepage inspired by/stolen from smbfs */ |
| 2329 | - |
| 2330 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 2331 | -static int yaffs_writepage(struct page *page, struct writeback_control *wbc) |
| 2332 | -#else |
| 2333 | -static int yaffs_writepage(struct page *page) |
| 2334 | -#endif |
| 2335 | -{ |
| 2336 | - struct address_space *mapping = page->mapping; |
| 2337 | - loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT; |
| 2338 | - struct inode *inode; |
| 2339 | - unsigned long end_index; |
| 2340 | - char *buffer; |
| 2341 | - yaffs_Object *obj; |
| 2342 | - int nWritten = 0; |
| 2343 | - unsigned nBytes; |
| 2344 | - |
| 2345 | - if (!mapping) |
| 2346 | - BUG(); |
| 2347 | - inode = mapping->host; |
| 2348 | - if (!inode) |
| 2349 | - BUG(); |
| 2350 | - |
| 2351 | - if (offset > inode->i_size) { |
| 2352 | - T(YAFFS_TRACE_OS, |
| 2353 | - ("yaffs_writepage at %08x, inode size = %08x!!!\n", |
| 2354 | - (unsigned)(page->index << PAGE_CACHE_SHIFT), |
| 2355 | - (unsigned)inode->i_size)); |
| 2356 | - T(YAFFS_TRACE_OS, |
| 2357 | - (" -> don't care!!\n")); |
| 2358 | - unlock_page(page); |
| 2359 | - return 0; |
| 2360 | - } |
| 2361 | - |
| 2362 | - end_index = inode->i_size >> PAGE_CACHE_SHIFT; |
| 2363 | - |
| 2364 | - /* easy case */ |
| 2365 | - if (page->index < end_index) |
| 2366 | - nBytes = PAGE_CACHE_SIZE; |
| 2367 | - else |
| 2368 | - nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1); |
| 2369 | - |
| 2370 | - get_page(page); |
| 2371 | - |
| 2372 | - buffer = kmap(page); |
| 2373 | - |
| 2374 | - obj = yaffs_InodeToObject(inode); |
| 2375 | - yaffs_GrossLock(obj->myDev); |
| 2376 | - |
| 2377 | - T(YAFFS_TRACE_OS, |
| 2378 | - ("yaffs_writepage at %08x, size %08x\n", |
| 2379 | - (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes)); |
| 2380 | - T(YAFFS_TRACE_OS, |
| 2381 | - ("writepag0: obj = %05x, ino = %05x\n", |
| 2382 | - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); |
| 2383 | - |
| 2384 | - nWritten = yaffs_WriteDataToFile(obj, buffer, |
| 2385 | - page->index << PAGE_CACHE_SHIFT, nBytes, 0); |
| 2386 | - |
| 2387 | - T(YAFFS_TRACE_OS, |
| 2388 | - ("writepag1: obj = %05x, ino = %05x\n", |
| 2389 | - (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); |
| 2390 | - |
| 2391 | - yaffs_GrossUnlock(obj->myDev); |
| 2392 | - |
| 2393 | - kunmap(page); |
| 2394 | - SetPageUptodate(page); |
| 2395 | - UnlockPage(page); |
| 2396 | - put_page(page); |
| 2397 | - |
| 2398 | - return (nWritten == nBytes) ? 0 : -ENOSPC; |
| 2399 | -} |
| 2400 | - |
| 2401 | - |
| 2402 | -#if (YAFFS_USE_WRITE_BEGIN_END > 0) |
| 2403 | -static int yaffs_write_begin(struct file *filp, struct address_space *mapping, |
| 2404 | - loff_t pos, unsigned len, unsigned flags, |
| 2405 | - struct page **pagep, void **fsdata) |
| 2406 | -{ |
| 2407 | - struct page *pg = NULL; |
| 2408 | - pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
| 2409 | - uint32_t offset = pos & (PAGE_CACHE_SIZE - 1); |
| 2410 | - uint32_t to = offset + len; |
| 2411 | - |
| 2412 | - int ret = 0; |
| 2413 | - int space_held = 0; |
| 2414 | - |
| 2415 | - T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n")); |
| 2416 | - /* Get a page */ |
| 2417 | -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28) |
| 2418 | - pg = grab_cache_page_write_begin(mapping, index, flags); |
| 2419 | -#else |
| 2420 | - pg = __grab_cache_page(mapping, index); |
| 2421 | -#endif |
| 2422 | - |
| 2423 | - *pagep = pg; |
| 2424 | - if (!pg) { |
| 2425 | - ret = -ENOMEM; |
| 2426 | - goto out; |
| 2427 | - } |
| 2428 | - /* Get fs space */ |
| 2429 | - space_held = yaffs_hold_space(filp); |
| 2430 | - |
| 2431 | - if (!space_held) { |
| 2432 | - ret = -ENOSPC; |
| 2433 | - goto out; |
| 2434 | - } |
| 2435 | - |
| 2436 | - /* Update page if required */ |
| 2437 | - |
| 2438 | - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) |
| 2439 | - ret = yaffs_readpage_nolock(filp, pg); |
| 2440 | - |
| 2441 | - if (ret) |
| 2442 | - goto out; |
| 2443 | - |
| 2444 | - /* Happy path return */ |
| 2445 | - T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n")); |
| 2446 | - |
| 2447 | - return 0; |
| 2448 | - |
| 2449 | -out: |
| 2450 | - T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret)); |
| 2451 | - if (space_held) |
| 2452 | - yaffs_release_space(filp); |
| 2453 | - if (pg) { |
| 2454 | - unlock_page(pg); |
| 2455 | - page_cache_release(pg); |
| 2456 | - } |
| 2457 | - return ret; |
| 2458 | -} |
| 2459 | - |
| 2460 | -#else |
| 2461 | - |
| 2462 | -static int yaffs_prepare_write(struct file *f, struct page *pg, |
| 2463 | - unsigned offset, unsigned to) |
| 2464 | -{ |
| 2465 | - T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n")); |
| 2466 | - |
| 2467 | - if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE)) |
| 2468 | - return yaffs_readpage_nolock(f, pg); |
| 2469 | - return 0; |
| 2470 | -} |
| 2471 | -#endif |
| 2472 | - |
| 2473 | -#if (YAFFS_USE_WRITE_BEGIN_END > 0) |
| 2474 | -static int yaffs_write_end(struct file *filp, struct address_space *mapping, |
| 2475 | - loff_t pos, unsigned len, unsigned copied, |
| 2476 | - struct page *pg, void *fsdadata) |
| 2477 | -{ |
| 2478 | - int ret = 0; |
| 2479 | - void *addr, *kva; |
| 2480 | - uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1); |
| 2481 | - |
| 2482 | - kva = kmap(pg); |
| 2483 | - addr = kva + offset_into_page; |
| 2484 | - |
| 2485 | - T(YAFFS_TRACE_OS, |
| 2486 | - ("yaffs_write_end addr %x pos %x nBytes %d\n", |
| 2487 | - (unsigned) addr, |
| 2488 | - (int)pos, copied)); |
| 2489 | - |
| 2490 | - ret = yaffs_file_write(filp, addr, copied, &pos); |
| 2491 | - |
| 2492 | - if (ret != copied) { |
| 2493 | - T(YAFFS_TRACE_OS, |
| 2494 | - ("yaffs_write_end not same size ret %d copied %d\n", |
| 2495 | - ret, copied)); |
| 2496 | - SetPageError(pg); |
| 2497 | - ClearPageUptodate(pg); |
| 2498 | - } else { |
| 2499 | - SetPageUptodate(pg); |
| 2500 | - } |
| 2501 | - |
| 2502 | - kunmap(pg); |
| 2503 | - |
| 2504 | - yaffs_release_space(filp); |
| 2505 | - unlock_page(pg); |
| 2506 | - page_cache_release(pg); |
| 2507 | - return ret; |
| 2508 | -} |
| 2509 | -#else |
| 2510 | - |
| 2511 | -static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, |
| 2512 | - unsigned to) |
| 2513 | -{ |
| 2514 | - void *addr, *kva; |
| 2515 | - |
| 2516 | - loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset; |
| 2517 | - int nBytes = to - offset; |
| 2518 | - int nWritten; |
| 2519 | - |
| 2520 | - unsigned spos = pos; |
| 2521 | - unsigned saddr; |
| 2522 | - |
| 2523 | - kva = kmap(pg); |
| 2524 | - addr = kva + offset; |
| 2525 | - |
| 2526 | - saddr = (unsigned) addr; |
| 2527 | - |
| 2528 | - T(YAFFS_TRACE_OS, |
| 2529 | - ("yaffs_commit_write addr %x pos %x nBytes %d\n", |
| 2530 | - saddr, spos, nBytes)); |
| 2531 | - |
| 2532 | - nWritten = yaffs_file_write(f, addr, nBytes, &pos); |
| 2533 | - |
| 2534 | - if (nWritten != nBytes) { |
| 2535 | - T(YAFFS_TRACE_OS, |
| 2536 | - ("yaffs_commit_write not same size nWritten %d nBytes %d\n", |
| 2537 | - nWritten, nBytes)); |
| 2538 | - SetPageError(pg); |
| 2539 | - ClearPageUptodate(pg); |
| 2540 | - } else { |
| 2541 | - SetPageUptodate(pg); |
| 2542 | - } |
| 2543 | - |
| 2544 | - kunmap(pg); |
| 2545 | - |
| 2546 | - T(YAFFS_TRACE_OS, |
| 2547 | - ("yaffs_commit_write returning %d\n", |
| 2548 | - nWritten == nBytes ? 0 : nWritten)); |
| 2549 | - |
| 2550 | - return nWritten == nBytes ? 0 : nWritten; |
| 2551 | -} |
| 2552 | -#endif |
| 2553 | - |
| 2554 | - |
| 2555 | -static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj) |
| 2556 | -{ |
| 2557 | - if (inode && obj) { |
| 2558 | - |
| 2559 | - |
| 2560 | - /* Check mode against the variant type and attempt to repair if broken. */ |
| 2561 | - __u32 mode = obj->yst_mode; |
| 2562 | - switch (obj->variantType) { |
| 2563 | - case YAFFS_OBJECT_TYPE_FILE: |
| 2564 | - if (!S_ISREG(mode)) { |
| 2565 | - obj->yst_mode &= ~S_IFMT; |
| 2566 | - obj->yst_mode |= S_IFREG; |
| 2567 | - } |
| 2568 | - |
| 2569 | - break; |
| 2570 | - case YAFFS_OBJECT_TYPE_SYMLINK: |
| 2571 | - if (!S_ISLNK(mode)) { |
| 2572 | - obj->yst_mode &= ~S_IFMT; |
| 2573 | - obj->yst_mode |= S_IFLNK; |
| 2574 | - } |
| 2575 | - |
| 2576 | - break; |
| 2577 | - case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 2578 | - if (!S_ISDIR(mode)) { |
| 2579 | - obj->yst_mode &= ~S_IFMT; |
| 2580 | - obj->yst_mode |= S_IFDIR; |
| 2581 | - } |
| 2582 | - |
| 2583 | - break; |
| 2584 | - case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 2585 | - case YAFFS_OBJECT_TYPE_HARDLINK: |
| 2586 | - case YAFFS_OBJECT_TYPE_SPECIAL: |
| 2587 | - default: |
| 2588 | - /* TODO? */ |
| 2589 | - break; |
| 2590 | - } |
| 2591 | - |
| 2592 | - inode->i_flags |= S_NOATIME; |
| 2593 | - |
| 2594 | - inode->i_ino = obj->objectId; |
| 2595 | - inode->i_mode = obj->yst_mode; |
| 2596 | - inode->i_uid = obj->yst_uid; |
| 2597 | - inode->i_gid = obj->yst_gid; |
| 2598 | -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) |
| 2599 | - inode->i_blksize = inode->i_sb->s_blocksize; |
| 2600 | -#endif |
| 2601 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 2602 | - |
| 2603 | - inode->i_rdev = old_decode_dev(obj->yst_rdev); |
| 2604 | - inode->i_atime.tv_sec = (time_t) (obj->yst_atime); |
| 2605 | - inode->i_atime.tv_nsec = 0; |
| 2606 | - inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; |
| 2607 | - inode->i_mtime.tv_nsec = 0; |
| 2608 | - inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; |
| 2609 | - inode->i_ctime.tv_nsec = 0; |
| 2610 | -#else |
| 2611 | - inode->i_rdev = obj->yst_rdev; |
| 2612 | - inode->i_atime = obj->yst_atime; |
| 2613 | - inode->i_mtime = obj->yst_mtime; |
| 2614 | - inode->i_ctime = obj->yst_ctime; |
| 2615 | -#endif |
| 2616 | - inode->i_size = yaffs_GetObjectFileLength(obj); |
| 2617 | - inode->i_blocks = (inode->i_size + 511) >> 9; |
| 2618 | - |
| 2619 | - inode->i_nlink = yaffs_GetObjectLinkCount(obj); |
| 2620 | - |
| 2621 | - T(YAFFS_TRACE_OS, |
| 2622 | - ("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n", |
| 2623 | - inode->i_mode, inode->i_uid, inode->i_gid, |
| 2624 | - (int)inode->i_size, atomic_read(&inode->i_count))); |
| 2625 | - |
| 2626 | - switch (obj->yst_mode & S_IFMT) { |
| 2627 | - default: /* fifo, device or socket */ |
| 2628 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 2629 | - init_special_inode(inode, obj->yst_mode, |
| 2630 | - old_decode_dev(obj->yst_rdev)); |
| 2631 | -#else |
| 2632 | - init_special_inode(inode, obj->yst_mode, |
| 2633 | - (dev_t) (obj->yst_rdev)); |
| 2634 | -#endif |
| 2635 | - break; |
| 2636 | - case S_IFREG: /* file */ |
| 2637 | - inode->i_op = &yaffs_file_inode_operations; |
| 2638 | - inode->i_fop = &yaffs_file_operations; |
| 2639 | - inode->i_mapping->a_ops = |
| 2640 | - &yaffs_file_address_operations; |
| 2641 | - break; |
| 2642 | - case S_IFDIR: /* directory */ |
| 2643 | - inode->i_op = &yaffs_dir_inode_operations; |
| 2644 | - inode->i_fop = &yaffs_dir_operations; |
| 2645 | - break; |
| 2646 | - case S_IFLNK: /* symlink */ |
| 2647 | - inode->i_op = &yaffs_symlink_inode_operations; |
| 2648 | - break; |
| 2649 | - } |
| 2650 | - |
| 2651 | - yaffs_InodeToObjectLV(inode) = obj; |
| 2652 | - |
| 2653 | - obj->myInode = inode; |
| 2654 | - |
| 2655 | - } else { |
| 2656 | - T(YAFFS_TRACE_OS, |
| 2657 | - ("yaffs_FileInode invalid parameters\n")); |
| 2658 | - } |
| 2659 | - |
| 2660 | -} |
| 2661 | - |
| 2662 | -struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, |
| 2663 | - yaffs_Object *obj) |
| 2664 | -{ |
| 2665 | - struct inode *inode; |
| 2666 | - |
| 2667 | - if (!sb) { |
| 2668 | - T(YAFFS_TRACE_OS, |
| 2669 | - ("yaffs_get_inode for NULL super_block!!\n")); |
| 2670 | - return NULL; |
| 2671 | - |
| 2672 | - } |
| 2673 | - |
| 2674 | - if (!obj) { |
| 2675 | - T(YAFFS_TRACE_OS, |
| 2676 | - ("yaffs_get_inode for NULL object!!\n")); |
| 2677 | - return NULL; |
| 2678 | - |
| 2679 | - } |
| 2680 | - |
| 2681 | - T(YAFFS_TRACE_OS, |
| 2682 | - ("yaffs_get_inode for object %d\n", obj->objectId)); |
| 2683 | - |
| 2684 | - inode = Y_IGET(sb, obj->objectId); |
| 2685 | - if (IS_ERR(inode)) |
| 2686 | - return NULL; |
| 2687 | - |
| 2688 | - /* NB Side effect: iget calls back to yaffs_read_inode(). */ |
| 2689 | - /* iget also increments the inode's i_count */ |
| 2690 | - /* NB You can't be holding grossLock or deadlock will happen! */ |
| 2691 | - |
| 2692 | - return inode; |
| 2693 | -} |
| 2694 | - |
| 2695 | -static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, |
| 2696 | - loff_t *pos) |
| 2697 | -{ |
| 2698 | - yaffs_Object *obj; |
| 2699 | - int nWritten, ipos; |
| 2700 | - struct inode *inode; |
| 2701 | - yaffs_Device *dev; |
| 2702 | - |
| 2703 | - obj = yaffs_DentryToObject(f->f_dentry); |
| 2704 | - |
| 2705 | - dev = obj->myDev; |
| 2706 | - |
| 2707 | - yaffs_GrossLock(dev); |
| 2708 | - |
| 2709 | - inode = f->f_dentry->d_inode; |
| 2710 | - |
| 2711 | - if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) |
| 2712 | - ipos = inode->i_size; |
| 2713 | - else |
| 2714 | - ipos = *pos; |
| 2715 | - |
| 2716 | - if (!obj) |
| 2717 | - T(YAFFS_TRACE_OS, |
| 2718 | - ("yaffs_file_write: hey obj is null!\n")); |
| 2719 | - else |
| 2720 | - T(YAFFS_TRACE_OS, |
| 2721 | - ("yaffs_file_write about to write writing %zu bytes" |
| 2722 | - "to object %d at %d\n", |
| 2723 | - n, obj->objectId, ipos)); |
| 2724 | - |
| 2725 | - nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0); |
| 2726 | - |
| 2727 | - T(YAFFS_TRACE_OS, |
| 2728 | - ("yaffs_file_write writing %zu bytes, %d written at %d\n", |
| 2729 | - n, nWritten, ipos)); |
| 2730 | - |
| 2731 | - if (nWritten > 0) { |
| 2732 | - ipos += nWritten; |
| 2733 | - *pos = ipos; |
| 2734 | - if (ipos > inode->i_size) { |
| 2735 | - inode->i_size = ipos; |
| 2736 | - inode->i_blocks = (ipos + 511) >> 9; |
| 2737 | - |
| 2738 | - T(YAFFS_TRACE_OS, |
| 2739 | - ("yaffs_file_write size updated to %d bytes, " |
| 2740 | - "%d blocks\n", |
| 2741 | - ipos, (int)(inode->i_blocks))); |
| 2742 | - } |
| 2743 | - |
| 2744 | - } |
| 2745 | - yaffs_GrossUnlock(dev); |
| 2746 | - return nWritten == 0 ? -ENOSPC : nWritten; |
| 2747 | -} |
| 2748 | - |
| 2749 | -/* Space holding and freeing is done to ensure we have space available for write_begin/end */ |
| 2750 | -/* For now we just assume few parallel writes and check against a small number. */ |
| 2751 | -/* Todo: need to do this with a counter to handle parallel reads better */ |
| 2752 | - |
| 2753 | -static ssize_t yaffs_hold_space(struct file *f) |
| 2754 | -{ |
| 2755 | - yaffs_Object *obj; |
| 2756 | - yaffs_Device *dev; |
| 2757 | - |
| 2758 | - int nFreeChunks; |
| 2759 | - |
| 2760 | - |
| 2761 | - obj = yaffs_DentryToObject(f->f_dentry); |
| 2762 | - |
| 2763 | - dev = obj->myDev; |
| 2764 | - |
| 2765 | - yaffs_GrossLock(dev); |
| 2766 | - |
| 2767 | - nFreeChunks = yaffs_GetNumberOfFreeChunks(dev); |
| 2768 | - |
| 2769 | - yaffs_GrossUnlock(dev); |
| 2770 | - |
| 2771 | - return (nFreeChunks > 20) ? 1 : 0; |
| 2772 | -} |
| 2773 | - |
| 2774 | -static void yaffs_release_space(struct file *f) |
| 2775 | -{ |
| 2776 | - yaffs_Object *obj; |
| 2777 | - yaffs_Device *dev; |
| 2778 | - |
| 2779 | - |
| 2780 | - obj = yaffs_DentryToObject(f->f_dentry); |
| 2781 | - |
| 2782 | - dev = obj->myDev; |
| 2783 | - |
| 2784 | - yaffs_GrossLock(dev); |
| 2785 | - |
| 2786 | - |
| 2787 | - yaffs_GrossUnlock(dev); |
| 2788 | -} |
| 2789 | - |
| 2790 | -static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) |
| 2791 | -{ |
| 2792 | - yaffs_Object *obj; |
| 2793 | - yaffs_Device *dev; |
| 2794 | - struct inode *inode = f->f_dentry->d_inode; |
| 2795 | - unsigned long offset, curoffs; |
| 2796 | - struct ylist_head *i; |
| 2797 | - yaffs_Object *l; |
| 2798 | - |
| 2799 | - char name[YAFFS_MAX_NAME_LENGTH + 1]; |
| 2800 | - |
| 2801 | - obj = yaffs_DentryToObject(f->f_dentry); |
| 2802 | - dev = obj->myDev; |
| 2803 | - |
| 2804 | - yaffs_GrossLock(dev); |
| 2805 | - |
| 2806 | - offset = f->f_pos; |
| 2807 | - |
| 2808 | - T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset)); |
| 2809 | - |
| 2810 | - if (offset == 0) { |
| 2811 | - T(YAFFS_TRACE_OS, |
| 2812 | - ("yaffs_readdir: entry . ino %d \n", |
| 2813 | - (int)inode->i_ino)); |
| 2814 | - if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) |
| 2815 | - goto out; |
| 2816 | - offset++; |
| 2817 | - f->f_pos++; |
| 2818 | - } |
| 2819 | - if (offset == 1) { |
| 2820 | - T(YAFFS_TRACE_OS, |
| 2821 | - ("yaffs_readdir: entry .. ino %d \n", |
| 2822 | - (int)f->f_dentry->d_parent->d_inode->i_ino)); |
| 2823 | - if (filldir(dirent, "..", 2, offset, |
| 2824 | - f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) |
| 2825 | - goto out; |
| 2826 | - offset++; |
| 2827 | - f->f_pos++; |
| 2828 | - } |
| 2829 | - |
| 2830 | - curoffs = 1; |
| 2831 | - |
| 2832 | - /* If the directory has changed since the open or last call to |
| 2833 | - readdir, rewind to after the 2 canned entries. */ |
| 2834 | - |
| 2835 | - if (f->f_version != inode->i_version) { |
| 2836 | - offset = 2; |
| 2837 | - f->f_pos = offset; |
| 2838 | - f->f_version = inode->i_version; |
| 2839 | - } |
| 2840 | - |
| 2841 | - ylist_for_each(i, &obj->variant.directoryVariant.children) { |
| 2842 | - curoffs++; |
| 2843 | - if (curoffs >= offset) { |
| 2844 | - l = ylist_entry(i, yaffs_Object, siblings); |
| 2845 | - |
| 2846 | - yaffs_GetObjectName(l, name, |
| 2847 | - YAFFS_MAX_NAME_LENGTH + 1); |
| 2848 | - T(YAFFS_TRACE_OS, |
| 2849 | - ("yaffs_readdir: %s inode %d\n", name, |
| 2850 | - yaffs_GetObjectInode(l))); |
| 2851 | - |
| 2852 | - if (filldir(dirent, |
| 2853 | - name, |
| 2854 | - strlen(name), |
| 2855 | - offset, |
| 2856 | - yaffs_GetObjectInode(l), |
| 2857 | - yaffs_GetObjectType(l)) < 0) |
| 2858 | - goto up_and_out; |
| 2859 | - |
| 2860 | - offset++; |
| 2861 | - f->f_pos++; |
| 2862 | - } |
| 2863 | - } |
| 2864 | - |
| 2865 | -up_and_out: |
| 2866 | -out: |
| 2867 | - yaffs_GrossUnlock(dev); |
| 2868 | - |
| 2869 | - return 0; |
| 2870 | -} |
| 2871 | - |
| 2872 | -/* |
| 2873 | - * File creation. Allocate an inode, and we're done.. |
| 2874 | - */ |
| 2875 | - |
| 2876 | -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) |
| 2877 | -#define YCRED(x) x |
| 2878 | -#else |
| 2879 | -#define YCRED(x) (x->cred) |
| 2880 | -#endif |
| 2881 | - |
| 2882 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 2883 | -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, |
| 2884 | - dev_t rdev) |
| 2885 | -#else |
| 2886 | -static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, |
| 2887 | - int rdev) |
| 2888 | -#endif |
| 2889 | -{ |
| 2890 | - struct inode *inode; |
| 2891 | - |
| 2892 | - yaffs_Object *obj = NULL; |
| 2893 | - yaffs_Device *dev; |
| 2894 | - |
| 2895 | - yaffs_Object *parent = yaffs_InodeToObject(dir); |
| 2896 | - |
| 2897 | - int error = -ENOSPC; |
| 2898 | - uid_t uid = YCRED(current)->fsuid; |
| 2899 | - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; |
| 2900 | - |
| 2901 | - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) |
| 2902 | - mode |= S_ISGID; |
| 2903 | - |
| 2904 | - if (parent) { |
| 2905 | - T(YAFFS_TRACE_OS, |
| 2906 | - ("yaffs_mknod: parent object %d type %d\n", |
| 2907 | - parent->objectId, parent->variantType)); |
| 2908 | - } else { |
| 2909 | - T(YAFFS_TRACE_OS, |
| 2910 | - ("yaffs_mknod: could not get parent object\n")); |
| 2911 | - return -EPERM; |
| 2912 | - } |
| 2913 | - |
| 2914 | - T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, " |
| 2915 | - "mode %x dev %x\n", |
| 2916 | - dentry->d_name.name, mode, rdev)); |
| 2917 | - |
| 2918 | - dev = parent->myDev; |
| 2919 | - |
| 2920 | - yaffs_GrossLock(dev); |
| 2921 | - |
| 2922 | - switch (mode & S_IFMT) { |
| 2923 | - default: |
| 2924 | - /* Special (socket, fifo, device...) */ |
| 2925 | - T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n")); |
| 2926 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 2927 | - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid, |
| 2928 | - gid, old_encode_dev(rdev)); |
| 2929 | -#else |
| 2930 | - obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid, |
| 2931 | - gid, rdev); |
| 2932 | -#endif |
| 2933 | - break; |
| 2934 | - case S_IFREG: /* file */ |
| 2935 | - T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n")); |
| 2936 | - obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid, |
| 2937 | - gid); |
| 2938 | - break; |
| 2939 | - case S_IFDIR: /* directory */ |
| 2940 | - T(YAFFS_TRACE_OS, |
| 2941 | - ("yaffs_mknod: making directory\n")); |
| 2942 | - obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode, |
| 2943 | - uid, gid); |
| 2944 | - break; |
| 2945 | - case S_IFLNK: /* symlink */ |
| 2946 | - T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n")); |
| 2947 | - obj = NULL; /* Do we ever get here? */ |
| 2948 | - break; |
| 2949 | - } |
| 2950 | - |
| 2951 | - /* Can not call yaffs_get_inode() with gross lock held */ |
| 2952 | - yaffs_GrossUnlock(dev); |
| 2953 | - |
| 2954 | - if (obj) { |
| 2955 | - inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); |
| 2956 | - d_instantiate(dentry, inode); |
| 2957 | - T(YAFFS_TRACE_OS, |
| 2958 | - ("yaffs_mknod created object %d count = %d\n", |
| 2959 | - obj->objectId, atomic_read(&inode->i_count))); |
| 2960 | - error = 0; |
| 2961 | - } else { |
| 2962 | - T(YAFFS_TRACE_OS, |
| 2963 | - ("yaffs_mknod failed making object\n")); |
| 2964 | - error = -ENOMEM; |
| 2965 | - } |
| 2966 | - |
| 2967 | - return error; |
| 2968 | -} |
| 2969 | - |
| 2970 | -static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
| 2971 | -{ |
| 2972 | - int retVal; |
| 2973 | - T(YAFFS_TRACE_OS, ("yaffs_mkdir\n")); |
| 2974 | - retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); |
| 2975 | - return retVal; |
| 2976 | -} |
| 2977 | - |
| 2978 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 2979 | -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, |
| 2980 | - struct nameidata *n) |
| 2981 | -#else |
| 2982 | -static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode) |
| 2983 | -#endif |
| 2984 | -{ |
| 2985 | - T(YAFFS_TRACE_OS, ("yaffs_create\n")); |
| 2986 | - return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); |
| 2987 | -} |
| 2988 | - |
| 2989 | -static int yaffs_unlink(struct inode *dir, struct dentry *dentry) |
| 2990 | -{ |
| 2991 | - int retVal; |
| 2992 | - |
| 2993 | - yaffs_Device *dev; |
| 2994 | - |
| 2995 | - T(YAFFS_TRACE_OS, |
| 2996 | - ("yaffs_unlink %d:%s\n", (int)(dir->i_ino), |
| 2997 | - dentry->d_name.name)); |
| 2998 | - |
| 2999 | - dev = yaffs_InodeToObject(dir)->myDev; |
| 3000 | - |
| 3001 | - yaffs_GrossLock(dev); |
| 3002 | - |
| 3003 | - retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name); |
| 3004 | - |
| 3005 | - if (retVal == YAFFS_OK) { |
| 3006 | - dentry->d_inode->i_nlink--; |
| 3007 | - dir->i_version++; |
| 3008 | - yaffs_GrossUnlock(dev); |
| 3009 | - mark_inode_dirty(dentry->d_inode); |
| 3010 | - return 0; |
| 3011 | - } |
| 3012 | - yaffs_GrossUnlock(dev); |
| 3013 | - return -ENOTEMPTY; |
| 3014 | -} |
| 3015 | - |
| 3016 | -/* |
| 3017 | - * Create a link... |
| 3018 | - */ |
| 3019 | -static int yaffs_link(struct dentry *old_dentry, struct inode *dir, |
| 3020 | - struct dentry *dentry) |
| 3021 | -{ |
| 3022 | - struct inode *inode = old_dentry->d_inode; |
| 3023 | - yaffs_Object *obj = NULL; |
| 3024 | - yaffs_Object *link = NULL; |
| 3025 | - yaffs_Device *dev; |
| 3026 | - |
| 3027 | - T(YAFFS_TRACE_OS, ("yaffs_link\n")); |
| 3028 | - |
| 3029 | - obj = yaffs_InodeToObject(inode); |
| 3030 | - dev = obj->myDev; |
| 3031 | - |
| 3032 | - yaffs_GrossLock(dev); |
| 3033 | - |
| 3034 | - if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ |
| 3035 | - link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name, |
| 3036 | - obj); |
| 3037 | - |
| 3038 | - if (link) { |
| 3039 | - old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj); |
| 3040 | - d_instantiate(dentry, old_dentry->d_inode); |
| 3041 | - atomic_inc(&old_dentry->d_inode->i_count); |
| 3042 | - T(YAFFS_TRACE_OS, |
| 3043 | - ("yaffs_link link count %d i_count %d\n", |
| 3044 | - old_dentry->d_inode->i_nlink, |
| 3045 | - atomic_read(&old_dentry->d_inode->i_count))); |
| 3046 | - } |
| 3047 | - |
| 3048 | - yaffs_GrossUnlock(dev); |
| 3049 | - |
| 3050 | - if (link) |
| 3051 | - return 0; |
| 3052 | - |
| 3053 | - return -EPERM; |
| 3054 | -} |
| 3055 | - |
| 3056 | -static int yaffs_symlink(struct inode *dir, struct dentry *dentry, |
| 3057 | - const char *symname) |
| 3058 | -{ |
| 3059 | - yaffs_Object *obj; |
| 3060 | - yaffs_Device *dev; |
| 3061 | - uid_t uid = YCRED(current)->fsuid; |
| 3062 | - gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; |
| 3063 | - |
| 3064 | - T(YAFFS_TRACE_OS, ("yaffs_symlink\n")); |
| 3065 | - |
| 3066 | - dev = yaffs_InodeToObject(dir)->myDev; |
| 3067 | - yaffs_GrossLock(dev); |
| 3068 | - obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name, |
| 3069 | - S_IFLNK | S_IRWXUGO, uid, gid, symname); |
| 3070 | - yaffs_GrossUnlock(dev); |
| 3071 | - |
| 3072 | - if (obj) { |
| 3073 | - struct inode *inode; |
| 3074 | - |
| 3075 | - inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); |
| 3076 | - d_instantiate(dentry, inode); |
| 3077 | - T(YAFFS_TRACE_OS, ("symlink created OK\n")); |
| 3078 | - return 0; |
| 3079 | - } else { |
| 3080 | - T(YAFFS_TRACE_OS, ("symlink not created\n")); |
| 3081 | - } |
| 3082 | - |
| 3083 | - return -ENOMEM; |
| 3084 | -} |
| 3085 | - |
| 3086 | -static int yaffs_sync_object(struct file *file, struct dentry *dentry, |
| 3087 | - int datasync) |
| 3088 | -{ |
| 3089 | - |
| 3090 | - yaffs_Object *obj; |
| 3091 | - yaffs_Device *dev; |
| 3092 | - |
| 3093 | - obj = yaffs_DentryToObject(dentry); |
| 3094 | - |
| 3095 | - dev = obj->myDev; |
| 3096 | - |
| 3097 | - T(YAFFS_TRACE_OS, ("yaffs_sync_object\n")); |
| 3098 | - yaffs_GrossLock(dev); |
| 3099 | - yaffs_FlushFile(obj, 1); |
| 3100 | - yaffs_GrossUnlock(dev); |
| 3101 | - return 0; |
| 3102 | -} |
| 3103 | - |
| 3104 | -/* |
| 3105 | - * The VFS layer already does all the dentry stuff for rename. |
| 3106 | - * |
| 3107 | - * NB: POSIX says you can rename an object over an old object of the same name |
| 3108 | - */ |
| 3109 | -static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, |
| 3110 | - struct inode *new_dir, struct dentry *new_dentry) |
| 3111 | -{ |
| 3112 | - yaffs_Device *dev; |
| 3113 | - int retVal = YAFFS_FAIL; |
| 3114 | - yaffs_Object *target; |
| 3115 | - |
| 3116 | - T(YAFFS_TRACE_OS, ("yaffs_rename\n")); |
| 3117 | - dev = yaffs_InodeToObject(old_dir)->myDev; |
| 3118 | - |
| 3119 | - yaffs_GrossLock(dev); |
| 3120 | - |
| 3121 | - /* Check if the target is an existing directory that is not empty. */ |
| 3122 | - target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir), |
| 3123 | - new_dentry->d_name.name); |
| 3124 | - |
| 3125 | - |
| 3126 | - |
| 3127 | - if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && |
| 3128 | - !ylist_empty(&target->variant.directoryVariant.children)) { |
| 3129 | - |
| 3130 | - T(YAFFS_TRACE_OS, ("target is non-empty dir\n")); |
| 3131 | - |
| 3132 | - retVal = YAFFS_FAIL; |
| 3133 | - } else { |
| 3134 | - /* Now does unlinking internally using shadowing mechanism */ |
| 3135 | - T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n")); |
| 3136 | - |
| 3137 | - retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir), |
| 3138 | - old_dentry->d_name.name, |
| 3139 | - yaffs_InodeToObject(new_dir), |
| 3140 | - new_dentry->d_name.name); |
| 3141 | - } |
| 3142 | - yaffs_GrossUnlock(dev); |
| 3143 | - |
| 3144 | - if (retVal == YAFFS_OK) { |
| 3145 | - if (target) { |
| 3146 | - new_dentry->d_inode->i_nlink--; |
| 3147 | - mark_inode_dirty(new_dentry->d_inode); |
| 3148 | - } |
| 3149 | - |
| 3150 | - return 0; |
| 3151 | - } else { |
| 3152 | - return -ENOTEMPTY; |
| 3153 | - } |
| 3154 | -} |
| 3155 | - |
| 3156 | -static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) |
| 3157 | -{ |
| 3158 | - struct inode *inode = dentry->d_inode; |
| 3159 | - int error; |
| 3160 | - yaffs_Device *dev; |
| 3161 | - |
| 3162 | - T(YAFFS_TRACE_OS, |
| 3163 | - ("yaffs_setattr of object %d\n", |
| 3164 | - yaffs_InodeToObject(inode)->objectId)); |
| 3165 | - |
| 3166 | - error = inode_change_ok(inode, attr); |
| 3167 | - if (error == 0) { |
| 3168 | - dev = yaffs_InodeToObject(inode)->myDev; |
| 3169 | - yaffs_GrossLock(dev); |
| 3170 | - if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) == |
| 3171 | - YAFFS_OK) { |
| 3172 | - error = 0; |
| 3173 | - } else { |
| 3174 | - error = -EPERM; |
| 3175 | - } |
| 3176 | - yaffs_GrossUnlock(dev); |
| 3177 | - if (!error) |
| 3178 | - error = inode_setattr(inode, attr); |
| 3179 | - } |
| 3180 | - return error; |
| 3181 | -} |
| 3182 | - |
| 3183 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 3184 | -static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) |
| 3185 | -{ |
| 3186 | - yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; |
| 3187 | - struct super_block *sb = dentry->d_sb; |
| 3188 | -#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 3189 | -static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf) |
| 3190 | -{ |
| 3191 | - yaffs_Device *dev = yaffs_SuperToDevice(sb); |
| 3192 | -#else |
| 3193 | -static int yaffs_statfs(struct super_block *sb, struct statfs *buf) |
| 3194 | -{ |
| 3195 | - yaffs_Device *dev = yaffs_SuperToDevice(sb); |
| 3196 | -#endif |
| 3197 | - |
| 3198 | - T(YAFFS_TRACE_OS, ("yaffs_statfs\n")); |
| 3199 | - |
| 3200 | - yaffs_GrossLock(dev); |
| 3201 | - |
| 3202 | - buf->f_type = YAFFS_MAGIC; |
| 3203 | - buf->f_bsize = sb->s_blocksize; |
| 3204 | - buf->f_namelen = 255; |
| 3205 | - |
| 3206 | - if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) { |
| 3207 | - /* Do this if chunk size is not a power of 2 */ |
| 3208 | - |
| 3209 | - uint64_t bytesInDev; |
| 3210 | - uint64_t bytesFree; |
| 3211 | - |
| 3212 | - bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) * |
| 3213 | - ((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk)); |
| 3214 | - |
| 3215 | - do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */ |
| 3216 | - buf->f_blocks = bytesInDev; |
| 3217 | - |
| 3218 | - bytesFree = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) * |
| 3219 | - ((uint64_t)(dev->nDataBytesPerChunk)); |
| 3220 | - |
| 3221 | - do_div(bytesFree, sb->s_blocksize); |
| 3222 | - |
| 3223 | - buf->f_bfree = bytesFree; |
| 3224 | - |
| 3225 | - } else if (sb->s_blocksize > dev->nDataBytesPerChunk) { |
| 3226 | - |
| 3227 | - buf->f_blocks = |
| 3228 | - (dev->endBlock - dev->startBlock + 1) * |
| 3229 | - dev->nChunksPerBlock / |
| 3230 | - (sb->s_blocksize / dev->nDataBytesPerChunk); |
| 3231 | - buf->f_bfree = |
| 3232 | - yaffs_GetNumberOfFreeChunks(dev) / |
| 3233 | - (sb->s_blocksize / dev->nDataBytesPerChunk); |
| 3234 | - } else { |
| 3235 | - buf->f_blocks = |
| 3236 | - (dev->endBlock - dev->startBlock + 1) * |
| 3237 | - dev->nChunksPerBlock * |
| 3238 | - (dev->nDataBytesPerChunk / sb->s_blocksize); |
| 3239 | - |
| 3240 | - buf->f_bfree = |
| 3241 | - yaffs_GetNumberOfFreeChunks(dev) * |
| 3242 | - (dev->nDataBytesPerChunk / sb->s_blocksize); |
| 3243 | - } |
| 3244 | - |
| 3245 | - buf->f_files = 0; |
| 3246 | - buf->f_ffree = 0; |
| 3247 | - buf->f_bavail = buf->f_bfree; |
| 3248 | - |
| 3249 | - yaffs_GrossUnlock(dev); |
| 3250 | - return 0; |
| 3251 | -} |
| 3252 | - |
| 3253 | - |
| 3254 | -static int yaffs_do_sync_fs(struct super_block *sb) |
| 3255 | -{ |
| 3256 | - |
| 3257 | - yaffs_Device *dev = yaffs_SuperToDevice(sb); |
| 3258 | - T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n")); |
| 3259 | - |
| 3260 | - if (sb->s_dirt) { |
| 3261 | - yaffs_GrossLock(dev); |
| 3262 | - |
| 3263 | - if (dev) { |
| 3264 | - yaffs_FlushEntireDeviceCache(dev); |
| 3265 | - yaffs_CheckpointSave(dev); |
| 3266 | - } |
| 3267 | - |
| 3268 | - yaffs_GrossUnlock(dev); |
| 3269 | - |
| 3270 | - sb->s_dirt = 0; |
| 3271 | - } |
| 3272 | - return 0; |
| 3273 | -} |
| 3274 | - |
| 3275 | - |
| 3276 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 3277 | -static void yaffs_write_super(struct super_block *sb) |
| 3278 | -#else |
| 3279 | -static int yaffs_write_super(struct super_block *sb) |
| 3280 | -#endif |
| 3281 | -{ |
| 3282 | - |
| 3283 | - T(YAFFS_TRACE_OS, ("yaffs_write_super\n")); |
| 3284 | - if (yaffs_auto_checkpoint >= 2) |
| 3285 | - yaffs_do_sync_fs(sb); |
| 3286 | -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) |
| 3287 | - return 0; |
| 3288 | -#endif |
| 3289 | -} |
| 3290 | - |
| 3291 | - |
| 3292 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 3293 | -static int yaffs_sync_fs(struct super_block *sb, int wait) |
| 3294 | -#else |
| 3295 | -static int yaffs_sync_fs(struct super_block *sb) |
| 3296 | -#endif |
| 3297 | -{ |
| 3298 | - T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n")); |
| 3299 | - |
| 3300 | - if (yaffs_auto_checkpoint >= 1) |
| 3301 | - yaffs_do_sync_fs(sb); |
| 3302 | - |
| 3303 | - return 0; |
| 3304 | -} |
| 3305 | - |
| 3306 | -#ifdef YAFFS_USE_OWN_IGET |
| 3307 | - |
| 3308 | -static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) |
| 3309 | -{ |
| 3310 | - struct inode *inode; |
| 3311 | - yaffs_Object *obj; |
| 3312 | - yaffs_Device *dev = yaffs_SuperToDevice(sb); |
| 3313 | - |
| 3314 | - T(YAFFS_TRACE_OS, |
| 3315 | - ("yaffs_iget for %lu\n", ino)); |
| 3316 | - |
| 3317 | - inode = iget_locked(sb, ino); |
| 3318 | - if (!inode) |
| 3319 | - return ERR_PTR(-ENOMEM); |
| 3320 | - if (!(inode->i_state & I_NEW)) |
| 3321 | - return inode; |
| 3322 | - |
| 3323 | - /* NB This is called as a side effect of other functions, but |
| 3324 | - * we had to release the lock to prevent deadlocks, so |
| 3325 | - * need to lock again. |
| 3326 | - */ |
| 3327 | - |
| 3328 | - yaffs_GrossLock(dev); |
| 3329 | - |
| 3330 | - obj = yaffs_FindObjectByNumber(dev, inode->i_ino); |
| 3331 | - |
| 3332 | - yaffs_FillInodeFromObject(inode, obj); |
| 3333 | - |
| 3334 | - yaffs_GrossUnlock(dev); |
| 3335 | - |
| 3336 | - unlock_new_inode(inode); |
| 3337 | - return inode; |
| 3338 | -} |
| 3339 | - |
| 3340 | -#else |
| 3341 | - |
| 3342 | -static void yaffs_read_inode(struct inode *inode) |
| 3343 | -{ |
| 3344 | - /* NB This is called as a side effect of other functions, but |
| 3345 | - * we had to release the lock to prevent deadlocks, so |
| 3346 | - * need to lock again. |
| 3347 | - */ |
| 3348 | - |
| 3349 | - yaffs_Object *obj; |
| 3350 | - yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb); |
| 3351 | - |
| 3352 | - T(YAFFS_TRACE_OS, |
| 3353 | - ("yaffs_read_inode for %d\n", (int)inode->i_ino)); |
| 3354 | - |
| 3355 | - yaffs_GrossLock(dev); |
| 3356 | - |
| 3357 | - obj = yaffs_FindObjectByNumber(dev, inode->i_ino); |
| 3358 | - |
| 3359 | - yaffs_FillInodeFromObject(inode, obj); |
| 3360 | - |
| 3361 | - yaffs_GrossUnlock(dev); |
| 3362 | -} |
| 3363 | - |
| 3364 | -#endif |
| 3365 | - |
| 3366 | -static YLIST_HEAD(yaffs_dev_list); |
| 3367 | - |
| 3368 | -#if 0 /* not used */ |
| 3369 | -static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) |
| 3370 | -{ |
| 3371 | - yaffs_Device *dev = yaffs_SuperToDevice(sb); |
| 3372 | - |
| 3373 | - if (*flags & MS_RDONLY) { |
| 3374 | - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; |
| 3375 | - |
| 3376 | - T(YAFFS_TRACE_OS, |
| 3377 | - ("yaffs_remount_fs: %s: RO\n", dev->name)); |
| 3378 | - |
| 3379 | - yaffs_GrossLock(dev); |
| 3380 | - |
| 3381 | - yaffs_FlushEntireDeviceCache(dev); |
| 3382 | - |
| 3383 | - yaffs_CheckpointSave(dev); |
| 3384 | - |
| 3385 | - if (mtd->sync) |
| 3386 | - mtd->sync(mtd); |
| 3387 | - |
| 3388 | - yaffs_GrossUnlock(dev); |
| 3389 | - } else { |
| 3390 | - T(YAFFS_TRACE_OS, |
| 3391 | - ("yaffs_remount_fs: %s: RW\n", dev->name)); |
| 3392 | - } |
| 3393 | - |
| 3394 | - return 0; |
| 3395 | -} |
| 3396 | -#endif |
| 3397 | - |
| 3398 | -static void yaffs_put_super(struct super_block *sb) |
| 3399 | -{ |
| 3400 | - yaffs_Device *dev = yaffs_SuperToDevice(sb); |
| 3401 | - |
| 3402 | - T(YAFFS_TRACE_OS, ("yaffs_put_super\n")); |
| 3403 | - |
| 3404 | - yaffs_GrossLock(dev); |
| 3405 | - |
| 3406 | - yaffs_FlushEntireDeviceCache(dev); |
| 3407 | - |
| 3408 | - yaffs_CheckpointSave(dev); |
| 3409 | - |
| 3410 | - if (dev->putSuperFunc) |
| 3411 | - dev->putSuperFunc(sb); |
| 3412 | - |
| 3413 | - yaffs_Deinitialise(dev); |
| 3414 | - |
| 3415 | - yaffs_GrossUnlock(dev); |
| 3416 | - |
| 3417 | - /* we assume this is protected by lock_kernel() in mount/umount */ |
| 3418 | - ylist_del(&dev->devList); |
| 3419 | - |
| 3420 | - if (dev->spareBuffer) { |
| 3421 | - YFREE(dev->spareBuffer); |
| 3422 | - dev->spareBuffer = NULL; |
| 3423 | - } |
| 3424 | - |
| 3425 | - kfree(dev); |
| 3426 | -} |
| 3427 | - |
| 3428 | - |
| 3429 | -static void yaffs_MTDPutSuper(struct super_block *sb) |
| 3430 | -{ |
| 3431 | - struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; |
| 3432 | - |
| 3433 | - if (mtd->sync) |
| 3434 | - mtd->sync(mtd); |
| 3435 | - |
| 3436 | - put_mtd_device(mtd); |
| 3437 | -} |
| 3438 | - |
| 3439 | - |
| 3440 | -static void yaffs_MarkSuperBlockDirty(void *vsb) |
| 3441 | -{ |
| 3442 | - struct super_block *sb = (struct super_block *)vsb; |
| 3443 | - |
| 3444 | - T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb)); |
| 3445 | - if (sb) |
| 3446 | - sb->s_dirt = 1; |
| 3447 | -} |
| 3448 | - |
| 3449 | -typedef struct { |
| 3450 | - int inband_tags; |
| 3451 | - int skip_checkpoint_read; |
| 3452 | - int skip_checkpoint_write; |
| 3453 | - int no_cache; |
| 3454 | -} yaffs_options; |
| 3455 | - |
| 3456 | -#define MAX_OPT_LEN 20 |
| 3457 | -static int yaffs_parse_options(yaffs_options *options, const char *options_str) |
| 3458 | -{ |
| 3459 | - char cur_opt[MAX_OPT_LEN + 1]; |
| 3460 | - int p; |
| 3461 | - int error = 0; |
| 3462 | - |
| 3463 | - /* Parse through the options which is a comma seperated list */ |
| 3464 | - |
| 3465 | - while (options_str && *options_str && !error) { |
| 3466 | - memset(cur_opt, 0, MAX_OPT_LEN + 1); |
| 3467 | - p = 0; |
| 3468 | - |
| 3469 | - while (*options_str && *options_str != ',') { |
| 3470 | - if (p < MAX_OPT_LEN) { |
| 3471 | - cur_opt[p] = *options_str; |
| 3472 | - p++; |
| 3473 | - } |
| 3474 | - options_str++; |
| 3475 | - } |
| 3476 | - |
| 3477 | - if (!strcmp(cur_opt, "inband-tags")) |
| 3478 | - options->inband_tags = 1; |
| 3479 | - else if (!strcmp(cur_opt, "no-cache")) |
| 3480 | - options->no_cache = 1; |
| 3481 | - else if (!strcmp(cur_opt, "no-checkpoint-read")) |
| 3482 | - options->skip_checkpoint_read = 1; |
| 3483 | - else if (!strcmp(cur_opt, "no-checkpoint-write")) |
| 3484 | - options->skip_checkpoint_write = 1; |
| 3485 | - else if (!strcmp(cur_opt, "no-checkpoint")) { |
| 3486 | - options->skip_checkpoint_read = 1; |
| 3487 | - options->skip_checkpoint_write = 1; |
| 3488 | - } else { |
| 3489 | - printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n", |
| 3490 | - cur_opt); |
| 3491 | - error = 1; |
| 3492 | - } |
| 3493 | - } |
| 3494 | - |
| 3495 | - return error; |
| 3496 | -} |
| 3497 | - |
| 3498 | -static struct super_block *yaffs_internal_read_super(int yaffsVersion, |
| 3499 | - struct super_block *sb, |
| 3500 | - void *data, int silent) |
| 3501 | -{ |
| 3502 | - int nBlocks; |
| 3503 | - struct inode *inode = NULL; |
| 3504 | - struct dentry *root; |
| 3505 | - yaffs_Device *dev = 0; |
| 3506 | - char devname_buf[BDEVNAME_SIZE + 1]; |
| 3507 | - struct mtd_info *mtd; |
| 3508 | - int err; |
| 3509 | - char *data_str = (char *)data; |
| 3510 | - |
| 3511 | - yaffs_options options; |
| 3512 | - |
| 3513 | - sb->s_magic = YAFFS_MAGIC; |
| 3514 | - sb->s_op = &yaffs_super_ops; |
| 3515 | - sb->s_flags |= MS_NOATIME; |
| 3516 | - |
| 3517 | - if (!sb) |
| 3518 | - printk(KERN_INFO "yaffs: sb is NULL\n"); |
| 3519 | - else if (!sb->s_dev) |
| 3520 | - printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); |
| 3521 | - else if (!yaffs_devname(sb, devname_buf)) |
| 3522 | - printk(KERN_INFO "yaffs: devname is NULL\n"); |
| 3523 | - else |
| 3524 | - printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n", |
| 3525 | - sb->s_dev, |
| 3526 | - yaffs_devname(sb, devname_buf)); |
| 3527 | - |
| 3528 | - if (!data_str) |
| 3529 | - data_str = ""; |
| 3530 | - |
| 3531 | - printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str); |
| 3532 | - |
| 3533 | - memset(&options, 0, sizeof(options)); |
| 3534 | - |
| 3535 | - if (yaffs_parse_options(&options, data_str)) { |
| 3536 | - /* Option parsing failed */ |
| 3537 | - return NULL; |
| 3538 | - } |
| 3539 | - |
| 3540 | - |
| 3541 | - sb->s_blocksize = PAGE_CACHE_SIZE; |
| 3542 | - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
| 3543 | - T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion)); |
| 3544 | - T(YAFFS_TRACE_OS, |
| 3545 | - ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize))); |
| 3546 | - |
| 3547 | -#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY |
| 3548 | - T(YAFFS_TRACE_OS, |
| 3549 | - ("yaffs: Write verification disabled. All guarantees " |
| 3550 | - "null and void\n")); |
| 3551 | -#endif |
| 3552 | - |
| 3553 | - T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, " |
| 3554 | - "\"%s\"\n", |
| 3555 | - MAJOR(sb->s_dev), MINOR(sb->s_dev), |
| 3556 | - yaffs_devname(sb, devname_buf))); |
| 3557 | - |
| 3558 | - /* Check it's an mtd device..... */ |
| 3559 | - if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) |
| 3560 | - return NULL; /* This isn't an mtd device */ |
| 3561 | - |
| 3562 | - /* Get the device */ |
| 3563 | - mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); |
| 3564 | - if (!mtd) { |
| 3565 | - T(YAFFS_TRACE_ALWAYS, |
| 3566 | - ("yaffs: MTD device #%u doesn't appear to exist\n", |
| 3567 | - MINOR(sb->s_dev))); |
| 3568 | - return NULL; |
| 3569 | - } |
| 3570 | - /* Check it's NAND */ |
| 3571 | - if (mtd->type != MTD_NANDFLASH) { |
| 3572 | - T(YAFFS_TRACE_ALWAYS, |
| 3573 | - ("yaffs: MTD device is not NAND it's type %d\n", mtd->type)); |
| 3574 | - return NULL; |
| 3575 | - } |
| 3576 | - |
| 3577 | - T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase)); |
| 3578 | - T(YAFFS_TRACE_OS, (" read %p\n", mtd->read)); |
| 3579 | - T(YAFFS_TRACE_OS, (" write %p\n", mtd->write)); |
| 3580 | - T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob)); |
| 3581 | - T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob)); |
| 3582 | - T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad)); |
| 3583 | - T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad)); |
| 3584 | - T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd))); |
| 3585 | - T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize)); |
| 3586 | - T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize)); |
| 3587 | -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) |
| 3588 | - T(YAFFS_TRACE_OS, (" size %u\n", mtd->size)); |
| 3589 | -#else |
| 3590 | - T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size)); |
| 3591 | -#endif |
| 3592 | - |
| 3593 | -#ifdef CONFIG_YAFFS_AUTO_YAFFS2 |
| 3594 | - |
| 3595 | - if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) { |
| 3596 | - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n")); |
| 3597 | - yaffsVersion = 2; |
| 3598 | - } |
| 3599 | - |
| 3600 | - /* Added NCB 26/5/2006 for completeness */ |
| 3601 | - if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) { |
| 3602 | - T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n")); |
| 3603 | - yaffsVersion = 1; |
| 3604 | - } |
| 3605 | - |
| 3606 | -#endif |
| 3607 | - |
| 3608 | - if (yaffsVersion == 2) { |
| 3609 | - /* Check for version 2 style functions */ |
| 3610 | - if (!mtd->erase || |
| 3611 | - !mtd->block_isbad || |
| 3612 | - !mtd->block_markbad || |
| 3613 | - !mtd->read || |
| 3614 | - !mtd->write || |
| 3615 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 3616 | - !mtd->read_oob || !mtd->write_oob) { |
| 3617 | -#else |
| 3618 | - !mtd->write_ecc || |
| 3619 | - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { |
| 3620 | -#endif |
| 3621 | - T(YAFFS_TRACE_ALWAYS, |
| 3622 | - ("yaffs: MTD device does not support required " |
| 3623 | - "functions\n"));; |
| 3624 | - return NULL; |
| 3625 | - } |
| 3626 | - |
| 3627 | - if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || |
| 3628 | - mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && |
| 3629 | - !options.inband_tags) { |
| 3630 | - T(YAFFS_TRACE_ALWAYS, |
| 3631 | - ("yaffs: MTD device does not have the " |
| 3632 | - "right page sizes\n")); |
| 3633 | - return NULL; |
| 3634 | - } |
| 3635 | - } else { |
| 3636 | - /* Check for V1 style functions */ |
| 3637 | - if (!mtd->erase || |
| 3638 | - !mtd->read || |
| 3639 | - !mtd->write || |
| 3640 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 3641 | - !mtd->read_oob || !mtd->write_oob) { |
| 3642 | -#else |
| 3643 | - !mtd->write_ecc || |
| 3644 | - !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { |
| 3645 | -#endif |
| 3646 | - T(YAFFS_TRACE_ALWAYS, |
| 3647 | - ("yaffs: MTD device does not support required " |
| 3648 | - "functions\n"));; |
| 3649 | - return NULL; |
| 3650 | - } |
| 3651 | - |
| 3652 | - if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || |
| 3653 | - mtd->oobsize != YAFFS_BYTES_PER_SPARE) { |
| 3654 | - T(YAFFS_TRACE_ALWAYS, |
| 3655 | - ("yaffs: MTD device does not support have the " |
| 3656 | - "right page sizes\n")); |
| 3657 | - return NULL; |
| 3658 | - } |
| 3659 | - } |
| 3660 | - |
| 3661 | - /* OK, so if we got here, we have an MTD that's NAND and looks |
| 3662 | - * like it has the right capabilities |
| 3663 | - * Set the yaffs_Device up for mtd |
| 3664 | - */ |
| 3665 | - |
| 3666 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 3667 | - sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); |
| 3668 | -#else |
| 3669 | - sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL); |
| 3670 | -#endif |
| 3671 | - if (!dev) { |
| 3672 | - /* Deep shit could not allocate device structure */ |
| 3673 | - T(YAFFS_TRACE_ALWAYS, |
| 3674 | - ("yaffs_read_super: Failed trying to allocate " |
| 3675 | - "yaffs_Device. \n")); |
| 3676 | - return NULL; |
| 3677 | - } |
| 3678 | - |
| 3679 | - memset(dev, 0, sizeof(yaffs_Device)); |
| 3680 | - dev->genericDevice = mtd; |
| 3681 | - dev->name = mtd->name; |
| 3682 | - |
| 3683 | - /* Set up the memory size parameters.... */ |
| 3684 | - |
| 3685 | - nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK)); |
| 3686 | - |
| 3687 | - dev->startBlock = 0; |
| 3688 | - dev->endBlock = nBlocks - 1; |
| 3689 | - dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; |
| 3690 | - dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK; |
| 3691 | - dev->nReservedBlocks = 5; |
| 3692 | - dev->nShortOpCaches = (options.no_cache) ? 0 : 10; |
| 3693 | - dev->inbandTags = options.inband_tags; |
| 3694 | - |
| 3695 | - /* ... and the functions. */ |
| 3696 | - if (yaffsVersion == 2) { |
| 3697 | - dev->writeChunkWithTagsToNAND = |
| 3698 | - nandmtd2_WriteChunkWithTagsToNAND; |
| 3699 | - dev->readChunkWithTagsFromNAND = |
| 3700 | - nandmtd2_ReadChunkWithTagsFromNAND; |
| 3701 | - dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad; |
| 3702 | - dev->queryNANDBlock = nandmtd2_QueryNANDBlock; |
| 3703 | - dev->spareBuffer = YMALLOC(mtd->oobsize); |
| 3704 | - dev->isYaffs2 = 1; |
| 3705 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 3706 | - dev->totalBytesPerChunk = mtd->writesize; |
| 3707 | - dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; |
| 3708 | -#else |
| 3709 | - dev->totalBytesPerChunk = mtd->oobblock; |
| 3710 | - dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; |
| 3711 | -#endif |
| 3712 | - nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize); |
| 3713 | - |
| 3714 | - dev->startBlock = 0; |
| 3715 | - dev->endBlock = nBlocks - 1; |
| 3716 | - } else { |
| 3717 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 3718 | - /* use the MTD interface in yaffs_mtdif1.c */ |
| 3719 | - dev->writeChunkWithTagsToNAND = |
| 3720 | - nandmtd1_WriteChunkWithTagsToNAND; |
| 3721 | - dev->readChunkWithTagsFromNAND = |
| 3722 | - nandmtd1_ReadChunkWithTagsFromNAND; |
| 3723 | - dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad; |
| 3724 | - dev->queryNANDBlock = nandmtd1_QueryNANDBlock; |
| 3725 | -#else |
| 3726 | - dev->writeChunkToNAND = nandmtd_WriteChunkToNAND; |
| 3727 | - dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND; |
| 3728 | -#endif |
| 3729 | - dev->isYaffs2 = 0; |
| 3730 | - } |
| 3731 | - /* ... and common functions */ |
| 3732 | - dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND; |
| 3733 | - dev->initialiseNAND = nandmtd_InitialiseNAND; |
| 3734 | - |
| 3735 | - dev->putSuperFunc = yaffs_MTDPutSuper; |
| 3736 | - |
| 3737 | - dev->superBlock = (void *)sb; |
| 3738 | - dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; |
| 3739 | - |
| 3740 | - |
| 3741 | -#ifndef CONFIG_YAFFS_DOES_ECC |
| 3742 | - dev->useNANDECC = 1; |
| 3743 | -#endif |
| 3744 | - |
| 3745 | -#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES |
| 3746 | - dev->wideTnodesDisabled = 1; |
| 3747 | -#endif |
| 3748 | - |
| 3749 | - dev->skipCheckpointRead = options.skip_checkpoint_read; |
| 3750 | - dev->skipCheckpointWrite = options.skip_checkpoint_write; |
| 3751 | - |
| 3752 | - /* we assume this is protected by lock_kernel() in mount/umount */ |
| 3753 | - ylist_add_tail(&dev->devList, &yaffs_dev_list); |
| 3754 | - |
| 3755 | - init_MUTEX(&dev->grossLock); |
| 3756 | - |
| 3757 | - yaffs_GrossLock(dev); |
| 3758 | - |
| 3759 | - err = yaffs_GutsInitialise(dev); |
| 3760 | - |
| 3761 | - T(YAFFS_TRACE_OS, |
| 3762 | - ("yaffs_read_super: guts initialised %s\n", |
| 3763 | - (err == YAFFS_OK) ? "OK" : "FAILED")); |
| 3764 | - |
| 3765 | - /* Release lock before yaffs_get_inode() */ |
| 3766 | - yaffs_GrossUnlock(dev); |
| 3767 | - |
| 3768 | - /* Create root inode */ |
| 3769 | - if (err == YAFFS_OK) |
| 3770 | - inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, |
| 3771 | - yaffs_Root(dev)); |
| 3772 | - |
| 3773 | - if (!inode) |
| 3774 | - return NULL; |
| 3775 | - |
| 3776 | - inode->i_op = &yaffs_dir_inode_operations; |
| 3777 | - inode->i_fop = &yaffs_dir_operations; |
| 3778 | - |
| 3779 | - T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n")); |
| 3780 | - |
| 3781 | - root = d_alloc_root(inode); |
| 3782 | - |
| 3783 | - T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n")); |
| 3784 | - |
| 3785 | - if (!root) { |
| 3786 | - iput(inode); |
| 3787 | - return NULL; |
| 3788 | - } |
| 3789 | - sb->s_root = root; |
| 3790 | - sb->s_dirt = !dev->isCheckpointed; |
| 3791 | - T(YAFFS_TRACE_ALWAYS, |
| 3792 | - ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed)); |
| 3793 | - |
| 3794 | - T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n")); |
| 3795 | - return sb; |
| 3796 | -} |
| 3797 | - |
| 3798 | - |
| 3799 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 3800 | -static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, |
| 3801 | - int silent) |
| 3802 | -{ |
| 3803 | - return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; |
| 3804 | -} |
| 3805 | - |
| 3806 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 3807 | -static int yaffs_read_super(struct file_system_type *fs, |
| 3808 | - int flags, const char *dev_name, |
| 3809 | - void *data, struct vfsmount *mnt) |
| 3810 | -{ |
| 3811 | - |
| 3812 | - return get_sb_bdev(fs, flags, dev_name, data, |
| 3813 | - yaffs_internal_read_super_mtd, mnt); |
| 3814 | -} |
| 3815 | -#else |
| 3816 | -static struct super_block *yaffs_read_super(struct file_system_type *fs, |
| 3817 | - int flags, const char *dev_name, |
| 3818 | - void *data) |
| 3819 | -{ |
| 3820 | - |
| 3821 | - return get_sb_bdev(fs, flags, dev_name, data, |
| 3822 | - yaffs_internal_read_super_mtd); |
| 3823 | -} |
| 3824 | -#endif |
| 3825 | - |
| 3826 | -static struct file_system_type yaffs_fs_type = { |
| 3827 | - .owner = THIS_MODULE, |
| 3828 | - .name = "yaffs", |
| 3829 | - .get_sb = yaffs_read_super, |
| 3830 | - .kill_sb = kill_block_super, |
| 3831 | - .fs_flags = FS_REQUIRES_DEV, |
| 3832 | -}; |
| 3833 | -#else |
| 3834 | -static struct super_block *yaffs_read_super(struct super_block *sb, void *data, |
| 3835 | - int silent) |
| 3836 | -{ |
| 3837 | - return yaffs_internal_read_super(1, sb, data, silent); |
| 3838 | -} |
| 3839 | - |
| 3840 | -static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, |
| 3841 | - FS_REQUIRES_DEV); |
| 3842 | -#endif |
| 3843 | - |
| 3844 | - |
| 3845 | -#ifdef CONFIG_YAFFS_YAFFS2 |
| 3846 | - |
| 3847 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 3848 | -static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, |
| 3849 | - int silent) |
| 3850 | -{ |
| 3851 | - return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; |
| 3852 | -} |
| 3853 | - |
| 3854 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 3855 | -static int yaffs2_read_super(struct file_system_type *fs, |
| 3856 | - int flags, const char *dev_name, void *data, |
| 3857 | - struct vfsmount *mnt) |
| 3858 | -{ |
| 3859 | - return get_sb_bdev(fs, flags, dev_name, data, |
| 3860 | - yaffs2_internal_read_super_mtd, mnt); |
| 3861 | -} |
| 3862 | -#else |
| 3863 | -static struct super_block *yaffs2_read_super(struct file_system_type *fs, |
| 3864 | - int flags, const char *dev_name, |
| 3865 | - void *data) |
| 3866 | -{ |
| 3867 | - |
| 3868 | - return get_sb_bdev(fs, flags, dev_name, data, |
| 3869 | - yaffs2_internal_read_super_mtd); |
| 3870 | -} |
| 3871 | -#endif |
| 3872 | - |
| 3873 | -static struct file_system_type yaffs2_fs_type = { |
| 3874 | - .owner = THIS_MODULE, |
| 3875 | - .name = "yaffs2", |
| 3876 | - .get_sb = yaffs2_read_super, |
| 3877 | - .kill_sb = kill_block_super, |
| 3878 | - .fs_flags = FS_REQUIRES_DEV, |
| 3879 | -}; |
| 3880 | -#else |
| 3881 | -static struct super_block *yaffs2_read_super(struct super_block *sb, |
| 3882 | - void *data, int silent) |
| 3883 | -{ |
| 3884 | - return yaffs_internal_read_super(2, sb, data, silent); |
| 3885 | -} |
| 3886 | - |
| 3887 | -static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, |
| 3888 | - FS_REQUIRES_DEV); |
| 3889 | -#endif |
| 3890 | - |
| 3891 | -#endif /* CONFIG_YAFFS_YAFFS2 */ |
| 3892 | - |
| 3893 | -static struct proc_dir_entry *my_proc_entry; |
| 3894 | - |
| 3895 | -static char *yaffs_dump_dev(char *buf, yaffs_Device * dev) |
| 3896 | -{ |
| 3897 | - buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock); |
| 3898 | - buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); |
| 3899 | - buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk); |
| 3900 | - buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk); |
| 3901 | - buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits); |
| 3902 | - buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize); |
| 3903 | - buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks); |
| 3904 | - buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks); |
| 3905 | - buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint); |
| 3906 | - buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated); |
| 3907 | - buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes); |
| 3908 | - buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated); |
| 3909 | - buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects); |
| 3910 | - buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks); |
| 3911 | - buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites); |
| 3912 | - buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads); |
| 3913 | - buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures); |
| 3914 | - buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies); |
| 3915 | - buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections); |
| 3916 | - buf += sprintf(buf, "passiveGCs......... %d\n", |
| 3917 | - dev->passiveGarbageCollections); |
| 3918 | - buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites); |
| 3919 | - buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches); |
| 3920 | - buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks); |
| 3921 | - buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed); |
| 3922 | - buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed); |
| 3923 | - buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed); |
| 3924 | - buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed); |
| 3925 | - buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits); |
| 3926 | - buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles); |
| 3927 | - buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles); |
| 3928 | - buf += |
| 3929 | - sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions); |
| 3930 | - buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC); |
| 3931 | - buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2); |
| 3932 | - buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags); |
| 3933 | - |
| 3934 | - return buf; |
| 3935 | -} |
| 3936 | - |
| 3937 | -static int yaffs_proc_read(char *page, |
| 3938 | - char **start, |
| 3939 | - off_t offset, int count, int *eof, void *data) |
| 3940 | -{ |
| 3941 | - struct ylist_head *item; |
| 3942 | - char *buf = page; |
| 3943 | - int step = offset; |
| 3944 | - int n = 0; |
| 3945 | - |
| 3946 | - /* Get proc_file_read() to step 'offset' by one on each sucessive call. |
| 3947 | - * We use 'offset' (*ppos) to indicate where we are in devList. |
| 3948 | - * This also assumes the user has posted a read buffer large |
| 3949 | - * enough to hold the complete output; but that's life in /proc. |
| 3950 | - */ |
| 3951 | - |
| 3952 | - *(int *)start = 1; |
| 3953 | - |
| 3954 | - /* Print header first */ |
| 3955 | - if (step == 0) { |
| 3956 | - buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__ |
| 3957 | - "\n%s\n%s\n", yaffs_fs_c_version, |
| 3958 | - yaffs_guts_c_version); |
| 3959 | - } |
| 3960 | - |
| 3961 | - /* hold lock_kernel while traversing yaffs_dev_list */ |
| 3962 | - lock_kernel(); |
| 3963 | - |
| 3964 | - /* Locate and print the Nth entry. Order N-squared but N is small. */ |
| 3965 | - ylist_for_each(item, &yaffs_dev_list) { |
| 3966 | - yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList); |
| 3967 | - if (n < step) { |
| 3968 | - n++; |
| 3969 | - continue; |
| 3970 | - } |
| 3971 | - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name); |
| 3972 | - buf = yaffs_dump_dev(buf, dev); |
| 3973 | - break; |
| 3974 | - } |
| 3975 | - unlock_kernel(); |
| 3976 | - |
| 3977 | - return buf - page < count ? buf - page : count; |
| 3978 | -} |
| 3979 | - |
| 3980 | -/** |
| 3981 | - * Set the verbosity of the warnings and error messages. |
| 3982 | - * |
| 3983 | - * Note that the names can only be a..z or _ with the current code. |
| 3984 | - */ |
| 3985 | - |
| 3986 | -static struct { |
| 3987 | - char *mask_name; |
| 3988 | - unsigned mask_bitfield; |
| 3989 | -} mask_flags[] = { |
| 3990 | - {"allocate", YAFFS_TRACE_ALLOCATE}, |
| 3991 | - {"always", YAFFS_TRACE_ALWAYS}, |
| 3992 | - {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, |
| 3993 | - {"buffers", YAFFS_TRACE_BUFFERS}, |
| 3994 | - {"bug", YAFFS_TRACE_BUG}, |
| 3995 | - {"checkpt", YAFFS_TRACE_CHECKPOINT}, |
| 3996 | - {"deletion", YAFFS_TRACE_DELETION}, |
| 3997 | - {"erase", YAFFS_TRACE_ERASE}, |
| 3998 | - {"error", YAFFS_TRACE_ERROR}, |
| 3999 | - {"gc_detail", YAFFS_TRACE_GC_DETAIL}, |
| 4000 | - {"gc", YAFFS_TRACE_GC}, |
| 4001 | - {"mtd", YAFFS_TRACE_MTD}, |
| 4002 | - {"nandaccess", YAFFS_TRACE_NANDACCESS}, |
| 4003 | - {"os", YAFFS_TRACE_OS}, |
| 4004 | - {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, |
| 4005 | - {"scan", YAFFS_TRACE_SCAN}, |
| 4006 | - {"tracing", YAFFS_TRACE_TRACING}, |
| 4007 | - |
| 4008 | - {"verify", YAFFS_TRACE_VERIFY}, |
| 4009 | - {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, |
| 4010 | - {"verify_full", YAFFS_TRACE_VERIFY_FULL}, |
| 4011 | - {"verify_all", YAFFS_TRACE_VERIFY_ALL}, |
| 4012 | - |
| 4013 | - {"write", YAFFS_TRACE_WRITE}, |
| 4014 | - {"all", 0xffffffff}, |
| 4015 | - {"none", 0}, |
| 4016 | - {NULL, 0}, |
| 4017 | -}; |
| 4018 | - |
| 4019 | -#define MAX_MASK_NAME_LENGTH 40 |
| 4020 | -static int yaffs_proc_write(struct file *file, const char *buf, |
| 4021 | - unsigned long count, void *data) |
| 4022 | -{ |
| 4023 | - unsigned rg = 0, mask_bitfield; |
| 4024 | - char *end; |
| 4025 | - char *mask_name; |
| 4026 | - const char *x; |
| 4027 | - char substring[MAX_MASK_NAME_LENGTH + 1]; |
| 4028 | - int i; |
| 4029 | - int done = 0; |
| 4030 | - int add, len = 0; |
| 4031 | - int pos = 0; |
| 4032 | - |
| 4033 | - rg = yaffs_traceMask; |
| 4034 | - |
| 4035 | - while (!done && (pos < count)) { |
| 4036 | - done = 1; |
| 4037 | - while ((pos < count) && isspace(buf[pos])) |
| 4038 | - pos++; |
| 4039 | - |
| 4040 | - switch (buf[pos]) { |
| 4041 | - case '+': |
| 4042 | - case '-': |
| 4043 | - case '=': |
| 4044 | - add = buf[pos]; |
| 4045 | - pos++; |
| 4046 | - break; |
| 4047 | - |
| 4048 | - default: |
| 4049 | - add = ' '; |
| 4050 | - break; |
| 4051 | - } |
| 4052 | - mask_name = NULL; |
| 4053 | - |
| 4054 | - mask_bitfield = simple_strtoul(buf + pos, &end, 0); |
| 4055 | - |
| 4056 | - if (end > buf + pos) { |
| 4057 | - mask_name = "numeral"; |
| 4058 | - len = end - (buf + pos); |
| 4059 | - pos += len; |
| 4060 | - done = 0; |
| 4061 | - } else { |
| 4062 | - for (x = buf + pos, i = 0; |
| 4063 | - (*x == '_' || (*x >= 'a' && *x <= 'z')) && |
| 4064 | - i < MAX_MASK_NAME_LENGTH; x++, i++, pos++) |
| 4065 | - substring[i] = *x; |
| 4066 | - substring[i] = '\0'; |
| 4067 | - |
| 4068 | - for (i = 0; mask_flags[i].mask_name != NULL; i++) { |
| 4069 | - if (strcmp(substring, mask_flags[i].mask_name) == 0) { |
| 4070 | - mask_name = mask_flags[i].mask_name; |
| 4071 | - mask_bitfield = mask_flags[i].mask_bitfield; |
| 4072 | - done = 0; |
| 4073 | - break; |
| 4074 | - } |
| 4075 | - } |
| 4076 | - } |
| 4077 | - |
| 4078 | - if (mask_name != NULL) { |
| 4079 | - done = 0; |
| 4080 | - switch (add) { |
| 4081 | - case '-': |
| 4082 | - rg &= ~mask_bitfield; |
| 4083 | - break; |
| 4084 | - case '+': |
| 4085 | - rg |= mask_bitfield; |
| 4086 | - break; |
| 4087 | - case '=': |
| 4088 | - rg = mask_bitfield; |
| 4089 | - break; |
| 4090 | - default: |
| 4091 | - rg |= mask_bitfield; |
| 4092 | - break; |
| 4093 | - } |
| 4094 | - } |
| 4095 | - } |
| 4096 | - |
| 4097 | - yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS; |
| 4098 | - |
| 4099 | - printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask); |
| 4100 | - |
| 4101 | - if (rg & YAFFS_TRACE_ALWAYS) { |
| 4102 | - for (i = 0; mask_flags[i].mask_name != NULL; i++) { |
| 4103 | - char flag; |
| 4104 | - flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-'; |
| 4105 | - printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name); |
| 4106 | - } |
| 4107 | - } |
| 4108 | - |
| 4109 | - return count; |
| 4110 | -} |
| 4111 | - |
| 4112 | -/* Stuff to handle installation of file systems */ |
| 4113 | -struct file_system_to_install { |
| 4114 | - struct file_system_type *fst; |
| 4115 | - int installed; |
| 4116 | -}; |
| 4117 | - |
| 4118 | -static struct file_system_to_install fs_to_install[] = { |
| 4119 | - {&yaffs_fs_type, 0}, |
| 4120 | - {&yaffs2_fs_type, 0}, |
| 4121 | - {NULL, 0} |
| 4122 | -}; |
| 4123 | - |
| 4124 | -static int __init init_yaffs_fs(void) |
| 4125 | -{ |
| 4126 | - int error = 0; |
| 4127 | - struct file_system_to_install *fsinst; |
| 4128 | - |
| 4129 | - T(YAFFS_TRACE_ALWAYS, |
| 4130 | - ("yaffs " __DATE__ " " __TIME__ " Installing. \n")); |
| 4131 | - |
| 4132 | - /* Install the proc_fs entry */ |
| 4133 | - my_proc_entry = create_proc_entry("yaffs", |
| 4134 | - S_IRUGO | S_IFREG, |
| 4135 | - YPROC_ROOT); |
| 4136 | - |
| 4137 | - if (my_proc_entry) { |
| 4138 | - my_proc_entry->write_proc = yaffs_proc_write; |
| 4139 | - my_proc_entry->read_proc = yaffs_proc_read; |
| 4140 | - my_proc_entry->data = NULL; |
| 4141 | - } else |
| 4142 | - return -ENOMEM; |
| 4143 | - |
| 4144 | - /* Now add the file system entries */ |
| 4145 | - |
| 4146 | - fsinst = fs_to_install; |
| 4147 | - |
| 4148 | - while (fsinst->fst && !error) { |
| 4149 | - error = register_filesystem(fsinst->fst); |
| 4150 | - if (!error) |
| 4151 | - fsinst->installed = 1; |
| 4152 | - fsinst++; |
| 4153 | - } |
| 4154 | - |
| 4155 | - /* Any errors? uninstall */ |
| 4156 | - if (error) { |
| 4157 | - fsinst = fs_to_install; |
| 4158 | - |
| 4159 | - while (fsinst->fst) { |
| 4160 | - if (fsinst->installed) { |
| 4161 | - unregister_filesystem(fsinst->fst); |
| 4162 | - fsinst->installed = 0; |
| 4163 | - } |
| 4164 | - fsinst++; |
| 4165 | - } |
| 4166 | - } |
| 4167 | - |
| 4168 | - return error; |
| 4169 | -} |
| 4170 | - |
| 4171 | -static void __exit exit_yaffs_fs(void) |
| 4172 | -{ |
| 4173 | - |
| 4174 | - struct file_system_to_install *fsinst; |
| 4175 | - |
| 4176 | - T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__ |
| 4177 | - " removing. \n")); |
| 4178 | - |
| 4179 | - remove_proc_entry("yaffs", YPROC_ROOT); |
| 4180 | - |
| 4181 | - fsinst = fs_to_install; |
| 4182 | - |
| 4183 | - while (fsinst->fst) { |
| 4184 | - if (fsinst->installed) { |
| 4185 | - unregister_filesystem(fsinst->fst); |
| 4186 | - fsinst->installed = 0; |
| 4187 | - } |
| 4188 | - fsinst++; |
| 4189 | - } |
| 4190 | -} |
| 4191 | - |
| 4192 | -module_init(init_yaffs_fs) |
| 4193 | -module_exit(exit_yaffs_fs) |
| 4194 | - |
| 4195 | -MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); |
| 4196 | -MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006"); |
| 4197 | -MODULE_LICENSE("GPL"); |
| 4198 | --- a/fs/yaffs2/yaffs_getblockinfo.h |
| 4199 | +++ b/fs/yaffs2/yaffs_getblockinfo.h |
| 4200 | @@ -1,7 +1,7 @@ |
| 4201 | /* |
| 4202 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 4203 | * |
| 4204 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 4205 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 4206 | * for Toby Churchill Ltd and Brightstar Engineering |
| 4207 | * |
| 4208 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 4209 | @@ -17,18 +17,19 @@ |
| 4210 | #define __YAFFS_GETBLOCKINFO_H__ |
| 4211 | |
| 4212 | #include "yaffs_guts.h" |
| 4213 | +#include "yaffs_trace.h" |
| 4214 | |
| 4215 | /* Function to manipulate block info */ |
| 4216 | -static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) |
| 4217 | +static Y_INLINE yaffs_block_info_t *yaffs_get_block_info(yaffs_dev_t * dev, int blk) |
| 4218 | { |
| 4219 | - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { |
| 4220 | + if (blk < dev->internal_start_block || blk > dev->internal_end_block) { |
| 4221 | T(YAFFS_TRACE_ERROR, |
| 4222 | (TSTR |
| 4223 | ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR), |
| 4224 | blk)); |
| 4225 | YBUG(); |
| 4226 | } |
| 4227 | - return &dev->blockInfo[blk - dev->internalStartBlock]; |
| 4228 | + return &dev->block_info[blk - dev->internal_start_block]; |
| 4229 | } |
| 4230 | |
| 4231 | #endif |
| 4232 | --- a/fs/yaffs2/yaffs_guts.c |
| 4233 | +++ b/fs/yaffs2/yaffs_guts.c |
| 4234 | @@ -1,7 +1,7 @@ |
| 4235 | /* |
| 4236 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 4237 | * |
| 4238 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 4239 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 4240 | * for Toby Churchill Ltd and Brightstar Engineering |
| 4241 | * |
| 4242 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 4243 | @@ -10,11 +10,8 @@ |
| 4244 | * it under the terms of the GNU General Public License version 2 as |
| 4245 | * published by the Free Software Foundation. |
| 4246 | */ |
| 4247 | - |
| 4248 | -const char *yaffs_guts_c_version = |
| 4249 | - "$Id: yaffs_guts.c,v 1.82 2009-03-09 04:24:17 charles Exp $"; |
| 4250 | - |
| 4251 | #include "yportenv.h" |
| 4252 | +#include "yaffs_trace.h" |
| 4253 | |
| 4254 | #include "yaffsinterface.h" |
| 4255 | #include "yaffs_guts.h" |
| 4256 | @@ -22,118 +19,109 @@ const char *yaffs_guts_c_version = |
| 4257 | #include "yaffs_getblockinfo.h" |
| 4258 | |
| 4259 | #include "yaffs_tagscompat.h" |
| 4260 | -#ifndef CONFIG_YAFFS_USE_OWN_SORT |
| 4261 | -#include "yaffs_qsort.h" |
| 4262 | -#endif |
| 4263 | + |
| 4264 | #include "yaffs_nand.h" |
| 4265 | |
| 4266 | -#include "yaffs_checkptrw.h" |
| 4267 | +#include "yaffs_yaffs1.h" |
| 4268 | +#include "yaffs_yaffs2.h" |
| 4269 | +#include "yaffs_bitmap.h" |
| 4270 | +#include "yaffs_verify.h" |
| 4271 | |
| 4272 | #include "yaffs_nand.h" |
| 4273 | #include "yaffs_packedtags2.h" |
| 4274 | |
| 4275 | +#include "yaffs_nameval.h" |
| 4276 | +#include "yaffs_allocator.h" |
| 4277 | |
| 4278 | -#define YAFFS_PASSIVE_GC_CHUNKS 2 |
| 4279 | +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ |
| 4280 | +#define YAFFS_GC_GOOD_ENOUGH 2 |
| 4281 | +#define YAFFS_GC_PASSIVE_THRESHOLD 4 |
| 4282 | |
| 4283 | #include "yaffs_ecc.h" |
| 4284 | |
| 4285 | |
| 4286 | + |
| 4287 | /* Robustification (if it ever comes about...) */ |
| 4288 | -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND); |
| 4289 | -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, |
| 4290 | +static void yaffs_retire_block(yaffs_dev_t *dev, int flash_block); |
| 4291 | +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk, |
| 4292 | int erasedOk); |
| 4293 | -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, |
| 4294 | +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk, |
| 4295 | const __u8 *data, |
| 4296 | - const yaffs_ExtendedTags *tags); |
| 4297 | -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, |
| 4298 | - const yaffs_ExtendedTags *tags); |
| 4299 | + const yaffs_ext_tags *tags); |
| 4300 | +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk, |
| 4301 | + const yaffs_ext_tags *tags); |
| 4302 | |
| 4303 | /* Other local prototypes */ |
| 4304 | -static int yaffs_UnlinkObject(yaffs_Object *obj); |
| 4305 | -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj); |
| 4306 | - |
| 4307 | -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList); |
| 4308 | +static void yaffs_update_parent(yaffs_obj_t *obj); |
| 4309 | +static int yaffs_unlink_obj(yaffs_obj_t *obj); |
| 4310 | +static int yaffs_obj_cache_dirty(yaffs_obj_t *obj); |
| 4311 | |
| 4312 | -static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, |
| 4313 | +static int yaffs_write_new_chunk(yaffs_dev_t *dev, |
| 4314 | const __u8 *buffer, |
| 4315 | - yaffs_ExtendedTags *tags, |
| 4316 | + yaffs_ext_tags *tags, |
| 4317 | int useReserve); |
| 4318 | -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, |
| 4319 | - int chunkInNAND, int inScan); |
| 4320 | |
| 4321 | -static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, |
| 4322 | - yaffs_ObjectType type); |
| 4323 | -static void yaffs_AddObjectToDirectory(yaffs_Object *directory, |
| 4324 | - yaffs_Object *obj); |
| 4325 | -static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, |
| 4326 | - int force, int isShrink, int shadows); |
| 4327 | -static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); |
| 4328 | -static int yaffs_CheckStructures(void); |
| 4329 | -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, |
| 4330 | - int chunkOffset, int *limit); |
| 4331 | -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in); |
| 4332 | - |
| 4333 | -static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo); |
| 4334 | |
| 4335 | +static yaffs_obj_t *yaffs_new_obj(yaffs_dev_t *dev, int number, |
| 4336 | + yaffs_obj_type type); |
| 4337 | |
| 4338 | -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, |
| 4339 | - int chunkInNAND); |
| 4340 | |
| 4341 | -static int yaffs_UnlinkWorker(yaffs_Object *obj); |
| 4342 | +static int yaffs_apply_xattrib_mod(yaffs_obj_t *obj, char *buffer, yaffs_xattr_mod *xmod); |
| 4343 | |
| 4344 | -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, |
| 4345 | - int chunkInObject); |
| 4346 | +static void yaffs_remove_obj_from_dir(yaffs_obj_t *obj); |
| 4347 | +static int yaffs_check_structures(void); |
| 4348 | +static int yaffs_generic_obj_del(yaffs_obj_t *in); |
| 4349 | + |
| 4350 | +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev, |
| 4351 | + int nand_chunk); |
| 4352 | |
| 4353 | -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, |
| 4354 | - yaffs_BlockInfo **blockUsedPtr); |
| 4355 | +static int yaffs_unlink_worker(yaffs_obj_t *obj); |
| 4356 | |
| 4357 | -static void yaffs_VerifyFreeChunks(yaffs_Device *dev); |
| 4358 | +static int yaffs_tags_match(const yaffs_ext_tags *tags, int obj_id, |
| 4359 | + int chunkInObject); |
| 4360 | |
| 4361 | -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in); |
| 4362 | +static int yaffs_alloc_chunk(yaffs_dev_t *dev, int useReserve, |
| 4363 | + yaffs_block_info_t **blockUsedPtr); |
| 4364 | |
| 4365 | -static void yaffs_VerifyDirectory(yaffs_Object *directory); |
| 4366 | -#ifdef YAFFS_PARANOID |
| 4367 | -static int yaffs_CheckFileSanity(yaffs_Object *in); |
| 4368 | -#else |
| 4369 | -#define yaffs_CheckFileSanity(in) |
| 4370 | -#endif |
| 4371 | +static void yaffs_check_obj_details_loaded(yaffs_obj_t *in); |
| 4372 | + |
| 4373 | +static void yaffs_invalidate_whole_cache(yaffs_obj_t *in); |
| 4374 | +static void yaffs_invalidate_chunk_cache(yaffs_obj_t *object, int chunk_id); |
| 4375 | |
| 4376 | -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in); |
| 4377 | -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId); |
| 4378 | +static int yaffs_find_chunk_in_file(yaffs_obj_t *in, int inode_chunk, |
| 4379 | + yaffs_ext_tags *tags); |
| 4380 | |
| 4381 | -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev); |
| 4382 | +static int yaffs_verify_chunk_written(yaffs_dev_t *dev, |
| 4383 | + int nand_chunk, |
| 4384 | + const __u8 *data, |
| 4385 | + yaffs_ext_tags *tags); |
| 4386 | |
| 4387 | -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode, |
| 4388 | - yaffs_ExtendedTags *tags); |
| 4389 | |
| 4390 | -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, |
| 4391 | - unsigned pos); |
| 4392 | -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, |
| 4393 | - yaffs_FileStructure *fStruct, |
| 4394 | - __u32 chunkId); |
| 4395 | +static void yaffs_load_name_from_oh(yaffs_dev_t *dev,YCHAR *name, const YCHAR *ohName, int bufferSize); |
| 4396 | +static void yaffs_load_oh_from_name(yaffs_dev_t *dev,YCHAR *ohName, const YCHAR *name); |
| 4397 | |
| 4398 | |
| 4399 | /* Function to calculate chunk and offset */ |
| 4400 | |
| 4401 | -static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut, |
| 4402 | +static void yaffs_addr_to_chunk(yaffs_dev_t *dev, loff_t addr, int *chunkOut, |
| 4403 | __u32 *offsetOut) |
| 4404 | { |
| 4405 | int chunk; |
| 4406 | __u32 offset; |
| 4407 | |
| 4408 | - chunk = (__u32)(addr >> dev->chunkShift); |
| 4409 | + chunk = (__u32)(addr >> dev->chunk_shift); |
| 4410 | |
| 4411 | - if (dev->chunkDiv == 1) { |
| 4412 | + if (dev->chunk_div == 1) { |
| 4413 | /* easy power of 2 case */ |
| 4414 | - offset = (__u32)(addr & dev->chunkMask); |
| 4415 | + offset = (__u32)(addr & dev->chunk_mask); |
| 4416 | } else { |
| 4417 | /* Non power-of-2 case */ |
| 4418 | |
| 4419 | loff_t chunkBase; |
| 4420 | |
| 4421 | - chunk /= dev->chunkDiv; |
| 4422 | + chunk /= dev->chunk_div; |
| 4423 | |
| 4424 | - chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk; |
| 4425 | + chunkBase = ((loff_t)chunk) * dev->data_bytes_per_chunk; |
| 4426 | offset = (__u32)(addr - chunkBase); |
| 4427 | } |
| 4428 | |
| 4429 | @@ -172,7 +160,7 @@ static __u32 ShiftsGE(__u32 x) |
| 4430 | |
| 4431 | static __u32 Shifts(__u32 x) |
| 4432 | { |
| 4433 | - int nShifts; |
| 4434 | + __u32 nShifts; |
| 4435 | |
| 4436 | nShifts = 0; |
| 4437 | |
| 4438 | @@ -193,49 +181,49 @@ static __u32 Shifts(__u32 x) |
| 4439 | * Temporary buffer manipulations. |
| 4440 | */ |
| 4441 | |
| 4442 | -static int yaffs_InitialiseTempBuffers(yaffs_Device *dev) |
| 4443 | +static int yaffs_init_tmp_buffers(yaffs_dev_t *dev) |
| 4444 | { |
| 4445 | int i; |
| 4446 | __u8 *buf = (__u8 *)1; |
| 4447 | |
| 4448 | - memset(dev->tempBuffer, 0, sizeof(dev->tempBuffer)); |
| 4449 | + memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer)); |
| 4450 | |
| 4451 | for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { |
| 4452 | - dev->tempBuffer[i].line = 0; /* not in use */ |
| 4453 | - dev->tempBuffer[i].buffer = buf = |
| 4454 | - YMALLOC_DMA(dev->totalBytesPerChunk); |
| 4455 | + dev->temp_buffer[i].line = 0; /* not in use */ |
| 4456 | + dev->temp_buffer[i].buffer = buf = |
| 4457 | + YMALLOC_DMA(dev->param.total_bytes_per_chunk); |
| 4458 | } |
| 4459 | |
| 4460 | return buf ? YAFFS_OK : YAFFS_FAIL; |
| 4461 | } |
| 4462 | |
| 4463 | -__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo) |
| 4464 | +__u8 *yaffs_get_temp_buffer(yaffs_dev_t *dev, int line_no) |
| 4465 | { |
| 4466 | int i, j; |
| 4467 | |
| 4468 | - dev->tempInUse++; |
| 4469 | - if (dev->tempInUse > dev->maxTemp) |
| 4470 | - dev->maxTemp = dev->tempInUse; |
| 4471 | + dev->temp_in_use++; |
| 4472 | + if (dev->temp_in_use > dev->max_temp) |
| 4473 | + dev->max_temp = dev->temp_in_use; |
| 4474 | |
| 4475 | for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { |
| 4476 | - if (dev->tempBuffer[i].line == 0) { |
| 4477 | - dev->tempBuffer[i].line = lineNo; |
| 4478 | - if ((i + 1) > dev->maxTemp) { |
| 4479 | - dev->maxTemp = i + 1; |
| 4480 | + if (dev->temp_buffer[i].line == 0) { |
| 4481 | + dev->temp_buffer[i].line = line_no; |
| 4482 | + if ((i + 1) > dev->max_temp) { |
| 4483 | + dev->max_temp = i + 1; |
| 4484 | for (j = 0; j <= i; j++) |
| 4485 | - dev->tempBuffer[j].maxLine = |
| 4486 | - dev->tempBuffer[j].line; |
| 4487 | + dev->temp_buffer[j].max_line = |
| 4488 | + dev->temp_buffer[j].line; |
| 4489 | } |
| 4490 | |
| 4491 | - return dev->tempBuffer[i].buffer; |
| 4492 | + return dev->temp_buffer[i].buffer; |
| 4493 | } |
| 4494 | } |
| 4495 | |
| 4496 | T(YAFFS_TRACE_BUFFERS, |
| 4497 | (TSTR("Out of temp buffers at line %d, other held by lines:"), |
| 4498 | - lineNo)); |
| 4499 | + line_no)); |
| 4500 | for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) |
| 4501 | - T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line)); |
| 4502 | + T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->temp_buffer[i].line)); |
| 4503 | |
| 4504 | T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR))); |
| 4505 | |
| 4506 | @@ -244,21 +232,21 @@ __u8 *yaffs_GetTempBuffer(yaffs_Device * |
| 4507 | * This is not good. |
| 4508 | */ |
| 4509 | |
| 4510 | - dev->unmanagedTempAllocations++; |
| 4511 | - return YMALLOC(dev->nDataBytesPerChunk); |
| 4512 | + dev->unmanaged_buffer_allocs++; |
| 4513 | + return YMALLOC(dev->data_bytes_per_chunk); |
| 4514 | |
| 4515 | } |
| 4516 | |
| 4517 | -void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, |
| 4518 | - int lineNo) |
| 4519 | +void yaffs_release_temp_buffer(yaffs_dev_t *dev, __u8 *buffer, |
| 4520 | + int line_no) |
| 4521 | { |
| 4522 | int i; |
| 4523 | |
| 4524 | - dev->tempInUse--; |
| 4525 | + dev->temp_in_use--; |
| 4526 | |
| 4527 | for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { |
| 4528 | - if (dev->tempBuffer[i].buffer == buffer) { |
| 4529 | - dev->tempBuffer[i].line = 0; |
| 4530 | + if (dev->temp_buffer[i].buffer == buffer) { |
| 4531 | + dev->temp_buffer[i].line = 0; |
| 4532 | return; |
| 4533 | } |
| 4534 | } |
| 4535 | @@ -267,9 +255,9 @@ void yaffs_ReleaseTempBuffer(yaffs_Devic |
| 4536 | /* assume it is an unmanaged one. */ |
| 4537 | T(YAFFS_TRACE_BUFFERS, |
| 4538 | (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR), |
| 4539 | - lineNo)); |
| 4540 | + line_no)); |
| 4541 | YFREE(buffer); |
| 4542 | - dev->unmanagedTempDeallocations++; |
| 4543 | + dev->unmanaged_buffer_deallocs++; |
| 4544 | } |
| 4545 | |
| 4546 | } |
| 4547 | @@ -277,21 +265,21 @@ void yaffs_ReleaseTempBuffer(yaffs_Devic |
| 4548 | /* |
| 4549 | * Determine if we have a managed buffer. |
| 4550 | */ |
| 4551 | -int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer) |
| 4552 | +int yaffs_is_managed_tmp_buffer(yaffs_dev_t *dev, const __u8 *buffer) |
| 4553 | { |
| 4554 | int i; |
| 4555 | |
| 4556 | for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { |
| 4557 | - if (dev->tempBuffer[i].buffer == buffer) |
| 4558 | + if (dev->temp_buffer[i].buffer == buffer) |
| 4559 | return 1; |
| 4560 | } |
| 4561 | |
| 4562 | - for (i = 0; i < dev->nShortOpCaches; i++) { |
| 4563 | - if (dev->srCache[i].data == buffer) |
| 4564 | + for (i = 0; i < dev->param.n_caches; i++) { |
| 4565 | + if (dev->cache[i].data == buffer) |
| 4566 | return 1; |
| 4567 | } |
| 4568 | |
| 4569 | - if (buffer == dev->checkpointBuffer) |
| 4570 | + if (buffer == dev->checkpt_buffer) |
| 4571 | return 1; |
| 4572 | |
| 4573 | T(YAFFS_TRACE_ALWAYS, |
| 4574 | @@ -299,6397 +287,4205 @@ int yaffs_IsManagedTempBuffer(yaffs_Devi |
| 4575 | return 0; |
| 4576 | } |
| 4577 | |
| 4578 | - |
| 4579 | - |
| 4580 | /* |
| 4581 | - * Chunk bitmap manipulations |
| 4582 | + * Verification code |
| 4583 | */ |
| 4584 | |
| 4585 | -static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk) |
| 4586 | -{ |
| 4587 | - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { |
| 4588 | - T(YAFFS_TRACE_ERROR, |
| 4589 | - (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), |
| 4590 | - blk)); |
| 4591 | - YBUG(); |
| 4592 | - } |
| 4593 | - return dev->chunkBits + |
| 4594 | - (dev->chunkBitmapStride * (blk - dev->internalStartBlock)); |
| 4595 | -} |
| 4596 | |
| 4597 | -static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk) |
| 4598 | -{ |
| 4599 | - if (blk < dev->internalStartBlock || blk > dev->internalEndBlock || |
| 4600 | - chunk < 0 || chunk >= dev->nChunksPerBlock) { |
| 4601 | - T(YAFFS_TRACE_ERROR, |
| 4602 | - (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR), |
| 4603 | - blk, chunk)); |
| 4604 | - YBUG(); |
| 4605 | - } |
| 4606 | -} |
| 4607 | |
| 4608 | -static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk) |
| 4609 | -{ |
| 4610 | - __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 4611 | |
| 4612 | - memset(blkBits, 0, dev->chunkBitmapStride); |
| 4613 | -} |
| 4614 | +/* |
| 4615 | + * Simple hash function. Needs to have a reasonable spread |
| 4616 | + */ |
| 4617 | |
| 4618 | -static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk) |
| 4619 | +static Y_INLINE int yaffs_hash_fn(int n) |
| 4620 | { |
| 4621 | - __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 4622 | - |
| 4623 | - yaffs_VerifyChunkBitId(dev, blk, chunk); |
| 4624 | - |
| 4625 | - blkBits[chunk / 8] &= ~(1 << (chunk & 7)); |
| 4626 | + n = abs(n); |
| 4627 | + return n % YAFFS_NOBJECT_BUCKETS; |
| 4628 | } |
| 4629 | |
| 4630 | -static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk) |
| 4631 | -{ |
| 4632 | - __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 4633 | - |
| 4634 | - yaffs_VerifyChunkBitId(dev, blk, chunk); |
| 4635 | - |
| 4636 | - blkBits[chunk / 8] |= (1 << (chunk & 7)); |
| 4637 | -} |
| 4638 | +/* |
| 4639 | + * Access functions to useful fake objects. |
| 4640 | + * Note that root might have a presence in NAND if permissions are set. |
| 4641 | + */ |
| 4642 | |
| 4643 | -static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk) |
| 4644 | +yaffs_obj_t *yaffs_root(yaffs_dev_t *dev) |
| 4645 | { |
| 4646 | - __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 4647 | - yaffs_VerifyChunkBitId(dev, blk, chunk); |
| 4648 | - |
| 4649 | - return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; |
| 4650 | + return dev->root_dir; |
| 4651 | } |
| 4652 | |
| 4653 | -static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk) |
| 4654 | +yaffs_obj_t *yaffs_lost_n_found(yaffs_dev_t *dev) |
| 4655 | { |
| 4656 | - __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 4657 | - int i; |
| 4658 | - for (i = 0; i < dev->chunkBitmapStride; i++) { |
| 4659 | - if (*blkBits) |
| 4660 | - return 1; |
| 4661 | - blkBits++; |
| 4662 | - } |
| 4663 | - return 0; |
| 4664 | + return dev->lost_n_found; |
| 4665 | } |
| 4666 | |
| 4667 | -static int yaffs_CountChunkBits(yaffs_Device *dev, int blk) |
| 4668 | -{ |
| 4669 | - __u8 *blkBits = yaffs_BlockBits(dev, blk); |
| 4670 | - int i; |
| 4671 | - int n = 0; |
| 4672 | - for (i = 0; i < dev->chunkBitmapStride; i++) { |
| 4673 | - __u8 x = *blkBits; |
| 4674 | - while (x) { |
| 4675 | - if (x & 1) |
| 4676 | - n++; |
| 4677 | - x >>= 1; |
| 4678 | - } |
| 4679 | - |
| 4680 | - blkBits++; |
| 4681 | - } |
| 4682 | - return n; |
| 4683 | -} |
| 4684 | |
| 4685 | /* |
| 4686 | - * Verification code |
| 4687 | + * Erased NAND checking functions |
| 4688 | */ |
| 4689 | |
| 4690 | -static int yaffs_SkipVerification(yaffs_Device *dev) |
| 4691 | -{ |
| 4692 | - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); |
| 4693 | -} |
| 4694 | - |
| 4695 | -static int yaffs_SkipFullVerification(yaffs_Device *dev) |
| 4696 | -{ |
| 4697 | - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); |
| 4698 | -} |
| 4699 | - |
| 4700 | -static int yaffs_SkipNANDVerification(yaffs_Device *dev) |
| 4701 | +int yaffs_check_ff(__u8 *buffer, int n_bytes) |
| 4702 | { |
| 4703 | - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); |
| 4704 | + /* Horrible, slow implementation */ |
| 4705 | + while (n_bytes--) { |
| 4706 | + if (*buffer != 0xFF) |
| 4707 | + return 0; |
| 4708 | + buffer++; |
| 4709 | + } |
| 4710 | + return 1; |
| 4711 | } |
| 4712 | |
| 4713 | -static const char *blockStateName[] = { |
| 4714 | -"Unknown", |
| 4715 | -"Needs scanning", |
| 4716 | -"Scanning", |
| 4717 | -"Empty", |
| 4718 | -"Allocating", |
| 4719 | -"Full", |
| 4720 | -"Dirty", |
| 4721 | -"Checkpoint", |
| 4722 | -"Collecting", |
| 4723 | -"Dead" |
| 4724 | -}; |
| 4725 | - |
| 4726 | -static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n) |
| 4727 | +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev, |
| 4728 | + int nand_chunk) |
| 4729 | { |
| 4730 | - int actuallyUsed; |
| 4731 | - int inUse; |
| 4732 | + int retval = YAFFS_OK; |
| 4733 | + __u8 *data = yaffs_get_temp_buffer(dev, __LINE__); |
| 4734 | + yaffs_ext_tags tags; |
| 4735 | + int result; |
| 4736 | |
| 4737 | - if (yaffs_SkipVerification(dev)) |
| 4738 | - return; |
| 4739 | + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags); |
| 4740 | |
| 4741 | - /* Report illegal runtime states */ |
| 4742 | - if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) |
| 4743 | - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState)); |
| 4744 | + if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR) |
| 4745 | + retval = YAFFS_FAIL; |
| 4746 | |
| 4747 | - switch (bi->blockState) { |
| 4748 | - case YAFFS_BLOCK_STATE_UNKNOWN: |
| 4749 | - case YAFFS_BLOCK_STATE_SCANNING: |
| 4750 | - case YAFFS_BLOCK_STATE_NEEDS_SCANNING: |
| 4751 | - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR), |
| 4752 | - n, blockStateName[bi->blockState])); |
| 4753 | + if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || tags.chunk_used) { |
| 4754 | + T(YAFFS_TRACE_NANDACCESS, |
| 4755 | + (TSTR("Chunk %d not erased" TENDSTR), nand_chunk)); |
| 4756 | + retval = YAFFS_FAIL; |
| 4757 | } |
| 4758 | |
| 4759 | - /* Check pages in use and soft deletions are legal */ |
| 4760 | - |
| 4761 | - actuallyUsed = bi->pagesInUse - bi->softDeletions; |
| 4762 | - |
| 4763 | - if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock || |
| 4764 | - bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock || |
| 4765 | - actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock) |
| 4766 | - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), |
| 4767 | - n, bi->pagesInUse, bi->softDeletions)); |
| 4768 | - |
| 4769 | + yaffs_release_temp_buffer(dev, data, __LINE__); |
| 4770 | |
| 4771 | - /* Check chunk bitmap legal */ |
| 4772 | - inUse = yaffs_CountChunkBits(dev, n); |
| 4773 | - if (inUse != bi->pagesInUse) |
| 4774 | - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), |
| 4775 | - n, bi->pagesInUse, inUse)); |
| 4776 | + return retval; |
| 4777 | |
| 4778 | - /* Check that the sequence number is valid. |
| 4779 | - * Ten million is legal, but is very unlikely |
| 4780 | - */ |
| 4781 | - if (dev->isYaffs2 && |
| 4782 | - (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) && |
| 4783 | - (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000)) |
| 4784 | - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR), |
| 4785 | - n, bi->sequenceNumber)); |
| 4786 | } |
| 4787 | |
| 4788 | -static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, |
| 4789 | - int n) |
| 4790 | + |
| 4791 | +static int yaffs_verify_chunk_written(yaffs_dev_t *dev, |
| 4792 | + int nand_chunk, |
| 4793 | + const __u8 *data, |
| 4794 | + yaffs_ext_tags *tags) |
| 4795 | { |
| 4796 | - yaffs_VerifyBlock(dev, bi, n); |
| 4797 | + int retval = YAFFS_OK; |
| 4798 | + yaffs_ext_tags tempTags; |
| 4799 | + __u8 *buffer = yaffs_get_temp_buffer(dev,__LINE__); |
| 4800 | + int result; |
| 4801 | + |
| 4802 | + result = yaffs_rd_chunk_tags_nand(dev,nand_chunk,buffer,&tempTags); |
| 4803 | + if(memcmp(buffer,data,dev->data_bytes_per_chunk) || |
| 4804 | + tempTags.obj_id != tags->obj_id || |
| 4805 | + tempTags.chunk_id != tags->chunk_id || |
| 4806 | + tempTags.n_bytes != tags->n_bytes) |
| 4807 | + retval = YAFFS_FAIL; |
| 4808 | |
| 4809 | - /* After collection the block should be in the erased state */ |
| 4810 | - /* This will need to change if we do partial gc */ |
| 4811 | + yaffs_release_temp_buffer(dev, buffer, __LINE__); |
| 4812 | |
| 4813 | - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && |
| 4814 | - bi->blockState != YAFFS_BLOCK_STATE_EMPTY) { |
| 4815 | - T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), |
| 4816 | - n, bi->blockState)); |
| 4817 | - } |
| 4818 | + return retval; |
| 4819 | } |
| 4820 | |
| 4821 | -static void yaffs_VerifyBlocks(yaffs_Device *dev) |
| 4822 | +static int yaffs_write_new_chunk(struct yaffs_dev_s *dev, |
| 4823 | + const __u8 *data, |
| 4824 | + yaffs_ext_tags *tags, |
| 4825 | + int useReserve) |
| 4826 | { |
| 4827 | - int i; |
| 4828 | - int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; |
| 4829 | - int nIllegalBlockStates = 0; |
| 4830 | - |
| 4831 | - if (yaffs_SkipVerification(dev)) |
| 4832 | - return; |
| 4833 | - |
| 4834 | - memset(nBlocksPerState, 0, sizeof(nBlocksPerState)); |
| 4835 | - |
| 4836 | - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { |
| 4837 | - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); |
| 4838 | - yaffs_VerifyBlock(dev, bi, i); |
| 4839 | - |
| 4840 | - if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) |
| 4841 | - nBlocksPerState[bi->blockState]++; |
| 4842 | - else |
| 4843 | - nIllegalBlockStates++; |
| 4844 | - } |
| 4845 | + int attempts = 0; |
| 4846 | + int writeOk = 0; |
| 4847 | + int chunk; |
| 4848 | |
| 4849 | - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); |
| 4850 | - T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR))); |
| 4851 | + yaffs2_checkpt_invalidate(dev); |
| 4852 | |
| 4853 | - T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates)); |
| 4854 | - if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) |
| 4855 | - T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR))); |
| 4856 | + do { |
| 4857 | + yaffs_block_info_t *bi = 0; |
| 4858 | + int erasedOk = 0; |
| 4859 | |
| 4860 | - for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) |
| 4861 | - T(YAFFS_TRACE_VERIFY, |
| 4862 | - (TSTR("%s %d blocks"TENDSTR), |
| 4863 | - blockStateName[i], nBlocksPerState[i])); |
| 4864 | + chunk = yaffs_alloc_chunk(dev, useReserve, &bi); |
| 4865 | + if (chunk < 0) { |
| 4866 | + /* no space */ |
| 4867 | + break; |
| 4868 | + } |
| 4869 | |
| 4870 | - if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) |
| 4871 | - T(YAFFS_TRACE_VERIFY, |
| 4872 | - (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), |
| 4873 | - dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); |
| 4874 | + /* First check this chunk is erased, if it needs |
| 4875 | + * checking. The checking policy (unless forced |
| 4876 | + * always on) is as follows: |
| 4877 | + * |
| 4878 | + * Check the first page we try to write in a block. |
| 4879 | + * If the check passes then we don't need to check any |
| 4880 | + * more. If the check fails, we check again... |
| 4881 | + * If the block has been erased, we don't need to check. |
| 4882 | + * |
| 4883 | + * However, if the block has been prioritised for gc, |
| 4884 | + * then we think there might be something odd about |
| 4885 | + * this block and stop using it. |
| 4886 | + * |
| 4887 | + * Rationale: We should only ever see chunks that have |
| 4888 | + * not been erased if there was a partially written |
| 4889 | + * chunk due to power loss. This checking policy should |
| 4890 | + * catch that case with very few checks and thus save a |
| 4891 | + * lot of checks that are most likely not needed. |
| 4892 | + * |
| 4893 | + * Mods to the above |
| 4894 | + * If an erase check fails or the write fails we skip the |
| 4895 | + * rest of the block. |
| 4896 | + */ |
| 4897 | |
| 4898 | - if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) |
| 4899 | - T(YAFFS_TRACE_VERIFY, |
| 4900 | - (TSTR("Erased block count wrong dev %d count %d"TENDSTR), |
| 4901 | - dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); |
| 4902 | + /* let's give it a try */ |
| 4903 | + attempts++; |
| 4904 | |
| 4905 | - if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) |
| 4906 | - T(YAFFS_TRACE_VERIFY, |
| 4907 | - (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), |
| 4908 | - nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); |
| 4909 | + if(dev->param.always_check_erased) |
| 4910 | + bi->skip_erased_check = 0; |
| 4911 | |
| 4912 | - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); |
| 4913 | + if (!bi->skip_erased_check) { |
| 4914 | + erasedOk = yaffs_check_chunk_erased(dev, chunk); |
| 4915 | + if (erasedOk != YAFFS_OK) { |
| 4916 | + T(YAFFS_TRACE_ERROR, |
| 4917 | + (TSTR("**>> yaffs chunk %d was not erased" |
| 4918 | + TENDSTR), chunk)); |
| 4919 | |
| 4920 | -} |
| 4921 | + /* If not erased, delete this one, |
| 4922 | + * skip rest of block and |
| 4923 | + * try another chunk */ |
| 4924 | + yaffs_chunk_del(dev,chunk,1,__LINE__); |
| 4925 | + yaffs_skip_rest_of_block(dev); |
| 4926 | + continue; |
| 4927 | + } |
| 4928 | + } |
| 4929 | |
| 4930 | -/* |
| 4931 | - * Verify the object header. oh must be valid, but obj and tags may be NULL in which |
| 4932 | - * case those tests will not be performed. |
| 4933 | - */ |
| 4934 | -static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) |
| 4935 | -{ |
| 4936 | - if (obj && yaffs_SkipVerification(obj->myDev)) |
| 4937 | - return; |
| 4938 | + writeOk = yaffs_wr_chunk_tags_nand(dev, chunk, |
| 4939 | + data, tags); |
| 4940 | |
| 4941 | - if (!(tags && obj && oh)) { |
| 4942 | - T(YAFFS_TRACE_VERIFY, |
| 4943 | - (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR), |
| 4944 | - (__u32)tags, (__u32)obj, (__u32)oh)); |
| 4945 | - return; |
| 4946 | - } |
| 4947 | + if(!bi->skip_erased_check) |
| 4948 | + writeOk = yaffs_verify_chunk_written(dev, chunk, data, tags); |
| 4949 | |
| 4950 | - if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || |
| 4951 | - oh->type > YAFFS_OBJECT_TYPE_MAX) |
| 4952 | - T(YAFFS_TRACE_VERIFY, |
| 4953 | - (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), |
| 4954 | - tags->objectId, oh->type)); |
| 4955 | + if (writeOk != YAFFS_OK) { |
| 4956 | + /* Clean up aborted write, skip to next block and |
| 4957 | + * try another chunk */ |
| 4958 | + yaffs_handle_chunk_wr_error(dev, chunk, erasedOk); |
| 4959 | + continue; |
| 4960 | + } |
| 4961 | |
| 4962 | - if (tags->objectId != obj->objectId) |
| 4963 | - T(YAFFS_TRACE_VERIFY, |
| 4964 | - (TSTR("Obj %d header mismatch objectId %d"TENDSTR), |
| 4965 | - tags->objectId, obj->objectId)); |
| 4966 | + bi->skip_erased_check = 1; |
| 4967 | |
| 4968 | + /* Copy the data into the robustification buffer */ |
| 4969 | + yaffs_handle_chunk_wr_ok(dev, chunk, data, tags); |
| 4970 | |
| 4971 | - /* |
| 4972 | - * Check that the object's parent ids match if parentCheck requested. |
| 4973 | - * |
| 4974 | - * Tests do not apply to the root object. |
| 4975 | - */ |
| 4976 | + } while (writeOk != YAFFS_OK && |
| 4977 | + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); |
| 4978 | |
| 4979 | - if (parentCheck && tags->objectId > 1 && !obj->parent) |
| 4980 | - T(YAFFS_TRACE_VERIFY, |
| 4981 | - (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR), |
| 4982 | - tags->objectId, oh->parentObjectId)); |
| 4983 | + if (!writeOk) |
| 4984 | + chunk = -1; |
| 4985 | |
| 4986 | - if (parentCheck && obj->parent && |
| 4987 | - oh->parentObjectId != obj->parent->objectId && |
| 4988 | - (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED || |
| 4989 | - obj->parent->objectId != YAFFS_OBJECTID_DELETED)) |
| 4990 | - T(YAFFS_TRACE_VERIFY, |
| 4991 | - (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR), |
| 4992 | - tags->objectId, oh->parentObjectId, obj->parent->objectId)); |
| 4993 | + if (attempts > 1) { |
| 4994 | + T(YAFFS_TRACE_ERROR, |
| 4995 | + (TSTR("**>> yaffs write required %d attempts" TENDSTR), |
| 4996 | + attempts)); |
| 4997 | |
| 4998 | - if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */ |
| 4999 | - T(YAFFS_TRACE_VERIFY, |
| 5000 | - (TSTR("Obj %d header name is NULL"TENDSTR), |
| 5001 | - obj->objectId)); |
| 5002 | + dev->n_retired_writes += (attempts - 1); |
| 5003 | + } |
| 5004 | |
| 5005 | - if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ |
| 5006 | - T(YAFFS_TRACE_VERIFY, |
| 5007 | - (TSTR("Obj %d header name is 0xFF"TENDSTR), |
| 5008 | - obj->objectId)); |
| 5009 | + return chunk; |
| 5010 | } |
| 5011 | |
| 5012 | |
| 5013 | + |
| 5014 | +/* |
| 5015 | + * Block retiring for handling a broken block. |
| 5016 | + */ |
| 5017 | |
| 5018 | -static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn, |
| 5019 | - __u32 level, int chunkOffset) |
| 5020 | +static void yaffs_retire_block(yaffs_dev_t *dev, int flash_block) |
| 5021 | { |
| 5022 | - int i; |
| 5023 | - yaffs_Device *dev = obj->myDev; |
| 5024 | - int ok = 1; |
| 5025 | + yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block); |
| 5026 | |
| 5027 | - if (tn) { |
| 5028 | - if (level > 0) { |
| 5029 | + yaffs2_checkpt_invalidate(dev); |
| 5030 | + |
| 5031 | + yaffs2_clear_oldest_dirty_seq(dev,bi); |
| 5032 | |
| 5033 | - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { |
| 5034 | - if (tn->internal[i]) { |
| 5035 | - ok = yaffs_VerifyTnodeWorker(obj, |
| 5036 | - tn->internal[i], |
| 5037 | - level - 1, |
| 5038 | - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i); |
| 5039 | - } |
| 5040 | - } |
| 5041 | - } else if (level == 0) { |
| 5042 | - yaffs_ExtendedTags tags; |
| 5043 | - __u32 objectId = obj->objectId; |
| 5044 | + if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) { |
| 5045 | + if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) { |
| 5046 | + T(YAFFS_TRACE_ALWAYS, (TSTR( |
| 5047 | + "yaffs: Failed to mark bad and erase block %d" |
| 5048 | + TENDSTR), flash_block)); |
| 5049 | + } else { |
| 5050 | + yaffs_ext_tags tags; |
| 5051 | + int chunk_id = flash_block * dev->param.chunks_per_block; |
| 5052 | |
| 5053 | - chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS; |
| 5054 | + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__); |
| 5055 | |
| 5056 | - for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) { |
| 5057 | - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); |
| 5058 | + memset(buffer, 0xff, dev->data_bytes_per_chunk); |
| 5059 | + yaffs_init_tags(&tags); |
| 5060 | + tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK; |
| 5061 | + if (dev->param.write_chunk_tags_fn(dev, chunk_id - |
| 5062 | + dev->chunk_offset, buffer, &tags) != YAFFS_OK) |
| 5063 | + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to " |
| 5064 | + TCONT("write bad block marker to block %d") |
| 5065 | + TENDSTR), flash_block)); |
| 5066 | |
| 5067 | - if (theChunk > 0) { |
| 5068 | - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */ |
| 5069 | - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); |
| 5070 | - if (tags.objectId != objectId || tags.chunkId != chunkOffset) { |
| 5071 | - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), |
| 5072 | - objectId, chunkOffset, theChunk, |
| 5073 | - tags.objectId, tags.chunkId)); |
| 5074 | - } |
| 5075 | - } |
| 5076 | - chunkOffset++; |
| 5077 | - } |
| 5078 | + yaffs_release_temp_buffer(dev, buffer, __LINE__); |
| 5079 | } |
| 5080 | } |
| 5081 | |
| 5082 | - return ok; |
| 5083 | + bi->block_state = YAFFS_BLOCK_STATE_DEAD; |
| 5084 | + bi->gc_prioritise = 0; |
| 5085 | + bi->needs_retiring = 0; |
| 5086 | |
| 5087 | + dev->n_retired_blocks++; |
| 5088 | } |
| 5089 | |
| 5090 | +/* |
| 5091 | + * Functions for robustisizing TODO |
| 5092 | + * |
| 5093 | + */ |
| 5094 | |
| 5095 | -static void yaffs_VerifyFile(yaffs_Object *obj) |
| 5096 | +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk, |
| 5097 | + const __u8 *data, |
| 5098 | + const yaffs_ext_tags *tags) |
| 5099 | { |
| 5100 | - int requiredTallness; |
| 5101 | - int actualTallness; |
| 5102 | - __u32 lastChunk; |
| 5103 | - __u32 x; |
| 5104 | - __u32 i; |
| 5105 | - yaffs_Device *dev; |
| 5106 | - yaffs_ExtendedTags tags; |
| 5107 | - yaffs_Tnode *tn; |
| 5108 | - __u32 objectId; |
| 5109 | + dev=dev; |
| 5110 | + nand_chunk=nand_chunk; |
| 5111 | + data=data; |
| 5112 | + tags=tags; |
| 5113 | +} |
| 5114 | |
| 5115 | - if (!obj) |
| 5116 | - return; |
| 5117 | +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk, |
| 5118 | + const yaffs_ext_tags *tags) |
| 5119 | +{ |
| 5120 | + dev=dev; |
| 5121 | + nand_chunk=nand_chunk; |
| 5122 | + tags=tags; |
| 5123 | +} |
| 5124 | |
| 5125 | - if (yaffs_SkipVerification(obj->myDev)) |
| 5126 | - return; |
| 5127 | +void yaffs_handle_chunk_error(yaffs_dev_t *dev, yaffs_block_info_t *bi) |
| 5128 | +{ |
| 5129 | + if (!bi->gc_prioritise) { |
| 5130 | + bi->gc_prioritise = 1; |
| 5131 | + dev->has_pending_prioritised_gc = 1; |
| 5132 | + bi->chunk_error_strikes++; |
| 5133 | |
| 5134 | - dev = obj->myDev; |
| 5135 | - objectId = obj->objectId; |
| 5136 | + if (bi->chunk_error_strikes > 3) { |
| 5137 | + bi->needs_retiring = 1; /* Too many stikes, so retire this */ |
| 5138 | + T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR))); |
| 5139 | |
| 5140 | - /* Check file size is consistent with tnode depth */ |
| 5141 | - lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1; |
| 5142 | - x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; |
| 5143 | - requiredTallness = 0; |
| 5144 | - while (x > 0) { |
| 5145 | - x >>= YAFFS_TNODES_INTERNAL_BITS; |
| 5146 | - requiredTallness++; |
| 5147 | + } |
| 5148 | } |
| 5149 | +} |
| 5150 | |
| 5151 | - actualTallness = obj->variant.fileVariant.topLevel; |
| 5152 | +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk, |
| 5153 | + int erasedOk) |
| 5154 | +{ |
| 5155 | + int flash_block = nand_chunk / dev->param.chunks_per_block; |
| 5156 | + yaffs_block_info_t *bi = yaffs_get_block_info(dev, flash_block); |
| 5157 | |
| 5158 | - if (requiredTallness > actualTallness) |
| 5159 | - T(YAFFS_TRACE_VERIFY, |
| 5160 | - (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR), |
| 5161 | - obj->objectId, actualTallness, requiredTallness)); |
| 5162 | + yaffs_handle_chunk_error(dev, bi); |
| 5163 | |
| 5164 | + if (erasedOk) { |
| 5165 | + /* Was an actual write failure, so mark the block for retirement */ |
| 5166 | + bi->needs_retiring = 1; |
| 5167 | + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, |
| 5168 | + (TSTR("**>> Block %d needs retiring" TENDSTR), flash_block)); |
| 5169 | + } |
| 5170 | |
| 5171 | - /* Check that the chunks in the tnode tree are all correct. |
| 5172 | - * We do this by scanning through the tnode tree and |
| 5173 | - * checking the tags for every chunk match. |
| 5174 | - */ |
| 5175 | + /* Delete the chunk */ |
| 5176 | + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); |
| 5177 | + yaffs_skip_rest_of_block(dev); |
| 5178 | +} |
| 5179 | |
| 5180 | - if (yaffs_SkipNANDVerification(dev)) |
| 5181 | - return; |
| 5182 | |
| 5183 | - for (i = 1; i <= lastChunk; i++) { |
| 5184 | - tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i); |
| 5185 | +/*---------------- Name handling functions ------------*/ |
| 5186 | |
| 5187 | - if (tn) { |
| 5188 | - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); |
| 5189 | - if (theChunk > 0) { |
| 5190 | - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ |
| 5191 | - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); |
| 5192 | - if (tags.objectId != objectId || tags.chunkId != i) { |
| 5193 | - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), |
| 5194 | - objectId, i, theChunk, |
| 5195 | - tags.objectId, tags.chunkId)); |
| 5196 | - } |
| 5197 | - } |
| 5198 | +static __u16 yaffs_calc_name_sum(const YCHAR *name) |
| 5199 | +{ |
| 5200 | + __u16 sum = 0; |
| 5201 | + __u16 i = 1; |
| 5202 | + |
| 5203 | + const YUCHAR *bname = (const YUCHAR *) name; |
| 5204 | + if (bname) { |
| 5205 | + while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { |
| 5206 | + |
| 5207 | +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE |
| 5208 | + sum += yaffs_toupper(*bname) * i; |
| 5209 | +#else |
| 5210 | + sum += (*bname) * i; |
| 5211 | +#endif |
| 5212 | + i++; |
| 5213 | + bname++; |
| 5214 | } |
| 5215 | } |
| 5216 | + return sum; |
| 5217 | } |
| 5218 | |
| 5219 | - |
| 5220 | -static void yaffs_VerifyHardLink(yaffs_Object *obj) |
| 5221 | +void yaffs_set_obj_name(yaffs_obj_t *obj, const YCHAR *name) |
| 5222 | { |
| 5223 | - if (obj && yaffs_SkipVerification(obj->myDev)) |
| 5224 | - return; |
| 5225 | - |
| 5226 | - /* Verify sane equivalent object */ |
| 5227 | +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM |
| 5228 | + memset(obj->short_name, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1)); |
| 5229 | + if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH) |
| 5230 | + yaffs_strcpy(obj->short_name, name); |
| 5231 | + else |
| 5232 | + obj->short_name[0] = _Y('\0'); |
| 5233 | +#endif |
| 5234 | + obj->sum = yaffs_calc_name_sum(name); |
| 5235 | } |
| 5236 | |
| 5237 | -static void yaffs_VerifySymlink(yaffs_Object *obj) |
| 5238 | +void yaffs_set_obj_name_from_oh(yaffs_obj_t *obj, const yaffs_obj_header *oh) |
| 5239 | { |
| 5240 | - if (obj && yaffs_SkipVerification(obj->myDev)) |
| 5241 | - return; |
| 5242 | - |
| 5243 | - /* Verify symlink string */ |
| 5244 | +#ifdef CONFIG_YAFFS_AUTO_UNICODE |
| 5245 | + YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1]; |
| 5246 | + memset(tmpName,0,sizeof(tmpName)); |
| 5247 | + yaffs_load_name_from_oh(obj->my_dev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1); |
| 5248 | + yaffs_set_obj_name(obj,tmpName); |
| 5249 | +#else |
| 5250 | + yaffs_set_obj_name(obj,oh->name); |
| 5251 | +#endif |
| 5252 | } |
| 5253 | |
| 5254 | -static void yaffs_VerifySpecial(yaffs_Object *obj) |
| 5255 | -{ |
| 5256 | - if (obj && yaffs_SkipVerification(obj->myDev)) |
| 5257 | - return; |
| 5258 | -} |
| 5259 | - |
| 5260 | -static void yaffs_VerifyObject(yaffs_Object *obj) |
| 5261 | -{ |
| 5262 | - yaffs_Device *dev; |
| 5263 | - |
| 5264 | - __u32 chunkMin; |
| 5265 | - __u32 chunkMax; |
| 5266 | - |
| 5267 | - __u32 chunkIdOk; |
| 5268 | - __u32 chunkInRange; |
| 5269 | - __u32 chunkShouldNotBeDeleted; |
| 5270 | - __u32 chunkValid; |
| 5271 | - |
| 5272 | - if (!obj) |
| 5273 | - return; |
| 5274 | - |
| 5275 | - if (obj->beingCreated) |
| 5276 | - return; |
| 5277 | +/*-------------------- TNODES ------------------- |
| 5278 | |
| 5279 | - dev = obj->myDev; |
| 5280 | + * List of spare tnodes |
| 5281 | + * The list is hooked together using the first pointer |
| 5282 | + * in the tnode. |
| 5283 | + */ |
| 5284 | |
| 5285 | - if (yaffs_SkipVerification(dev)) |
| 5286 | - return; |
| 5287 | |
| 5288 | - /* Check sane object header chunk */ |
| 5289 | +yaffs_tnode_t *yaffs_get_tnode(yaffs_dev_t *dev) |
| 5290 | +{ |
| 5291 | + yaffs_tnode_t *tn = yaffs_alloc_raw_tnode(dev); |
| 5292 | + if (tn){ |
| 5293 | + memset(tn, 0, dev->tnode_size); |
| 5294 | + dev->n_tnodes++; |
| 5295 | + } |
| 5296 | |
| 5297 | - chunkMin = dev->internalStartBlock * dev->nChunksPerBlock; |
| 5298 | - chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1; |
| 5299 | + dev->checkpoint_blocks_required = 0; /* force recalculation*/ |
| 5300 | |
| 5301 | - chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax); |
| 5302 | - chunkIdOk = chunkInRange || obj->hdrChunk == 0; |
| 5303 | - chunkValid = chunkInRange && |
| 5304 | - yaffs_CheckChunkBit(dev, |
| 5305 | - obj->hdrChunk / dev->nChunksPerBlock, |
| 5306 | - obj->hdrChunk % dev->nChunksPerBlock); |
| 5307 | - chunkShouldNotBeDeleted = chunkInRange && !chunkValid; |
| 5308 | + return tn; |
| 5309 | +} |
| 5310 | |
| 5311 | - if (!obj->fake && |
| 5312 | - (!chunkIdOk || chunkShouldNotBeDeleted)) { |
| 5313 | - T(YAFFS_TRACE_VERIFY, |
| 5314 | - (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), |
| 5315 | - obj->objectId, obj->hdrChunk, |
| 5316 | - chunkIdOk ? "" : ",out of range", |
| 5317 | - chunkShouldNotBeDeleted ? ",marked as deleted" : "")); |
| 5318 | - } |
| 5319 | +/* FreeTnode frees up a tnode and puts it back on the free list */ |
| 5320 | +static void yaffs_free_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn) |
| 5321 | +{ |
| 5322 | + yaffs_free_raw_tnode(dev,tn); |
| 5323 | + dev->n_tnodes--; |
| 5324 | + dev->checkpoint_blocks_required = 0; /* force recalculation*/ |
| 5325 | +} |
| 5326 | |
| 5327 | - if (chunkValid && !yaffs_SkipNANDVerification(dev)) { |
| 5328 | - yaffs_ExtendedTags tags; |
| 5329 | - yaffs_ObjectHeader *oh; |
| 5330 | - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); |
| 5331 | +static void yaffs_deinit_tnodes_and_objs(yaffs_dev_t *dev) |
| 5332 | +{ |
| 5333 | + yaffs_deinit_raw_tnodes_and_objs(dev); |
| 5334 | + dev->n_obj = 0; |
| 5335 | + dev->n_tnodes = 0; |
| 5336 | +} |
| 5337 | |
| 5338 | - oh = (yaffs_ObjectHeader *)buffer; |
| 5339 | |
| 5340 | - yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer, |
| 5341 | - &tags); |
| 5342 | +void yaffs_load_tnode_0(yaffs_dev_t *dev, yaffs_tnode_t *tn, unsigned pos, |
| 5343 | + unsigned val) |
| 5344 | +{ |
| 5345 | + __u32 *map = (__u32 *)tn; |
| 5346 | + __u32 bitInMap; |
| 5347 | + __u32 bitInWord; |
| 5348 | + __u32 wordInMap; |
| 5349 | + __u32 mask; |
| 5350 | |
| 5351 | - yaffs_VerifyObjectHeader(obj, oh, &tags, 1); |
| 5352 | + pos &= YAFFS_TNODES_LEVEL0_MASK; |
| 5353 | + val >>= dev->chunk_grp_bits; |
| 5354 | |
| 5355 | - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); |
| 5356 | - } |
| 5357 | + bitInMap = pos * dev->tnode_width; |
| 5358 | + wordInMap = bitInMap / 32; |
| 5359 | + bitInWord = bitInMap & (32 - 1); |
| 5360 | |
| 5361 | - /* Verify it has a parent */ |
| 5362 | - if (obj && !obj->fake && |
| 5363 | - (!obj->parent || obj->parent->myDev != dev)) { |
| 5364 | - T(YAFFS_TRACE_VERIFY, |
| 5365 | - (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), |
| 5366 | - obj->objectId, obj->parent)); |
| 5367 | - } |
| 5368 | + mask = dev->tnode_mask << bitInWord; |
| 5369 | |
| 5370 | - /* Verify parent is a directory */ |
| 5371 | - if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 5372 | - T(YAFFS_TRACE_VERIFY, |
| 5373 | - (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), |
| 5374 | - obj->objectId, obj->parent->variantType)); |
| 5375 | - } |
| 5376 | + map[wordInMap] &= ~mask; |
| 5377 | + map[wordInMap] |= (mask & (val << bitInWord)); |
| 5378 | |
| 5379 | - switch (obj->variantType) { |
| 5380 | - case YAFFS_OBJECT_TYPE_FILE: |
| 5381 | - yaffs_VerifyFile(obj); |
| 5382 | - break; |
| 5383 | - case YAFFS_OBJECT_TYPE_SYMLINK: |
| 5384 | - yaffs_VerifySymlink(obj); |
| 5385 | - break; |
| 5386 | - case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 5387 | - yaffs_VerifyDirectory(obj); |
| 5388 | - break; |
| 5389 | - case YAFFS_OBJECT_TYPE_HARDLINK: |
| 5390 | - yaffs_VerifyHardLink(obj); |
| 5391 | - break; |
| 5392 | - case YAFFS_OBJECT_TYPE_SPECIAL: |
| 5393 | - yaffs_VerifySpecial(obj); |
| 5394 | - break; |
| 5395 | - case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 5396 | - default: |
| 5397 | - T(YAFFS_TRACE_VERIFY, |
| 5398 | - (TSTR("Obj %d has illegaltype %d"TENDSTR), |
| 5399 | - obj->objectId, obj->variantType)); |
| 5400 | - break; |
| 5401 | + if (dev->tnode_width > (32 - bitInWord)) { |
| 5402 | + bitInWord = (32 - bitInWord); |
| 5403 | + wordInMap++;; |
| 5404 | + mask = dev->tnode_mask >> (/*dev->tnode_width -*/ bitInWord); |
| 5405 | + map[wordInMap] &= ~mask; |
| 5406 | + map[wordInMap] |= (mask & (val >> bitInWord)); |
| 5407 | } |
| 5408 | } |
| 5409 | |
| 5410 | -static void yaffs_VerifyObjects(yaffs_Device *dev) |
| 5411 | +__u32 yaffs_get_group_base(yaffs_dev_t *dev, yaffs_tnode_t *tn, |
| 5412 | + unsigned pos) |
| 5413 | { |
| 5414 | - yaffs_Object *obj; |
| 5415 | - int i; |
| 5416 | - struct ylist_head *lh; |
| 5417 | + __u32 *map = (__u32 *)tn; |
| 5418 | + __u32 bitInMap; |
| 5419 | + __u32 bitInWord; |
| 5420 | + __u32 wordInMap; |
| 5421 | + __u32 val; |
| 5422 | |
| 5423 | - if (yaffs_SkipVerification(dev)) |
| 5424 | - return; |
| 5425 | + pos &= YAFFS_TNODES_LEVEL0_MASK; |
| 5426 | |
| 5427 | - /* Iterate through the objects in each hash entry */ |
| 5428 | + bitInMap = pos * dev->tnode_width; |
| 5429 | + wordInMap = bitInMap / 32; |
| 5430 | + bitInWord = bitInMap & (32 - 1); |
| 5431 | |
| 5432 | - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { |
| 5433 | - ylist_for_each(lh, &dev->objectBucket[i].list) { |
| 5434 | - if (lh) { |
| 5435 | - obj = ylist_entry(lh, yaffs_Object, hashLink); |
| 5436 | - yaffs_VerifyObject(obj); |
| 5437 | - } |
| 5438 | - } |
| 5439 | - } |
| 5440 | -} |
| 5441 | + val = map[wordInMap] >> bitInWord; |
| 5442 | |
| 5443 | + if (dev->tnode_width > (32 - bitInWord)) { |
| 5444 | + bitInWord = (32 - bitInWord); |
| 5445 | + wordInMap++;; |
| 5446 | + val |= (map[wordInMap] << bitInWord); |
| 5447 | + } |
| 5448 | |
| 5449 | -/* |
| 5450 | - * Simple hash function. Needs to have a reasonable spread |
| 5451 | - */ |
| 5452 | + val &= dev->tnode_mask; |
| 5453 | + val <<= dev->chunk_grp_bits; |
| 5454 | |
| 5455 | -static Y_INLINE int yaffs_HashFunction(int n) |
| 5456 | -{ |
| 5457 | - n = abs(n); |
| 5458 | - return n % YAFFS_NOBJECT_BUCKETS; |
| 5459 | + return val; |
| 5460 | } |
| 5461 | |
| 5462 | -/* |
| 5463 | - * Access functions to useful fake objects. |
| 5464 | - * Note that root might have a presence in NAND if permissions are set. |
| 5465 | +/* ------------------- End of individual tnode manipulation -----------------*/ |
| 5466 | + |
| 5467 | +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ |
| 5468 | + * The look up tree is represented by the top tnode and the number of top_level |
| 5469 | + * in the tree. 0 means only the level 0 tnode is in the tree. |
| 5470 | */ |
| 5471 | |
| 5472 | -yaffs_Object *yaffs_Root(yaffs_Device *dev) |
| 5473 | +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ |
| 5474 | +yaffs_tnode_t *yaffs_find_tnode_0(yaffs_dev_t *dev, |
| 5475 | + yaffs_file_s *file_struct, |
| 5476 | + __u32 chunk_id) |
| 5477 | { |
| 5478 | - return dev->rootDir; |
| 5479 | -} |
| 5480 | + yaffs_tnode_t *tn = file_struct->top; |
| 5481 | + __u32 i; |
| 5482 | + int requiredTallness; |
| 5483 | + int level = file_struct->top_level; |
| 5484 | |
| 5485 | -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev) |
| 5486 | -{ |
| 5487 | - return dev->lostNFoundDir; |
| 5488 | -} |
| 5489 | + dev=dev; |
| 5490 | |
| 5491 | + /* Check sane level and chunk Id */ |
| 5492 | + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) |
| 5493 | + return NULL; |
| 5494 | |
| 5495 | -/* |
| 5496 | - * Erased NAND checking functions |
| 5497 | - */ |
| 5498 | + if (chunk_id > YAFFS_MAX_CHUNK_ID) |
| 5499 | + return NULL; |
| 5500 | |
| 5501 | -int yaffs_CheckFF(__u8 *buffer, int nBytes) |
| 5502 | -{ |
| 5503 | - /* Horrible, slow implementation */ |
| 5504 | - while (nBytes--) { |
| 5505 | - if (*buffer != 0xFF) |
| 5506 | - return 0; |
| 5507 | - buffer++; |
| 5508 | + /* First check we're tall enough (ie enough top_level) */ |
| 5509 | + |
| 5510 | + i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; |
| 5511 | + requiredTallness = 0; |
| 5512 | + while (i) { |
| 5513 | + i >>= YAFFS_TNODES_INTERNAL_BITS; |
| 5514 | + requiredTallness++; |
| 5515 | } |
| 5516 | - return 1; |
| 5517 | -} |
| 5518 | |
| 5519 | -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, |
| 5520 | - int chunkInNAND) |
| 5521 | -{ |
| 5522 | - int retval = YAFFS_OK; |
| 5523 | - __u8 *data = yaffs_GetTempBuffer(dev, __LINE__); |
| 5524 | - yaffs_ExtendedTags tags; |
| 5525 | - int result; |
| 5526 | + if (requiredTallness > file_struct->top_level) |
| 5527 | + return NULL; /* Not tall enough, so we can't find it */ |
| 5528 | + |
| 5529 | + /* Traverse down to level 0 */ |
| 5530 | + while (level > 0 && tn) { |
| 5531 | + tn = tn->internal[(chunk_id >> |
| 5532 | + (YAFFS_TNODES_LEVEL0_BITS + |
| 5533 | + (level - 1) * |
| 5534 | + YAFFS_TNODES_INTERNAL_BITS)) & |
| 5535 | + YAFFS_TNODES_INTERNAL_MASK]; |
| 5536 | + level--; |
| 5537 | + } |
| 5538 | |
| 5539 | - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags); |
| 5540 | + return tn; |
| 5541 | +} |
| 5542 | |
| 5543 | - if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR) |
| 5544 | - retval = YAFFS_FAIL; |
| 5545 | +/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree. |
| 5546 | + * This happens in two steps: |
| 5547 | + * 1. If the tree isn't tall enough, then make it taller. |
| 5548 | + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. |
| 5549 | + * |
| 5550 | + * Used when modifying the tree. |
| 5551 | + * |
| 5552 | + * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will |
| 5553 | + * be plugged into the ttree. |
| 5554 | + */ |
| 5555 | |
| 5556 | - if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) { |
| 5557 | - T(YAFFS_TRACE_NANDACCESS, |
| 5558 | - (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND)); |
| 5559 | - retval = YAFFS_FAIL; |
| 5560 | - } |
| 5561 | +yaffs_tnode_t *yaffs_add_find_tnode_0(yaffs_dev_t *dev, |
| 5562 | + yaffs_file_s *file_struct, |
| 5563 | + __u32 chunk_id, |
| 5564 | + yaffs_tnode_t *passed_tn) |
| 5565 | +{ |
| 5566 | + int requiredTallness; |
| 5567 | + int i; |
| 5568 | + int l; |
| 5569 | + yaffs_tnode_t *tn; |
| 5570 | |
| 5571 | - yaffs_ReleaseTempBuffer(dev, data, __LINE__); |
| 5572 | + __u32 x; |
| 5573 | |
| 5574 | - return retval; |
| 5575 | |
| 5576 | -} |
| 5577 | + /* Check sane level and page Id */ |
| 5578 | + if (file_struct->top_level < 0 || file_struct->top_level > YAFFS_TNODES_MAX_LEVEL) |
| 5579 | + return NULL; |
| 5580 | |
| 5581 | -static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, |
| 5582 | - const __u8 *data, |
| 5583 | - yaffs_ExtendedTags *tags, |
| 5584 | - int useReserve) |
| 5585 | -{ |
| 5586 | - int attempts = 0; |
| 5587 | - int writeOk = 0; |
| 5588 | - int chunk; |
| 5589 | + if (chunk_id > YAFFS_MAX_CHUNK_ID) |
| 5590 | + return NULL; |
| 5591 | |
| 5592 | - yaffs_InvalidateCheckpoint(dev); |
| 5593 | + /* First check we're tall enough (ie enough top_level) */ |
| 5594 | |
| 5595 | - do { |
| 5596 | - yaffs_BlockInfo *bi = 0; |
| 5597 | - int erasedOk = 0; |
| 5598 | + x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; |
| 5599 | + requiredTallness = 0; |
| 5600 | + while (x) { |
| 5601 | + x >>= YAFFS_TNODES_INTERNAL_BITS; |
| 5602 | + requiredTallness++; |
| 5603 | + } |
| 5604 | |
| 5605 | - chunk = yaffs_AllocateChunk(dev, useReserve, &bi); |
| 5606 | - if (chunk < 0) { |
| 5607 | - /* no space */ |
| 5608 | - break; |
| 5609 | - } |
| 5610 | |
| 5611 | - /* First check this chunk is erased, if it needs |
| 5612 | - * checking. The checking policy (unless forced |
| 5613 | - * always on) is as follows: |
| 5614 | - * |
| 5615 | - * Check the first page we try to write in a block. |
| 5616 | - * If the check passes then we don't need to check any |
| 5617 | - * more. If the check fails, we check again... |
| 5618 | - * If the block has been erased, we don't need to check. |
| 5619 | - * |
| 5620 | - * However, if the block has been prioritised for gc, |
| 5621 | - * then we think there might be something odd about |
| 5622 | - * this block and stop using it. |
| 5623 | - * |
| 5624 | - * Rationale: We should only ever see chunks that have |
| 5625 | - * not been erased if there was a partially written |
| 5626 | - * chunk due to power loss. This checking policy should |
| 5627 | - * catch that case with very few checks and thus save a |
| 5628 | - * lot of checks that are most likely not needed. |
| 5629 | - */ |
| 5630 | - if (bi->gcPrioritise) { |
| 5631 | - yaffs_DeleteChunk(dev, chunk, 1, __LINE__); |
| 5632 | - /* try another chunk */ |
| 5633 | - continue; |
| 5634 | - } |
| 5635 | + if (requiredTallness > file_struct->top_level) { |
| 5636 | + /* Not tall enough, gotta make the tree taller */ |
| 5637 | + for (i = file_struct->top_level; i < requiredTallness; i++) { |
| 5638 | |
| 5639 | - /* let's give it a try */ |
| 5640 | - attempts++; |
| 5641 | + tn = yaffs_get_tnode(dev); |
| 5642 | |
| 5643 | -#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED |
| 5644 | - bi->skipErasedCheck = 0; |
| 5645 | -#endif |
| 5646 | - if (!bi->skipErasedCheck) { |
| 5647 | - erasedOk = yaffs_CheckChunkErased(dev, chunk); |
| 5648 | - if (erasedOk != YAFFS_OK) { |
| 5649 | + if (tn) { |
| 5650 | + tn->internal[0] = file_struct->top; |
| 5651 | + file_struct->top = tn; |
| 5652 | + file_struct->top_level++; |
| 5653 | + } else { |
| 5654 | T(YAFFS_TRACE_ERROR, |
| 5655 | - (TSTR("**>> yaffs chunk %d was not erased" |
| 5656 | - TENDSTR), chunk)); |
| 5657 | - |
| 5658 | - /* try another chunk */ |
| 5659 | - continue; |
| 5660 | + (TSTR("yaffs: no more tnodes" TENDSTR))); |
| 5661 | + return NULL; |
| 5662 | } |
| 5663 | - bi->skipErasedCheck = 1; |
| 5664 | } |
| 5665 | + } |
| 5666 | |
| 5667 | - writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, |
| 5668 | - data, tags); |
| 5669 | - if (writeOk != YAFFS_OK) { |
| 5670 | - yaffs_HandleWriteChunkError(dev, chunk, erasedOk); |
| 5671 | - /* try another chunk */ |
| 5672 | - continue; |
| 5673 | - } |
| 5674 | + /* Traverse down to level 0, adding anything we need */ |
| 5675 | |
| 5676 | - /* Copy the data into the robustification buffer */ |
| 5677 | - yaffs_HandleWriteChunkOk(dev, chunk, data, tags); |
| 5678 | + l = file_struct->top_level; |
| 5679 | + tn = file_struct->top; |
| 5680 | |
| 5681 | - } while (writeOk != YAFFS_OK && |
| 5682 | - (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); |
| 5683 | + if (l > 0) { |
| 5684 | + while (l > 0 && tn) { |
| 5685 | + x = (chunk_id >> |
| 5686 | + (YAFFS_TNODES_LEVEL0_BITS + |
| 5687 | + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & |
| 5688 | + YAFFS_TNODES_INTERNAL_MASK; |
| 5689 | |
| 5690 | - if (!writeOk) |
| 5691 | - chunk = -1; |
| 5692 | |
| 5693 | - if (attempts > 1) { |
| 5694 | - T(YAFFS_TRACE_ERROR, |
| 5695 | - (TSTR("**>> yaffs write required %d attempts" TENDSTR), |
| 5696 | - attempts)); |
| 5697 | + if ((l > 1) && !tn->internal[x]) { |
| 5698 | + /* Add missing non-level-zero tnode */ |
| 5699 | + tn->internal[x] = yaffs_get_tnode(dev); |
| 5700 | + if(!tn->internal[x]) |
| 5701 | + return NULL; |
| 5702 | + } else if (l == 1) { |
| 5703 | + /* Looking from level 1 at level 0 */ |
| 5704 | + if (passed_tn) { |
| 5705 | + /* If we already have one, then release it.*/ |
| 5706 | + if (tn->internal[x]) |
| 5707 | + yaffs_free_tnode(dev, tn->internal[x]); |
| 5708 | + tn->internal[x] = passed_tn; |
| 5709 | + |
| 5710 | + } else if (!tn->internal[x]) { |
| 5711 | + /* Don't have one, none passed in */ |
| 5712 | + tn->internal[x] = yaffs_get_tnode(dev); |
| 5713 | + if(!tn->internal[x]) |
| 5714 | + return NULL; |
| 5715 | + } |
| 5716 | + } |
| 5717 | |
| 5718 | - dev->nRetriedWrites += (attempts - 1); |
| 5719 | + tn = tn->internal[x]; |
| 5720 | + l--; |
| 5721 | + } |
| 5722 | + } else { |
| 5723 | + /* top is level 0 */ |
| 5724 | + if (passed_tn) { |
| 5725 | + memcpy(tn, passed_tn, (dev->tnode_width * YAFFS_NTNODES_LEVEL0)/8); |
| 5726 | + yaffs_free_tnode(dev, passed_tn); |
| 5727 | + } |
| 5728 | } |
| 5729 | |
| 5730 | - return chunk; |
| 5731 | + return tn; |
| 5732 | } |
| 5733 | |
| 5734 | -/* |
| 5735 | - * Block retiring for handling a broken block. |
| 5736 | - */ |
| 5737 | - |
| 5738 | -static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND) |
| 5739 | +static int yaffs_find_chunk_in_group(yaffs_dev_t *dev, int theChunk, |
| 5740 | + yaffs_ext_tags *tags, int obj_id, |
| 5741 | + int inode_chunk) |
| 5742 | { |
| 5743 | - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); |
| 5744 | + int j; |
| 5745 | |
| 5746 | - yaffs_InvalidateCheckpoint(dev); |
| 5747 | + for (j = 0; theChunk && j < dev->chunk_grp_size; j++) { |
| 5748 | + if (yaffs_check_chunk_bit(dev, theChunk / dev->param.chunks_per_block, |
| 5749 | + theChunk % dev->param.chunks_per_block)) { |
| 5750 | + |
| 5751 | + if(dev->chunk_grp_size == 1) |
| 5752 | + return theChunk; |
| 5753 | + else { |
| 5754 | + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, |
| 5755 | + tags); |
| 5756 | + if (yaffs_tags_match(tags, obj_id, inode_chunk)) { |
| 5757 | + /* found it; */ |
| 5758 | + return theChunk; |
| 5759 | + } |
| 5760 | + } |
| 5761 | + } |
| 5762 | + theChunk++; |
| 5763 | + } |
| 5764 | + return -1; |
| 5765 | +} |
| 5766 | |
| 5767 | - if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) { |
| 5768 | - if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) { |
| 5769 | - T(YAFFS_TRACE_ALWAYS, (TSTR( |
| 5770 | - "yaffs: Failed to mark bad and erase block %d" |
| 5771 | - TENDSTR), blockInNAND)); |
| 5772 | - } else { |
| 5773 | - yaffs_ExtendedTags tags; |
| 5774 | - int chunkId = blockInNAND * dev->nChunksPerBlock; |
| 5775 | +#if 0 |
| 5776 | +/* Experimental code not being used yet. Might speed up file deletion */ |
| 5777 | +/* DeleteWorker scans backwards through the tnode tree and deletes all the |
| 5778 | + * chunks and tnodes in the file. |
| 5779 | + * Returns 1 if the tree was deleted. |
| 5780 | + * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete. |
| 5781 | + */ |
| 5782 | |
| 5783 | - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); |
| 5784 | +static int yaffs_del_worker(yaffs_obj_t *in, yaffs_tnode_t *tn, __u32 level, |
| 5785 | + int chunk_offset, int *limit) |
| 5786 | +{ |
| 5787 | + int i; |
| 5788 | + int inode_chunk; |
| 5789 | + int theChunk; |
| 5790 | + yaffs_ext_tags tags; |
| 5791 | + int foundChunk; |
| 5792 | + yaffs_dev_t *dev = in->my_dev; |
| 5793 | |
| 5794 | - memset(buffer, 0xff, dev->nDataBytesPerChunk); |
| 5795 | - yaffs_InitialiseTags(&tags); |
| 5796 | - tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK; |
| 5797 | - if (dev->writeChunkWithTagsToNAND(dev, chunkId - |
| 5798 | - dev->chunkOffset, buffer, &tags) != YAFFS_OK) |
| 5799 | - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to " |
| 5800 | - TCONT("write bad block marker to block %d") |
| 5801 | - TENDSTR), blockInNAND)); |
| 5802 | + int allDone = 1; |
| 5803 | |
| 5804 | - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); |
| 5805 | - } |
| 5806 | - } |
| 5807 | + if (tn) { |
| 5808 | + if (level > 0) { |
| 5809 | + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; |
| 5810 | + i--) { |
| 5811 | + if (tn->internal[i]) { |
| 5812 | + if (limit && (*limit) < 0) { |
| 5813 | + allDone = 0; |
| 5814 | + } else { |
| 5815 | + allDone = |
| 5816 | + yaffs_del_worker(in, |
| 5817 | + tn-> |
| 5818 | + internal |
| 5819 | + [i], |
| 5820 | + level - |
| 5821 | + 1, |
| 5822 | + (chunk_offset |
| 5823 | + << |
| 5824 | + YAFFS_TNODES_INTERNAL_BITS) |
| 5825 | + + i, |
| 5826 | + limit); |
| 5827 | + } |
| 5828 | + if (allDone) { |
| 5829 | + yaffs_free_tnode(dev, |
| 5830 | + tn-> |
| 5831 | + internal[i]); |
| 5832 | + tn->internal[i] = NULL; |
| 5833 | + } |
| 5834 | + } |
| 5835 | + } |
| 5836 | + return (allDone) ? 1 : 0; |
| 5837 | + } else if (level == 0) { |
| 5838 | + int hitLimit = 0; |
| 5839 | |
| 5840 | - bi->blockState = YAFFS_BLOCK_STATE_DEAD; |
| 5841 | - bi->gcPrioritise = 0; |
| 5842 | - bi->needsRetiring = 0; |
| 5843 | + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit; |
| 5844 | + i--) { |
| 5845 | + theChunk = yaffs_get_group_base(dev, tn, i); |
| 5846 | + if (theChunk) { |
| 5847 | |
| 5848 | - dev->nRetiredBlocks++; |
| 5849 | -} |
| 5850 | + inode_chunk = (chunk_offset << |
| 5851 | + YAFFS_TNODES_LEVEL0_BITS) + i; |
| 5852 | |
| 5853 | -/* |
| 5854 | - * Functions for robustisizing TODO |
| 5855 | - * |
| 5856 | - */ |
| 5857 | + foundChunk = |
| 5858 | + yaffs_find_chunk_in_group(dev, |
| 5859 | + theChunk, |
| 5860 | + &tags, |
| 5861 | + in->obj_id, |
| 5862 | + inode_chunk); |
| 5863 | |
| 5864 | -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, |
| 5865 | - const __u8 *data, |
| 5866 | - const yaffs_ExtendedTags *tags) |
| 5867 | -{ |
| 5868 | -} |
| 5869 | + if (foundChunk > 0) { |
| 5870 | + yaffs_chunk_del(dev, |
| 5871 | + foundChunk, 1, |
| 5872 | + __LINE__); |
| 5873 | + in->n_data_chunks--; |
| 5874 | + if (limit) { |
| 5875 | + *limit = *limit - 1; |
| 5876 | + if (*limit <= 0) |
| 5877 | + hitLimit = 1; |
| 5878 | + } |
| 5879 | |
| 5880 | -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, |
| 5881 | - const yaffs_ExtendedTags *tags) |
| 5882 | -{ |
| 5883 | -} |
| 5884 | + } |
| 5885 | |
| 5886 | -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi) |
| 5887 | -{ |
| 5888 | - if (!bi->gcPrioritise) { |
| 5889 | - bi->gcPrioritise = 1; |
| 5890 | - dev->hasPendingPrioritisedGCs = 1; |
| 5891 | - bi->chunkErrorStrikes++; |
| 5892 | + yaffs_load_tnode_0(dev, tn, i, 0); |
| 5893 | + } |
| 5894 | |
| 5895 | - if (bi->chunkErrorStrikes > 3) { |
| 5896 | - bi->needsRetiring = 1; /* Too many stikes, so retire this */ |
| 5897 | - T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR))); |
| 5898 | + } |
| 5899 | + return (i < 0) ? 1 : 0; |
| 5900 | |
| 5901 | } |
| 5902 | + |
| 5903 | } |
| 5904 | + |
| 5905 | + return 1; |
| 5906 | + |
| 5907 | } |
| 5908 | |
| 5909 | -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND, |
| 5910 | - int erasedOk) |
| 5911 | +#endif |
| 5912 | + |
| 5913 | +static void yaffs_soft_del_chunk(yaffs_dev_t *dev, int chunk) |
| 5914 | { |
| 5915 | - int blockInNAND = chunkInNAND / dev->nChunksPerBlock; |
| 5916 | - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); |
| 5917 | + yaffs_block_info_t *theBlock; |
| 5918 | + unsigned block_no; |
| 5919 | |
| 5920 | - yaffs_HandleChunkError(dev, bi); |
| 5921 | + T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk)); |
| 5922 | |
| 5923 | - if (erasedOk) { |
| 5924 | - /* Was an actual write failure, so mark the block for retirement */ |
| 5925 | - bi->needsRetiring = 1; |
| 5926 | - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, |
| 5927 | - (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND)); |
| 5928 | + block_no = chunk / dev->param.chunks_per_block; |
| 5929 | + theBlock = yaffs_get_block_info(dev, block_no); |
| 5930 | + if (theBlock) { |
| 5931 | + theBlock->soft_del_pages++; |
| 5932 | + dev->n_free_chunks++; |
| 5933 | + yaffs2_update_oldest_dirty_seq(dev, block_no, theBlock); |
| 5934 | } |
| 5935 | - |
| 5936 | - /* Delete the chunk */ |
| 5937 | - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); |
| 5938 | } |
| 5939 | |
| 5940 | +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file. |
| 5941 | + * All soft deleting does is increment the block's softdelete count and pulls the chunk out |
| 5942 | + * of the tnode. |
| 5943 | + * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted. |
| 5944 | + */ |
| 5945 | |
| 5946 | -/*---------------- Name handling functions ------------*/ |
| 5947 | - |
| 5948 | -static __u16 yaffs_CalcNameSum(const YCHAR *name) |
| 5949 | +static int yaffs_soft_del_worker(yaffs_obj_t *in, yaffs_tnode_t *tn, |
| 5950 | + __u32 level, int chunk_offset) |
| 5951 | { |
| 5952 | - __u16 sum = 0; |
| 5953 | - __u16 i = 1; |
| 5954 | + int i; |
| 5955 | + int theChunk; |
| 5956 | + int allDone = 1; |
| 5957 | + yaffs_dev_t *dev = in->my_dev; |
| 5958 | |
| 5959 | - const YUCHAR *bname = (const YUCHAR *) name; |
| 5960 | - if (bname) { |
| 5961 | - while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { |
| 5962 | + if (tn) { |
| 5963 | + if (level > 0) { |
| 5964 | + |
| 5965 | + for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; |
| 5966 | + i--) { |
| 5967 | + if (tn->internal[i]) { |
| 5968 | + allDone = |
| 5969 | + yaffs_soft_del_worker(in, |
| 5970 | + tn-> |
| 5971 | + internal[i], |
| 5972 | + level - 1, |
| 5973 | + (chunk_offset |
| 5974 | + << |
| 5975 | + YAFFS_TNODES_INTERNAL_BITS) |
| 5976 | + + i); |
| 5977 | + if (allDone) { |
| 5978 | + yaffs_free_tnode(dev, |
| 5979 | + tn-> |
| 5980 | + internal[i]); |
| 5981 | + tn->internal[i] = NULL; |
| 5982 | + } else { |
| 5983 | + /* Hoosterman... how could this happen? */ |
| 5984 | + } |
| 5985 | + } |
| 5986 | + } |
| 5987 | + return (allDone) ? 1 : 0; |
| 5988 | + } else if (level == 0) { |
| 5989 | + |
| 5990 | + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { |
| 5991 | + theChunk = yaffs_get_group_base(dev, tn, i); |
| 5992 | + if (theChunk) { |
| 5993 | + /* Note this does not find the real chunk, only the chunk group. |
| 5994 | + * We make an assumption that a chunk group is not larger than |
| 5995 | + * a block. |
| 5996 | + */ |
| 5997 | + yaffs_soft_del_chunk(dev, theChunk); |
| 5998 | + yaffs_load_tnode_0(dev, tn, i, 0); |
| 5999 | + } |
| 6000 | + |
| 6001 | + } |
| 6002 | + return 1; |
| 6003 | |
| 6004 | -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE |
| 6005 | - sum += yaffs_toupper(*bname) * i; |
| 6006 | -#else |
| 6007 | - sum += (*bname) * i; |
| 6008 | -#endif |
| 6009 | - i++; |
| 6010 | - bname++; |
| 6011 | } |
| 6012 | + |
| 6013 | } |
| 6014 | - return sum; |
| 6015 | + |
| 6016 | + return 1; |
| 6017 | + |
| 6018 | } |
| 6019 | |
| 6020 | -static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) |
| 6021 | +static void yaffs_soft_del_file(yaffs_obj_t *obj) |
| 6022 | { |
| 6023 | -#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM |
| 6024 | - memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1)); |
| 6025 | - if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) |
| 6026 | - yaffs_strcpy(obj->shortName, name); |
| 6027 | - else |
| 6028 | - obj->shortName[0] = _Y('\0'); |
| 6029 | -#endif |
| 6030 | - obj->sum = yaffs_CalcNameSum(name); |
| 6031 | + if (obj->deleted && |
| 6032 | + obj->variant_type == YAFFS_OBJECT_TYPE_FILE && !obj->soft_del) { |
| 6033 | + if (obj->n_data_chunks <= 0) { |
| 6034 | + /* Empty file with no duplicate object headers, just delete it immediately */ |
| 6035 | + yaffs_free_tnode(obj->my_dev, |
| 6036 | + obj->variant.file_variant.top); |
| 6037 | + obj->variant.file_variant.top = NULL; |
| 6038 | + T(YAFFS_TRACE_TRACING, |
| 6039 | + (TSTR("yaffs: Deleting empty file %d" TENDSTR), |
| 6040 | + obj->obj_id)); |
| 6041 | + yaffs_generic_obj_del(obj); |
| 6042 | + } else { |
| 6043 | + yaffs_soft_del_worker(obj, |
| 6044 | + obj->variant.file_variant.top, |
| 6045 | + obj->variant.file_variant. |
| 6046 | + top_level, 0); |
| 6047 | + obj->soft_del = 1; |
| 6048 | + } |
| 6049 | + } |
| 6050 | } |
| 6051 | |
| 6052 | -/*-------------------- TNODES ------------------- |
| 6053 | - |
| 6054 | - * List of spare tnodes |
| 6055 | - * The list is hooked together using the first pointer |
| 6056 | - * in the tnode. |
| 6057 | - */ |
| 6058 | - |
| 6059 | -/* yaffs_CreateTnodes creates a bunch more tnodes and |
| 6060 | - * adds them to the tnode free list. |
| 6061 | - * Don't use this function directly |
| 6062 | +/* Pruning removes any part of the file structure tree that is beyond the |
| 6063 | + * bounds of the file (ie that does not point to chunks). |
| 6064 | + * |
| 6065 | + * A file should only get pruned when its size is reduced. |
| 6066 | + * |
| 6067 | + * Before pruning, the chunks must be pulled from the tree and the |
| 6068 | + * level 0 tnode entries must be zeroed out. |
| 6069 | + * Could also use this for file deletion, but that's probably better handled |
| 6070 | + * by a special case. |
| 6071 | + * |
| 6072 | + * This function is recursive. For levels > 0 the function is called again on |
| 6073 | + * any sub-tree. For level == 0 we just check if the sub-tree has data. |
| 6074 | + * If there is no data in a subtree then it is pruned. |
| 6075 | */ |
| 6076 | |
| 6077 | -static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes) |
| 6078 | +static yaffs_tnode_t *yaffs_prune_worker(yaffs_dev_t *dev, yaffs_tnode_t *tn, |
| 6079 | + __u32 level, int del0) |
| 6080 | { |
| 6081 | int i; |
| 6082 | - int tnodeSize; |
| 6083 | - yaffs_Tnode *newTnodes; |
| 6084 | - __u8 *mem; |
| 6085 | - yaffs_Tnode *curr; |
| 6086 | - yaffs_Tnode *next; |
| 6087 | - yaffs_TnodeList *tnl; |
| 6088 | + int hasData; |
| 6089 | |
| 6090 | - if (nTnodes < 1) |
| 6091 | - return YAFFS_OK; |
| 6092 | + if (tn) { |
| 6093 | + hasData = 0; |
| 6094 | |
| 6095 | - /* Calculate the tnode size in bytes for variable width tnode support. |
| 6096 | - * Must be a multiple of 32-bits */ |
| 6097 | - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; |
| 6098 | + if(level > 0){ |
| 6099 | + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { |
| 6100 | + if (tn->internal[i]) { |
| 6101 | + tn->internal[i] = |
| 6102 | + yaffs_prune_worker(dev, tn->internal[i], |
| 6103 | + level - 1, |
| 6104 | + (i == 0) ? del0 : 1); |
| 6105 | + } |
| 6106 | |
| 6107 | - if (tnodeSize < sizeof(yaffs_Tnode)) |
| 6108 | - tnodeSize = sizeof(yaffs_Tnode); |
| 6109 | + if (tn->internal[i]) |
| 6110 | + hasData++; |
| 6111 | + } |
| 6112 | + } else { |
| 6113 | + int tnode_size_u32 = dev->tnode_size/sizeof(__u32); |
| 6114 | + __u32 *map = (__u32 *)tn; |
| 6115 | |
| 6116 | - /* make these things */ |
| 6117 | + for(i = 0; !hasData && i < tnode_size_u32; i++){ |
| 6118 | + if(map[i]) |
| 6119 | + hasData++; |
| 6120 | + } |
| 6121 | + } |
| 6122 | |
| 6123 | - newTnodes = YMALLOC(nTnodes * tnodeSize); |
| 6124 | - mem = (__u8 *)newTnodes; |
| 6125 | + if (hasData == 0 && del0) { |
| 6126 | + /* Free and return NULL */ |
| 6127 | |
| 6128 | - if (!newTnodes) { |
| 6129 | - T(YAFFS_TRACE_ERROR, |
| 6130 | - (TSTR("yaffs: Could not allocate Tnodes" TENDSTR))); |
| 6131 | - return YAFFS_FAIL; |
| 6132 | - } |
| 6133 | + yaffs_free_tnode(dev, tn); |
| 6134 | + tn = NULL; |
| 6135 | + } |
| 6136 | |
| 6137 | - /* Hook them into the free list */ |
| 6138 | -#if 0 |
| 6139 | - for (i = 0; i < nTnodes - 1; i++) { |
| 6140 | - newTnodes[i].internal[0] = &newTnodes[i + 1]; |
| 6141 | -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG |
| 6142 | - newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; |
| 6143 | -#endif |
| 6144 | } |
| 6145 | |
| 6146 | - newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes; |
| 6147 | -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG |
| 6148 | - newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; |
| 6149 | -#endif |
| 6150 | - dev->freeTnodes = newTnodes; |
| 6151 | -#else |
| 6152 | - /* New hookup for wide tnodes */ |
| 6153 | - for (i = 0; i < nTnodes - 1; i++) { |
| 6154 | - curr = (yaffs_Tnode *) &mem[i * tnodeSize]; |
| 6155 | - next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize]; |
| 6156 | - curr->internal[0] = next; |
| 6157 | - } |
| 6158 | + return tn; |
| 6159 | |
| 6160 | - curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize]; |
| 6161 | - curr->internal[0] = dev->freeTnodes; |
| 6162 | - dev->freeTnodes = (yaffs_Tnode *)mem; |
| 6163 | +} |
| 6164 | |
| 6165 | -#endif |
| 6166 | +static int yaffs_prune_tree(yaffs_dev_t *dev, |
| 6167 | + yaffs_file_s *file_struct) |
| 6168 | +{ |
| 6169 | + int i; |
| 6170 | + int hasData; |
| 6171 | + int done = 0; |
| 6172 | + yaffs_tnode_t *tn; |
| 6173 | |
| 6174 | + if (file_struct->top_level > 0) { |
| 6175 | + file_struct->top = |
| 6176 | + yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0); |
| 6177 | + |
| 6178 | + /* Now we have a tree with all the non-zero branches NULL but the height |
| 6179 | + * is the same as it was. |
| 6180 | + * Let's see if we can trim internal tnodes to shorten the tree. |
| 6181 | + * We can do this if only the 0th element in the tnode is in use |
| 6182 | + * (ie all the non-zero are NULL) |
| 6183 | + */ |
| 6184 | |
| 6185 | - dev->nFreeTnodes += nTnodes; |
| 6186 | - dev->nTnodesCreated += nTnodes; |
| 6187 | + while (file_struct->top_level && !done) { |
| 6188 | + tn = file_struct->top; |
| 6189 | |
| 6190 | - /* Now add this bunch of tnodes to a list for freeing up. |
| 6191 | - * NB If we can't add this to the management list it isn't fatal |
| 6192 | - * but it just means we can't free this bunch of tnodes later. |
| 6193 | - */ |
| 6194 | + hasData = 0; |
| 6195 | + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { |
| 6196 | + if (tn->internal[i]) |
| 6197 | + hasData++; |
| 6198 | + } |
| 6199 | |
| 6200 | - tnl = YMALLOC(sizeof(yaffs_TnodeList)); |
| 6201 | - if (!tnl) { |
| 6202 | - T(YAFFS_TRACE_ERROR, |
| 6203 | - (TSTR |
| 6204 | - ("yaffs: Could not add tnodes to management list" TENDSTR))); |
| 6205 | - return YAFFS_FAIL; |
| 6206 | - } else { |
| 6207 | - tnl->tnodes = newTnodes; |
| 6208 | - tnl->next = dev->allocatedTnodeList; |
| 6209 | - dev->allocatedTnodeList = tnl; |
| 6210 | + if (!hasData) { |
| 6211 | + file_struct->top = tn->internal[0]; |
| 6212 | + file_struct->top_level--; |
| 6213 | + yaffs_free_tnode(dev, tn); |
| 6214 | + } else { |
| 6215 | + done = 1; |
| 6216 | + } |
| 6217 | + } |
| 6218 | } |
| 6219 | |
| 6220 | - T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR))); |
| 6221 | - |
| 6222 | return YAFFS_OK; |
| 6223 | } |
| 6224 | |
| 6225 | -/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */ |
| 6226 | +/*-------------------- End of File Structure functions.-------------------*/ |
| 6227 | + |
| 6228 | |
| 6229 | -static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev) |
| 6230 | +/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */ |
| 6231 | +static yaffs_obj_t *yaffs_alloc_empty_obj(yaffs_dev_t *dev) |
| 6232 | { |
| 6233 | - yaffs_Tnode *tn = NULL; |
| 6234 | + yaffs_obj_t *obj = yaffs_alloc_raw_obj(dev); |
| 6235 | |
| 6236 | - /* If there are none left make more */ |
| 6237 | - if (!dev->freeTnodes) |
| 6238 | - yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES); |
| 6239 | - |
| 6240 | - if (dev->freeTnodes) { |
| 6241 | - tn = dev->freeTnodes; |
| 6242 | -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG |
| 6243 | - if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) { |
| 6244 | - /* Hoosterman, this thing looks like it isn't in the list */ |
| 6245 | - T(YAFFS_TRACE_ALWAYS, |
| 6246 | - (TSTR("yaffs: Tnode list bug 1" TENDSTR))); |
| 6247 | - } |
| 6248 | -#endif |
| 6249 | - dev->freeTnodes = dev->freeTnodes->internal[0]; |
| 6250 | - dev->nFreeTnodes--; |
| 6251 | - } |
| 6252 | + if (obj) { |
| 6253 | + dev->n_obj++; |
| 6254 | |
| 6255 | - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ |
| 6256 | + /* Now sweeten it up... */ |
| 6257 | |
| 6258 | - return tn; |
| 6259 | -} |
| 6260 | + memset(obj, 0, sizeof(yaffs_obj_t)); |
| 6261 | + obj->being_created = 1; |
| 6262 | |
| 6263 | -static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev) |
| 6264 | -{ |
| 6265 | - yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev); |
| 6266 | - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; |
| 6267 | + obj->my_dev = dev; |
| 6268 | + obj->hdr_chunk = 0; |
| 6269 | + obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN; |
| 6270 | + YINIT_LIST_HEAD(&(obj->hard_links)); |
| 6271 | + YINIT_LIST_HEAD(&(obj->hash_link)); |
| 6272 | + YINIT_LIST_HEAD(&obj->siblings); |
| 6273 | |
| 6274 | - if (tnodeSize < sizeof(yaffs_Tnode)) |
| 6275 | - tnodeSize = sizeof(yaffs_Tnode); |
| 6276 | |
| 6277 | - if (tn) |
| 6278 | - memset(tn, 0, tnodeSize); |
| 6279 | + /* Now make the directory sane */ |
| 6280 | + if (dev->root_dir) { |
| 6281 | + obj->parent = dev->root_dir; |
| 6282 | + ylist_add(&(obj->siblings), &dev->root_dir->variant.dir_variant.children); |
| 6283 | + } |
| 6284 | |
| 6285 | - return tn; |
| 6286 | + /* Add it to the lost and found directory. |
| 6287 | + * NB Can't put root or lostNFound in lostNFound so |
| 6288 | + * check if lostNFound exists first |
| 6289 | + */ |
| 6290 | + if (dev->lost_n_found) |
| 6291 | + yaffs_add_obj_to_dir(dev->lost_n_found, obj); |
| 6292 | + |
| 6293 | + obj->being_created = 0; |
| 6294 | + } |
| 6295 | + |
| 6296 | + dev->checkpoint_blocks_required = 0; /* force recalculation*/ |
| 6297 | + |
| 6298 | + return obj; |
| 6299 | } |
| 6300 | |
| 6301 | -/* FreeTnode frees up a tnode and puts it back on the free list */ |
| 6302 | -static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn) |
| 6303 | +static yaffs_obj_t *yaffs_create_fake_dir(yaffs_dev_t *dev, int number, |
| 6304 | + __u32 mode) |
| 6305 | { |
| 6306 | - if (tn) { |
| 6307 | -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG |
| 6308 | - if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) { |
| 6309 | - /* Hoosterman, this thing looks like it is already in the list */ |
| 6310 | - T(YAFFS_TRACE_ALWAYS, |
| 6311 | - (TSTR("yaffs: Tnode list bug 2" TENDSTR))); |
| 6312 | - } |
| 6313 | - tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1; |
| 6314 | -#endif |
| 6315 | - tn->internal[0] = dev->freeTnodes; |
| 6316 | - dev->freeTnodes = tn; |
| 6317 | - dev->nFreeTnodes++; |
| 6318 | + |
| 6319 | + yaffs_obj_t *obj = |
| 6320 | + yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); |
| 6321 | + if (obj) { |
| 6322 | + obj->fake = 1; /* it is fake so it might have no NAND presence... */ |
| 6323 | + obj->rename_allowed = 0; /* ... and we're not allowed to rename it... */ |
| 6324 | + obj->unlink_allowed = 0; /* ... or unlink it */ |
| 6325 | + obj->deleted = 0; |
| 6326 | + obj->unlinked = 0; |
| 6327 | + obj->yst_mode = mode; |
| 6328 | + obj->my_dev = dev; |
| 6329 | + obj->hdr_chunk = 0; /* Not a valid chunk. */ |
| 6330 | + } |
| 6331 | + |
| 6332 | + return obj; |
| 6333 | + |
| 6334 | +} |
| 6335 | + |
| 6336 | +static void yaffs_unhash_obj(yaffs_obj_t *obj) |
| 6337 | +{ |
| 6338 | + int bucket; |
| 6339 | + yaffs_dev_t *dev = obj->my_dev; |
| 6340 | + |
| 6341 | + /* If it is still linked into the bucket list, free from the list */ |
| 6342 | + if (!ylist_empty(&obj->hash_link)) { |
| 6343 | + ylist_del_init(&obj->hash_link); |
| 6344 | + bucket = yaffs_hash_fn(obj->obj_id); |
| 6345 | + dev->obj_bucket[bucket].count--; |
| 6346 | } |
| 6347 | - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ |
| 6348 | } |
| 6349 | |
| 6350 | -static void yaffs_DeinitialiseTnodes(yaffs_Device *dev) |
| 6351 | +/* FreeObject frees up a Object and puts it back on the free list */ |
| 6352 | +static void yaffs_free_obj(yaffs_obj_t *obj) |
| 6353 | { |
| 6354 | - /* Free the list of allocated tnodes */ |
| 6355 | - yaffs_TnodeList *tmp; |
| 6356 | + yaffs_dev_t *dev = obj->my_dev; |
| 6357 | + |
| 6358 | + T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), obj, obj->my_inode)); |
| 6359 | |
| 6360 | - while (dev->allocatedTnodeList) { |
| 6361 | - tmp = dev->allocatedTnodeList->next; |
| 6362 | + if (!obj) |
| 6363 | + YBUG(); |
| 6364 | + if (obj->parent) |
| 6365 | + YBUG(); |
| 6366 | + if (!ylist_empty(&obj->siblings)) |
| 6367 | + YBUG(); |
| 6368 | |
| 6369 | - YFREE(dev->allocatedTnodeList->tnodes); |
| 6370 | - YFREE(dev->allocatedTnodeList); |
| 6371 | - dev->allocatedTnodeList = tmp; |
| 6372 | |
| 6373 | + if (obj->my_inode) { |
| 6374 | + /* We're still hooked up to a cached inode. |
| 6375 | + * Don't delete now, but mark for later deletion |
| 6376 | + */ |
| 6377 | + obj->defered_free = 1; |
| 6378 | + return; |
| 6379 | } |
| 6380 | |
| 6381 | - dev->freeTnodes = NULL; |
| 6382 | - dev->nFreeTnodes = 0; |
| 6383 | -} |
| 6384 | + yaffs_unhash_obj(obj); |
| 6385 | |
| 6386 | -static void yaffs_InitialiseTnodes(yaffs_Device *dev) |
| 6387 | -{ |
| 6388 | - dev->allocatedTnodeList = NULL; |
| 6389 | - dev->freeTnodes = NULL; |
| 6390 | - dev->nFreeTnodes = 0; |
| 6391 | - dev->nTnodesCreated = 0; |
| 6392 | + yaffs_free_raw_obj(dev,obj); |
| 6393 | + dev->n_obj--; |
| 6394 | + dev->checkpoint_blocks_required = 0; /* force recalculation*/ |
| 6395 | } |
| 6396 | |
| 6397 | |
| 6398 | -void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, |
| 6399 | - unsigned val) |
| 6400 | +void yaffs_handle_defered_free(yaffs_obj_t *obj) |
| 6401 | { |
| 6402 | - __u32 *map = (__u32 *)tn; |
| 6403 | - __u32 bitInMap; |
| 6404 | - __u32 bitInWord; |
| 6405 | - __u32 wordInMap; |
| 6406 | - __u32 mask; |
| 6407 | - |
| 6408 | - pos &= YAFFS_TNODES_LEVEL0_MASK; |
| 6409 | - val >>= dev->chunkGroupBits; |
| 6410 | + if (obj->defered_free) |
| 6411 | + yaffs_free_obj(obj); |
| 6412 | +} |
| 6413 | |
| 6414 | - bitInMap = pos * dev->tnodeWidth; |
| 6415 | - wordInMap = bitInMap / 32; |
| 6416 | - bitInWord = bitInMap & (32 - 1); |
| 6417 | +static void yaffs_init_tnodes_and_objs(yaffs_dev_t *dev) |
| 6418 | +{ |
| 6419 | + int i; |
| 6420 | |
| 6421 | - mask = dev->tnodeMask << bitInWord; |
| 6422 | + dev->n_obj = 0; |
| 6423 | + dev->n_tnodes = 0; |
| 6424 | |
| 6425 | - map[wordInMap] &= ~mask; |
| 6426 | - map[wordInMap] |= (mask & (val << bitInWord)); |
| 6427 | + yaffs_init_raw_tnodes_and_objs(dev); |
| 6428 | |
| 6429 | - if (dev->tnodeWidth > (32 - bitInWord)) { |
| 6430 | - bitInWord = (32 - bitInWord); |
| 6431 | - wordInMap++;; |
| 6432 | - mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord); |
| 6433 | - map[wordInMap] &= ~mask; |
| 6434 | - map[wordInMap] |= (mask & (val >> bitInWord)); |
| 6435 | + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { |
| 6436 | + YINIT_LIST_HEAD(&dev->obj_bucket[i].list); |
| 6437 | + dev->obj_bucket[i].count = 0; |
| 6438 | } |
| 6439 | } |
| 6440 | |
| 6441 | -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, |
| 6442 | - unsigned pos) |
| 6443 | +static int yaffs_find_nice_bucket(yaffs_dev_t *dev) |
| 6444 | { |
| 6445 | - __u32 *map = (__u32 *)tn; |
| 6446 | - __u32 bitInMap; |
| 6447 | - __u32 bitInWord; |
| 6448 | - __u32 wordInMap; |
| 6449 | - __u32 val; |
| 6450 | + int i; |
| 6451 | + int l = 999; |
| 6452 | + int lowest = 999999; |
| 6453 | |
| 6454 | - pos &= YAFFS_TNODES_LEVEL0_MASK; |
| 6455 | |
| 6456 | - bitInMap = pos * dev->tnodeWidth; |
| 6457 | - wordInMap = bitInMap / 32; |
| 6458 | - bitInWord = bitInMap & (32 - 1); |
| 6459 | + /* Search for the shortest list or one that |
| 6460 | + * isn't too long. |
| 6461 | + */ |
| 6462 | |
| 6463 | - val = map[wordInMap] >> bitInWord; |
| 6464 | + for (i = 0; i < 10 && lowest > 4; i++) { |
| 6465 | + dev->bucket_finder++; |
| 6466 | + dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS; |
| 6467 | + if (dev->obj_bucket[dev->bucket_finder].count < lowest) { |
| 6468 | + lowest = dev->obj_bucket[dev->bucket_finder].count; |
| 6469 | + l = dev->bucket_finder; |
| 6470 | + } |
| 6471 | |
| 6472 | - if (dev->tnodeWidth > (32 - bitInWord)) { |
| 6473 | - bitInWord = (32 - bitInWord); |
| 6474 | - wordInMap++;; |
| 6475 | - val |= (map[wordInMap] << bitInWord); |
| 6476 | } |
| 6477 | |
| 6478 | - val &= dev->tnodeMask; |
| 6479 | - val <<= dev->chunkGroupBits; |
| 6480 | - |
| 6481 | - return val; |
| 6482 | + return l; |
| 6483 | } |
| 6484 | |
| 6485 | -/* ------------------- End of individual tnode manipulation -----------------*/ |
| 6486 | - |
| 6487 | -/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ |
| 6488 | - * The look up tree is represented by the top tnode and the number of topLevel |
| 6489 | - * in the tree. 0 means only the level 0 tnode is in the tree. |
| 6490 | - */ |
| 6491 | - |
| 6492 | -/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ |
| 6493 | -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, |
| 6494 | - yaffs_FileStructure *fStruct, |
| 6495 | - __u32 chunkId) |
| 6496 | +static int yaffs_new_obj_id(yaffs_dev_t *dev) |
| 6497 | { |
| 6498 | - yaffs_Tnode *tn = fStruct->top; |
| 6499 | - __u32 i; |
| 6500 | - int requiredTallness; |
| 6501 | - int level = fStruct->topLevel; |
| 6502 | - |
| 6503 | - /* Check sane level and chunk Id */ |
| 6504 | - if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) |
| 6505 | - return NULL; |
| 6506 | + int bucket = yaffs_find_nice_bucket(dev); |
| 6507 | |
| 6508 | - if (chunkId > YAFFS_MAX_CHUNK_ID) |
| 6509 | - return NULL; |
| 6510 | + /* Now find an object value that has not already been taken |
| 6511 | + * by scanning the list. |
| 6512 | + */ |
| 6513 | |
| 6514 | - /* First check we're tall enough (ie enough topLevel) */ |
| 6515 | + int found = 0; |
| 6516 | + struct ylist_head *i; |
| 6517 | |
| 6518 | - i = chunkId >> YAFFS_TNODES_LEVEL0_BITS; |
| 6519 | - requiredTallness = 0; |
| 6520 | - while (i) { |
| 6521 | - i >>= YAFFS_TNODES_INTERNAL_BITS; |
| 6522 | - requiredTallness++; |
| 6523 | - } |
| 6524 | + __u32 n = (__u32) bucket; |
| 6525 | |
| 6526 | - if (requiredTallness > fStruct->topLevel) |
| 6527 | - return NULL; /* Not tall enough, so we can't find it */ |
| 6528 | + /* yaffs_check_obj_hash_sane(); */ |
| 6529 | |
| 6530 | - /* Traverse down to level 0 */ |
| 6531 | - while (level > 0 && tn) { |
| 6532 | - tn = tn->internal[(chunkId >> |
| 6533 | - (YAFFS_TNODES_LEVEL0_BITS + |
| 6534 | - (level - 1) * |
| 6535 | - YAFFS_TNODES_INTERNAL_BITS)) & |
| 6536 | - YAFFS_TNODES_INTERNAL_MASK]; |
| 6537 | - level--; |
| 6538 | + while (!found) { |
| 6539 | + found = 1; |
| 6540 | + n += YAFFS_NOBJECT_BUCKETS; |
| 6541 | + if (1 || dev->obj_bucket[bucket].count > 0) { |
| 6542 | + ylist_for_each(i, &dev->obj_bucket[bucket].list) { |
| 6543 | + /* If there is already one in the list */ |
| 6544 | + if (i && ylist_entry(i, yaffs_obj_t, |
| 6545 | + hash_link)->obj_id == n) { |
| 6546 | + found = 0; |
| 6547 | + } |
| 6548 | + } |
| 6549 | + } |
| 6550 | } |
| 6551 | |
| 6552 | - return tn; |
| 6553 | + return n; |
| 6554 | } |
| 6555 | |
| 6556 | -/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree. |
| 6557 | - * This happens in two steps: |
| 6558 | - * 1. If the tree isn't tall enough, then make it taller. |
| 6559 | - * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. |
| 6560 | - * |
| 6561 | - * Used when modifying the tree. |
| 6562 | - * |
| 6563 | - * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will |
| 6564 | - * be plugged into the ttree. |
| 6565 | - */ |
| 6566 | - |
| 6567 | -static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, |
| 6568 | - yaffs_FileStructure *fStruct, |
| 6569 | - __u32 chunkId, |
| 6570 | - yaffs_Tnode *passedTn) |
| 6571 | +static void yaffs_hash_obj(yaffs_obj_t *in) |
| 6572 | { |
| 6573 | - int requiredTallness; |
| 6574 | - int i; |
| 6575 | - int l; |
| 6576 | - yaffs_Tnode *tn; |
| 6577 | - |
| 6578 | - __u32 x; |
| 6579 | + int bucket = yaffs_hash_fn(in->obj_id); |
| 6580 | + yaffs_dev_t *dev = in->my_dev; |
| 6581 | |
| 6582 | + ylist_add(&in->hash_link, &dev->obj_bucket[bucket].list); |
| 6583 | + dev->obj_bucket[bucket].count++; |
| 6584 | +} |
| 6585 | |
| 6586 | - /* Check sane level and page Id */ |
| 6587 | - if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL) |
| 6588 | - return NULL; |
| 6589 | +yaffs_obj_t *yaffs_find_by_number(yaffs_dev_t *dev, __u32 number) |
| 6590 | +{ |
| 6591 | + int bucket = yaffs_hash_fn(number); |
| 6592 | + struct ylist_head *i; |
| 6593 | + yaffs_obj_t *in; |
| 6594 | |
| 6595 | - if (chunkId > YAFFS_MAX_CHUNK_ID) |
| 6596 | - return NULL; |
| 6597 | + ylist_for_each(i, &dev->obj_bucket[bucket].list) { |
| 6598 | + /* Look if it is in the list */ |
| 6599 | + if (i) { |
| 6600 | + in = ylist_entry(i, yaffs_obj_t, hash_link); |
| 6601 | + if (in->obj_id == number) { |
| 6602 | |
| 6603 | - /* First check we're tall enough (ie enough topLevel) */ |
| 6604 | + /* Don't tell the VFS about this one if it is defered free */ |
| 6605 | + if (in->defered_free) |
| 6606 | + return NULL; |
| 6607 | |
| 6608 | - x = chunkId >> YAFFS_TNODES_LEVEL0_BITS; |
| 6609 | - requiredTallness = 0; |
| 6610 | - while (x) { |
| 6611 | - x >>= YAFFS_TNODES_INTERNAL_BITS; |
| 6612 | - requiredTallness++; |
| 6613 | + return in; |
| 6614 | + } |
| 6615 | + } |
| 6616 | } |
| 6617 | |
| 6618 | + return NULL; |
| 6619 | +} |
| 6620 | |
| 6621 | - if (requiredTallness > fStruct->topLevel) { |
| 6622 | - /* Not tall enough, gotta make the tree taller */ |
| 6623 | - for (i = fStruct->topLevel; i < requiredTallness; i++) { |
| 6624 | +yaffs_obj_t *yaffs_new_obj(yaffs_dev_t *dev, int number, |
| 6625 | + yaffs_obj_type type) |
| 6626 | +{ |
| 6627 | + yaffs_obj_t *theObject=NULL; |
| 6628 | + yaffs_tnode_t *tn = NULL; |
| 6629 | |
| 6630 | - tn = yaffs_GetTnode(dev); |
| 6631 | + if (number < 0) |
| 6632 | + number = yaffs_new_obj_id(dev); |
| 6633 | |
| 6634 | - if (tn) { |
| 6635 | - tn->internal[0] = fStruct->top; |
| 6636 | - fStruct->top = tn; |
| 6637 | - } else { |
| 6638 | - T(YAFFS_TRACE_ERROR, |
| 6639 | - (TSTR("yaffs: no more tnodes" TENDSTR))); |
| 6640 | - } |
| 6641 | - } |
| 6642 | + if (type == YAFFS_OBJECT_TYPE_FILE) { |
| 6643 | + tn = yaffs_get_tnode(dev); |
| 6644 | + if (!tn) |
| 6645 | + return NULL; |
| 6646 | + } |
| 6647 | |
| 6648 | - fStruct->topLevel = requiredTallness; |
| 6649 | + theObject = yaffs_alloc_empty_obj(dev); |
| 6650 | + if (!theObject){ |
| 6651 | + if(tn) |
| 6652 | + yaffs_free_tnode(dev,tn); |
| 6653 | + return NULL; |
| 6654 | } |
| 6655 | |
| 6656 | - /* Traverse down to level 0, adding anything we need */ |
| 6657 | |
| 6658 | - l = fStruct->topLevel; |
| 6659 | - tn = fStruct->top; |
| 6660 | + if (theObject) { |
| 6661 | + theObject->fake = 0; |
| 6662 | + theObject->rename_allowed = 1; |
| 6663 | + theObject->unlink_allowed = 1; |
| 6664 | + theObject->obj_id = number; |
| 6665 | + yaffs_hash_obj(theObject); |
| 6666 | + theObject->variant_type = type; |
| 6667 | +#ifdef CONFIG_YAFFS_WINCE |
| 6668 | + yfsd_win_file_time_now(theObject->win_atime); |
| 6669 | + theObject->win_ctime[0] = theObject->win_mtime[0] = |
| 6670 | + theObject->win_atime[0]; |
| 6671 | + theObject->win_ctime[1] = theObject->win_mtime[1] = |
| 6672 | + theObject->win_atime[1]; |
| 6673 | + |
| 6674 | +#else |
| 6675 | |
| 6676 | - if (l > 0) { |
| 6677 | - while (l > 0 && tn) { |
| 6678 | - x = (chunkId >> |
| 6679 | - (YAFFS_TNODES_LEVEL0_BITS + |
| 6680 | - (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & |
| 6681 | - YAFFS_TNODES_INTERNAL_MASK; |
| 6682 | + theObject->yst_atime = theObject->yst_mtime = |
| 6683 | + theObject->yst_ctime = Y_CURRENT_TIME; |
| 6684 | +#endif |
| 6685 | + switch (type) { |
| 6686 | + case YAFFS_OBJECT_TYPE_FILE: |
| 6687 | + theObject->variant.file_variant.file_size = 0; |
| 6688 | + theObject->variant.file_variant.scanned_size = 0; |
| 6689 | + theObject->variant.file_variant.shrink_size = 0xFFFFFFFF; /* max __u32 */ |
| 6690 | + theObject->variant.file_variant.top_level = 0; |
| 6691 | + theObject->variant.file_variant.top = tn; |
| 6692 | + break; |
| 6693 | + case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 6694 | + YINIT_LIST_HEAD(&theObject->variant.dir_variant. |
| 6695 | + children); |
| 6696 | + YINIT_LIST_HEAD(&theObject->variant.dir_variant. |
| 6697 | + dirty); |
| 6698 | + break; |
| 6699 | + case YAFFS_OBJECT_TYPE_SYMLINK: |
| 6700 | + case YAFFS_OBJECT_TYPE_HARDLINK: |
| 6701 | + case YAFFS_OBJECT_TYPE_SPECIAL: |
| 6702 | + /* No action required */ |
| 6703 | + break; |
| 6704 | + case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 6705 | + /* todo this should not happen */ |
| 6706 | + break; |
| 6707 | + } |
| 6708 | + } |
| 6709 | |
| 6710 | + return theObject; |
| 6711 | +} |
| 6712 | |
| 6713 | - if ((l > 1) && !tn->internal[x]) { |
| 6714 | - /* Add missing non-level-zero tnode */ |
| 6715 | - tn->internal[x] = yaffs_GetTnode(dev); |
| 6716 | +yaffs_obj_t *yaffs_find_or_create_by_number(yaffs_dev_t *dev, |
| 6717 | + int number, |
| 6718 | + yaffs_obj_type type) |
| 6719 | +{ |
| 6720 | + yaffs_obj_t *theObject = NULL; |
| 6721 | |
| 6722 | - } else if (l == 1) { |
| 6723 | - /* Looking from level 1 at level 0 */ |
| 6724 | - if (passedTn) { |
| 6725 | - /* If we already have one, then release it.*/ |
| 6726 | - if (tn->internal[x]) |
| 6727 | - yaffs_FreeTnode(dev, tn->internal[x]); |
| 6728 | - tn->internal[x] = passedTn; |
| 6729 | + if (number > 0) |
| 6730 | + theObject = yaffs_find_by_number(dev, number); |
| 6731 | |
| 6732 | - } else if (!tn->internal[x]) { |
| 6733 | - /* Don't have one, none passed in */ |
| 6734 | - tn->internal[x] = yaffs_GetTnode(dev); |
| 6735 | - } |
| 6736 | - } |
| 6737 | + if (!theObject) |
| 6738 | + theObject = yaffs_new_obj(dev, number, type); |
| 6739 | |
| 6740 | - tn = tn->internal[x]; |
| 6741 | - l--; |
| 6742 | - } |
| 6743 | - } else { |
| 6744 | - /* top is level 0 */ |
| 6745 | - if (passedTn) { |
| 6746 | - memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); |
| 6747 | - yaffs_FreeTnode(dev, passedTn); |
| 6748 | - } |
| 6749 | - } |
| 6750 | + return theObject; |
| 6751 | |
| 6752 | - return tn; |
| 6753 | } |
| 6754 | |
| 6755 | -static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, |
| 6756 | - yaffs_ExtendedTags *tags, int objectId, |
| 6757 | - int chunkInInode) |
| 6758 | + |
| 6759 | +YCHAR *yaffs_clone_str(const YCHAR *str) |
| 6760 | { |
| 6761 | - int j; |
| 6762 | + YCHAR *newStr = NULL; |
| 6763 | + int len; |
| 6764 | |
| 6765 | - for (j = 0; theChunk && j < dev->chunkGroupSize; j++) { |
| 6766 | - if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock, |
| 6767 | - theChunk % dev->nChunksPerBlock)) { |
| 6768 | - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, |
| 6769 | - tags); |
| 6770 | - if (yaffs_TagsMatch(tags, objectId, chunkInInode)) { |
| 6771 | - /* found it; */ |
| 6772 | - return theChunk; |
| 6773 | - } |
| 6774 | - } |
| 6775 | - theChunk++; |
| 6776 | + if (!str) |
| 6777 | + str = _Y(""); |
| 6778 | + |
| 6779 | + len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH); |
| 6780 | + newStr = YMALLOC((len + 1) * sizeof(YCHAR)); |
| 6781 | + if (newStr){ |
| 6782 | + yaffs_strncpy(newStr, str,len); |
| 6783 | + newStr[len] = 0; |
| 6784 | } |
| 6785 | - return -1; |
| 6786 | -} |
| 6787 | + return newStr; |
| 6788 | |
| 6789 | +} |
| 6790 | |
| 6791 | -/* DeleteWorker scans backwards through the tnode tree and deletes all the |
| 6792 | - * chunks and tnodes in the file |
| 6793 | - * Returns 1 if the tree was deleted. |
| 6794 | - * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete. |
| 6795 | +/* |
| 6796 | + * Mknod (create) a new object. |
| 6797 | + * equiv_obj only has meaning for a hard link; |
| 6798 | + * aliasString only has meaning for a symlink. |
| 6799 | + * rdev only has meaning for devices (a subset of special objects) |
| 6800 | */ |
| 6801 | |
| 6802 | -static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, |
| 6803 | - int chunkOffset, int *limit) |
| 6804 | +static yaffs_obj_t *yaffs_create_obj(yaffs_obj_type type, |
| 6805 | + yaffs_obj_t *parent, |
| 6806 | + const YCHAR *name, |
| 6807 | + __u32 mode, |
| 6808 | + __u32 uid, |
| 6809 | + __u32 gid, |
| 6810 | + yaffs_obj_t *equiv_obj, |
| 6811 | + const YCHAR *aliasString, __u32 rdev) |
| 6812 | { |
| 6813 | - int i; |
| 6814 | - int chunkInInode; |
| 6815 | - int theChunk; |
| 6816 | - yaffs_ExtendedTags tags; |
| 6817 | - int foundChunk; |
| 6818 | - yaffs_Device *dev = in->myDev; |
| 6819 | - |
| 6820 | - int allDone = 1; |
| 6821 | - |
| 6822 | - if (tn) { |
| 6823 | - if (level > 0) { |
| 6824 | - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; |
| 6825 | - i--) { |
| 6826 | - if (tn->internal[i]) { |
| 6827 | - if (limit && (*limit) < 0) { |
| 6828 | - allDone = 0; |
| 6829 | - } else { |
| 6830 | - allDone = |
| 6831 | - yaffs_DeleteWorker(in, |
| 6832 | - tn-> |
| 6833 | - internal |
| 6834 | - [i], |
| 6835 | - level - |
| 6836 | - 1, |
| 6837 | - (chunkOffset |
| 6838 | - << |
| 6839 | - YAFFS_TNODES_INTERNAL_BITS) |
| 6840 | - + i, |
| 6841 | - limit); |
| 6842 | - } |
| 6843 | - if (allDone) { |
| 6844 | - yaffs_FreeTnode(dev, |
| 6845 | - tn-> |
| 6846 | - internal[i]); |
| 6847 | - tn->internal[i] = NULL; |
| 6848 | - } |
| 6849 | - } |
| 6850 | - } |
| 6851 | - return (allDone) ? 1 : 0; |
| 6852 | - } else if (level == 0) { |
| 6853 | - int hitLimit = 0; |
| 6854 | - |
| 6855 | - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit; |
| 6856 | - i--) { |
| 6857 | - theChunk = yaffs_GetChunkGroupBase(dev, tn, i); |
| 6858 | - if (theChunk) { |
| 6859 | - |
| 6860 | - chunkInInode = (chunkOffset << |
| 6861 | - YAFFS_TNODES_LEVEL0_BITS) + i; |
| 6862 | - |
| 6863 | - foundChunk = |
| 6864 | - yaffs_FindChunkInGroup(dev, |
| 6865 | - theChunk, |
| 6866 | - &tags, |
| 6867 | - in->objectId, |
| 6868 | - chunkInInode); |
| 6869 | - |
| 6870 | - if (foundChunk > 0) { |
| 6871 | - yaffs_DeleteChunk(dev, |
| 6872 | - foundChunk, 1, |
| 6873 | - __LINE__); |
| 6874 | - in->nDataChunks--; |
| 6875 | - if (limit) { |
| 6876 | - *limit = *limit - 1; |
| 6877 | - if (*limit <= 0) |
| 6878 | - hitLimit = 1; |
| 6879 | - } |
| 6880 | - |
| 6881 | - } |
| 6882 | - |
| 6883 | - yaffs_PutLevel0Tnode(dev, tn, i, 0); |
| 6884 | - } |
| 6885 | - |
| 6886 | - } |
| 6887 | - return (i < 0) ? 1 : 0; |
| 6888 | - |
| 6889 | - } |
| 6890 | - |
| 6891 | - } |
| 6892 | - |
| 6893 | - return 1; |
| 6894 | - |
| 6895 | -} |
| 6896 | - |
| 6897 | -static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk) |
| 6898 | -{ |
| 6899 | - yaffs_BlockInfo *theBlock; |
| 6900 | - |
| 6901 | - T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk)); |
| 6902 | - |
| 6903 | - theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock); |
| 6904 | - if (theBlock) { |
| 6905 | - theBlock->softDeletions++; |
| 6906 | - dev->nFreeChunks++; |
| 6907 | - } |
| 6908 | -} |
| 6909 | - |
| 6910 | -/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file. |
| 6911 | - * All soft deleting does is increment the block's softdelete count and pulls the chunk out |
| 6912 | - * of the tnode. |
| 6913 | - * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted. |
| 6914 | - */ |
| 6915 | - |
| 6916 | -static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, |
| 6917 | - __u32 level, int chunkOffset) |
| 6918 | -{ |
| 6919 | - int i; |
| 6920 | - int theChunk; |
| 6921 | - int allDone = 1; |
| 6922 | - yaffs_Device *dev = in->myDev; |
| 6923 | - |
| 6924 | - if (tn) { |
| 6925 | - if (level > 0) { |
| 6926 | - |
| 6927 | - for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; |
| 6928 | - i--) { |
| 6929 | - if (tn->internal[i]) { |
| 6930 | - allDone = |
| 6931 | - yaffs_SoftDeleteWorker(in, |
| 6932 | - tn-> |
| 6933 | - internal[i], |
| 6934 | - level - 1, |
| 6935 | - (chunkOffset |
| 6936 | - << |
| 6937 | - YAFFS_TNODES_INTERNAL_BITS) |
| 6938 | - + i); |
| 6939 | - if (allDone) { |
| 6940 | - yaffs_FreeTnode(dev, |
| 6941 | - tn-> |
| 6942 | - internal[i]); |
| 6943 | - tn->internal[i] = NULL; |
| 6944 | - } else { |
| 6945 | - /* Hoosterman... how could this happen? */ |
| 6946 | - } |
| 6947 | - } |
| 6948 | - } |
| 6949 | - return (allDone) ? 1 : 0; |
| 6950 | - } else if (level == 0) { |
| 6951 | - |
| 6952 | - for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { |
| 6953 | - theChunk = yaffs_GetChunkGroupBase(dev, tn, i); |
| 6954 | - if (theChunk) { |
| 6955 | - /* Note this does not find the real chunk, only the chunk group. |
| 6956 | - * We make an assumption that a chunk group is not larger than |
| 6957 | - * a block. |
| 6958 | - */ |
| 6959 | - yaffs_SoftDeleteChunk(dev, theChunk); |
| 6960 | - yaffs_PutLevel0Tnode(dev, tn, i, 0); |
| 6961 | - } |
| 6962 | - |
| 6963 | - } |
| 6964 | - return 1; |
| 6965 | - |
| 6966 | - } |
| 6967 | - |
| 6968 | - } |
| 6969 | - |
| 6970 | - return 1; |
| 6971 | - |
| 6972 | -} |
| 6973 | - |
| 6974 | -static void yaffs_SoftDeleteFile(yaffs_Object *obj) |
| 6975 | -{ |
| 6976 | - if (obj->deleted && |
| 6977 | - obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) { |
| 6978 | - if (obj->nDataChunks <= 0) { |
| 6979 | - /* Empty file with no duplicate object headers, just delete it immediately */ |
| 6980 | - yaffs_FreeTnode(obj->myDev, |
| 6981 | - obj->variant.fileVariant.top); |
| 6982 | - obj->variant.fileVariant.top = NULL; |
| 6983 | - T(YAFFS_TRACE_TRACING, |
| 6984 | - (TSTR("yaffs: Deleting empty file %d" TENDSTR), |
| 6985 | - obj->objectId)); |
| 6986 | - yaffs_DoGenericObjectDeletion(obj); |
| 6987 | - } else { |
| 6988 | - yaffs_SoftDeleteWorker(obj, |
| 6989 | - obj->variant.fileVariant.top, |
| 6990 | - obj->variant.fileVariant. |
| 6991 | - topLevel, 0); |
| 6992 | - obj->softDeleted = 1; |
| 6993 | - } |
| 6994 | - } |
| 6995 | -} |
| 6996 | - |
| 6997 | -/* Pruning removes any part of the file structure tree that is beyond the |
| 6998 | - * bounds of the file (ie that does not point to chunks). |
| 6999 | - * |
| 7000 | - * A file should only get pruned when its size is reduced. |
| 7001 | - * |
| 7002 | - * Before pruning, the chunks must be pulled from the tree and the |
| 7003 | - * level 0 tnode entries must be zeroed out. |
| 7004 | - * Could also use this for file deletion, but that's probably better handled |
| 7005 | - * by a special case. |
| 7006 | - */ |
| 7007 | - |
| 7008 | -static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, |
| 7009 | - __u32 level, int del0) |
| 7010 | -{ |
| 7011 | - int i; |
| 7012 | - int hasData; |
| 7013 | - |
| 7014 | - if (tn) { |
| 7015 | - hasData = 0; |
| 7016 | - |
| 7017 | - for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { |
| 7018 | - if (tn->internal[i] && level > 0) { |
| 7019 | - tn->internal[i] = |
| 7020 | - yaffs_PruneWorker(dev, tn->internal[i], |
| 7021 | - level - 1, |
| 7022 | - (i == 0) ? del0 : 1); |
| 7023 | - } |
| 7024 | - |
| 7025 | - if (tn->internal[i]) |
| 7026 | - hasData++; |
| 7027 | - } |
| 7028 | - |
| 7029 | - if (hasData == 0 && del0) { |
| 7030 | - /* Free and return NULL */ |
| 7031 | - |
| 7032 | - yaffs_FreeTnode(dev, tn); |
| 7033 | - tn = NULL; |
| 7034 | - } |
| 7035 | - |
| 7036 | - } |
| 7037 | - |
| 7038 | - return tn; |
| 7039 | - |
| 7040 | -} |
| 7041 | - |
| 7042 | -static int yaffs_PruneFileStructure(yaffs_Device *dev, |
| 7043 | - yaffs_FileStructure *fStruct) |
| 7044 | -{ |
| 7045 | - int i; |
| 7046 | - int hasData; |
| 7047 | - int done = 0; |
| 7048 | - yaffs_Tnode *tn; |
| 7049 | - |
| 7050 | - if (fStruct->topLevel > 0) { |
| 7051 | - fStruct->top = |
| 7052 | - yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0); |
| 7053 | - |
| 7054 | - /* Now we have a tree with all the non-zero branches NULL but the height |
| 7055 | - * is the same as it was. |
| 7056 | - * Let's see if we can trim internal tnodes to shorten the tree. |
| 7057 | - * We can do this if only the 0th element in the tnode is in use |
| 7058 | - * (ie all the non-zero are NULL) |
| 7059 | - */ |
| 7060 | - |
| 7061 | - while (fStruct->topLevel && !done) { |
| 7062 | - tn = fStruct->top; |
| 7063 | - |
| 7064 | - hasData = 0; |
| 7065 | - for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { |
| 7066 | - if (tn->internal[i]) |
| 7067 | - hasData++; |
| 7068 | - } |
| 7069 | - |
| 7070 | - if (!hasData) { |
| 7071 | - fStruct->top = tn->internal[0]; |
| 7072 | - fStruct->topLevel--; |
| 7073 | - yaffs_FreeTnode(dev, tn); |
| 7074 | - } else { |
| 7075 | - done = 1; |
| 7076 | - } |
| 7077 | - } |
| 7078 | - } |
| 7079 | - |
| 7080 | - return YAFFS_OK; |
| 7081 | -} |
| 7082 | - |
| 7083 | -/*-------------------- End of File Structure functions.-------------------*/ |
| 7084 | - |
| 7085 | -/* yaffs_CreateFreeObjects creates a bunch more objects and |
| 7086 | - * adds them to the object free list. |
| 7087 | - */ |
| 7088 | -static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects) |
| 7089 | -{ |
| 7090 | - int i; |
| 7091 | - yaffs_Object *newObjects; |
| 7092 | - yaffs_ObjectList *list; |
| 7093 | - |
| 7094 | - if (nObjects < 1) |
| 7095 | - return YAFFS_OK; |
| 7096 | - |
| 7097 | - /* make these things */ |
| 7098 | - newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); |
| 7099 | - list = YMALLOC(sizeof(yaffs_ObjectList)); |
| 7100 | - |
| 7101 | - if (!newObjects || !list) { |
| 7102 | - if (newObjects) |
| 7103 | - YFREE(newObjects); |
| 7104 | - if (list) |
| 7105 | - YFREE(list); |
| 7106 | - T(YAFFS_TRACE_ALLOCATE, |
| 7107 | - (TSTR("yaffs: Could not allocate more objects" TENDSTR))); |
| 7108 | - return YAFFS_FAIL; |
| 7109 | - } |
| 7110 | - |
| 7111 | - /* Hook them into the free list */ |
| 7112 | - for (i = 0; i < nObjects - 1; i++) { |
| 7113 | - newObjects[i].siblings.next = |
| 7114 | - (struct ylist_head *)(&newObjects[i + 1]); |
| 7115 | - } |
| 7116 | - |
| 7117 | - newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects; |
| 7118 | - dev->freeObjects = newObjects; |
| 7119 | - dev->nFreeObjects += nObjects; |
| 7120 | - dev->nObjectsCreated += nObjects; |
| 7121 | - |
| 7122 | - /* Now add this bunch of Objects to a list for freeing up. */ |
| 7123 | - |
| 7124 | - list->objects = newObjects; |
| 7125 | - list->next = dev->allocatedObjectList; |
| 7126 | - dev->allocatedObjectList = list; |
| 7127 | - |
| 7128 | - return YAFFS_OK; |
| 7129 | -} |
| 7130 | - |
| 7131 | - |
| 7132 | -/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */ |
| 7133 | -static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev) |
| 7134 | -{ |
| 7135 | - yaffs_Object *tn = NULL; |
| 7136 | - |
| 7137 | -#ifdef VALGRIND_TEST |
| 7138 | - tn = YMALLOC(sizeof(yaffs_Object)); |
| 7139 | -#else |
| 7140 | - /* If there are none left make more */ |
| 7141 | - if (!dev->freeObjects) |
| 7142 | - yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS); |
| 7143 | - |
| 7144 | - if (dev->freeObjects) { |
| 7145 | - tn = dev->freeObjects; |
| 7146 | - dev->freeObjects = |
| 7147 | - (yaffs_Object *) (dev->freeObjects->siblings.next); |
| 7148 | - dev->nFreeObjects--; |
| 7149 | - } |
| 7150 | -#endif |
| 7151 | - if (tn) { |
| 7152 | - /* Now sweeten it up... */ |
| 7153 | - |
| 7154 | - memset(tn, 0, sizeof(yaffs_Object)); |
| 7155 | - tn->beingCreated = 1; |
| 7156 | - |
| 7157 | - tn->myDev = dev; |
| 7158 | - tn->hdrChunk = 0; |
| 7159 | - tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN; |
| 7160 | - YINIT_LIST_HEAD(&(tn->hardLinks)); |
| 7161 | - YINIT_LIST_HEAD(&(tn->hashLink)); |
| 7162 | - YINIT_LIST_HEAD(&tn->siblings); |
| 7163 | - |
| 7164 | - |
| 7165 | - /* Now make the directory sane */ |
| 7166 | - if (dev->rootDir) { |
| 7167 | - tn->parent = dev->rootDir; |
| 7168 | - ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children); |
| 7169 | - } |
| 7170 | - |
| 7171 | - /* Add it to the lost and found directory. |
| 7172 | - * NB Can't put root or lostNFound in lostNFound so |
| 7173 | - * check if lostNFound exists first |
| 7174 | - */ |
| 7175 | - if (dev->lostNFoundDir) |
| 7176 | - yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn); |
| 7177 | - |
| 7178 | - tn->beingCreated = 0; |
| 7179 | - } |
| 7180 | - |
| 7181 | - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ |
| 7182 | - |
| 7183 | - return tn; |
| 7184 | -} |
| 7185 | - |
| 7186 | -static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number, |
| 7187 | - __u32 mode) |
| 7188 | -{ |
| 7189 | - |
| 7190 | - yaffs_Object *obj = |
| 7191 | - yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); |
| 7192 | - if (obj) { |
| 7193 | - obj->fake = 1; /* it is fake so it might have no NAND presence... */ |
| 7194 | - obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */ |
| 7195 | - obj->unlinkAllowed = 0; /* ... or unlink it */ |
| 7196 | - obj->deleted = 0; |
| 7197 | - obj->unlinked = 0; |
| 7198 | - obj->yst_mode = mode; |
| 7199 | - obj->myDev = dev; |
| 7200 | - obj->hdrChunk = 0; /* Not a valid chunk. */ |
| 7201 | - } |
| 7202 | - |
| 7203 | - return obj; |
| 7204 | - |
| 7205 | -} |
| 7206 | - |
| 7207 | -static void yaffs_UnhashObject(yaffs_Object *tn) |
| 7208 | -{ |
| 7209 | - int bucket; |
| 7210 | - yaffs_Device *dev = tn->myDev; |
| 7211 | - |
| 7212 | - /* If it is still linked into the bucket list, free from the list */ |
| 7213 | - if (!ylist_empty(&tn->hashLink)) { |
| 7214 | - ylist_del_init(&tn->hashLink); |
| 7215 | - bucket = yaffs_HashFunction(tn->objectId); |
| 7216 | - dev->objectBucket[bucket].count--; |
| 7217 | - } |
| 7218 | -} |
| 7219 | - |
| 7220 | -/* FreeObject frees up a Object and puts it back on the free list */ |
| 7221 | -static void yaffs_FreeObject(yaffs_Object *tn) |
| 7222 | -{ |
| 7223 | - yaffs_Device *dev = tn->myDev; |
| 7224 | - |
| 7225 | -#ifdef __KERNEL__ |
| 7226 | - T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode)); |
| 7227 | -#endif |
| 7228 | - |
| 7229 | - if (tn->parent) |
| 7230 | - YBUG(); |
| 7231 | - if (!ylist_empty(&tn->siblings)) |
| 7232 | - YBUG(); |
| 7233 | - |
| 7234 | - |
| 7235 | -#ifdef __KERNEL__ |
| 7236 | - if (tn->myInode) { |
| 7237 | - /* We're still hooked up to a cached inode. |
| 7238 | - * Don't delete now, but mark for later deletion |
| 7239 | - */ |
| 7240 | - tn->deferedFree = 1; |
| 7241 | - return; |
| 7242 | - } |
| 7243 | -#endif |
| 7244 | - |
| 7245 | - yaffs_UnhashObject(tn); |
| 7246 | - |
| 7247 | -#ifdef VALGRIND_TEST |
| 7248 | - YFREE(tn); |
| 7249 | -#else |
| 7250 | - /* Link into the free list. */ |
| 7251 | - tn->siblings.next = (struct ylist_head *)(dev->freeObjects); |
| 7252 | - dev->freeObjects = tn; |
| 7253 | - dev->nFreeObjects++; |
| 7254 | -#endif |
| 7255 | - dev->nCheckpointBlocksRequired = 0; /* force recalculation*/ |
| 7256 | -} |
| 7257 | - |
| 7258 | -#ifdef __KERNEL__ |
| 7259 | - |
| 7260 | -void yaffs_HandleDeferedFree(yaffs_Object *obj) |
| 7261 | -{ |
| 7262 | - if (obj->deferedFree) |
| 7263 | - yaffs_FreeObject(obj); |
| 7264 | -} |
| 7265 | - |
| 7266 | -#endif |
| 7267 | - |
| 7268 | -static void yaffs_DeinitialiseObjects(yaffs_Device *dev) |
| 7269 | -{ |
| 7270 | - /* Free the list of allocated Objects */ |
| 7271 | - |
| 7272 | - yaffs_ObjectList *tmp; |
| 7273 | - |
| 7274 | - while (dev->allocatedObjectList) { |
| 7275 | - tmp = dev->allocatedObjectList->next; |
| 7276 | - YFREE(dev->allocatedObjectList->objects); |
| 7277 | - YFREE(dev->allocatedObjectList); |
| 7278 | - |
| 7279 | - dev->allocatedObjectList = tmp; |
| 7280 | - } |
| 7281 | - |
| 7282 | - dev->freeObjects = NULL; |
| 7283 | - dev->nFreeObjects = 0; |
| 7284 | -} |
| 7285 | - |
| 7286 | -static void yaffs_InitialiseObjects(yaffs_Device *dev) |
| 7287 | -{ |
| 7288 | - int i; |
| 7289 | - |
| 7290 | - dev->allocatedObjectList = NULL; |
| 7291 | - dev->freeObjects = NULL; |
| 7292 | - dev->nFreeObjects = 0; |
| 7293 | - |
| 7294 | - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { |
| 7295 | - YINIT_LIST_HEAD(&dev->objectBucket[i].list); |
| 7296 | - dev->objectBucket[i].count = 0; |
| 7297 | - } |
| 7298 | -} |
| 7299 | - |
| 7300 | -static int yaffs_FindNiceObjectBucket(yaffs_Device *dev) |
| 7301 | -{ |
| 7302 | - static int x; |
| 7303 | - int i; |
| 7304 | - int l = 999; |
| 7305 | - int lowest = 999999; |
| 7306 | - |
| 7307 | - /* First let's see if we can find one that's empty. */ |
| 7308 | - |
| 7309 | - for (i = 0; i < 10 && lowest > 0; i++) { |
| 7310 | - x++; |
| 7311 | - x %= YAFFS_NOBJECT_BUCKETS; |
| 7312 | - if (dev->objectBucket[x].count < lowest) { |
| 7313 | - lowest = dev->objectBucket[x].count; |
| 7314 | - l = x; |
| 7315 | - } |
| 7316 | - |
| 7317 | - } |
| 7318 | - |
| 7319 | - /* If we didn't find an empty list, then try |
| 7320 | - * looking a bit further for a short one |
| 7321 | - */ |
| 7322 | - |
| 7323 | - for (i = 0; i < 10 && lowest > 3; i++) { |
| 7324 | - x++; |
| 7325 | - x %= YAFFS_NOBJECT_BUCKETS; |
| 7326 | - if (dev->objectBucket[x].count < lowest) { |
| 7327 | - lowest = dev->objectBucket[x].count; |
| 7328 | - l = x; |
| 7329 | - } |
| 7330 | - |
| 7331 | - } |
| 7332 | - |
| 7333 | - return l; |
| 7334 | -} |
| 7335 | - |
| 7336 | -static int yaffs_CreateNewObjectNumber(yaffs_Device *dev) |
| 7337 | -{ |
| 7338 | - int bucket = yaffs_FindNiceObjectBucket(dev); |
| 7339 | - |
| 7340 | - /* Now find an object value that has not already been taken |
| 7341 | - * by scanning the list. |
| 7342 | - */ |
| 7343 | - |
| 7344 | - int found = 0; |
| 7345 | - struct ylist_head *i; |
| 7346 | - |
| 7347 | - __u32 n = (__u32) bucket; |
| 7348 | - |
| 7349 | - /* yaffs_CheckObjectHashSanity(); */ |
| 7350 | - |
| 7351 | - while (!found) { |
| 7352 | - found = 1; |
| 7353 | - n += YAFFS_NOBJECT_BUCKETS; |
| 7354 | - if (1 || dev->objectBucket[bucket].count > 0) { |
| 7355 | - ylist_for_each(i, &dev->objectBucket[bucket].list) { |
| 7356 | - /* If there is already one in the list */ |
| 7357 | - if (i && ylist_entry(i, yaffs_Object, |
| 7358 | - hashLink)->objectId == n) { |
| 7359 | - found = 0; |
| 7360 | - } |
| 7361 | - } |
| 7362 | - } |
| 7363 | - } |
| 7364 | - |
| 7365 | - return n; |
| 7366 | -} |
| 7367 | - |
| 7368 | -static void yaffs_HashObject(yaffs_Object *in) |
| 7369 | -{ |
| 7370 | - int bucket = yaffs_HashFunction(in->objectId); |
| 7371 | - yaffs_Device *dev = in->myDev; |
| 7372 | - |
| 7373 | - ylist_add(&in->hashLink, &dev->objectBucket[bucket].list); |
| 7374 | - dev->objectBucket[bucket].count++; |
| 7375 | -} |
| 7376 | - |
| 7377 | -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number) |
| 7378 | -{ |
| 7379 | - int bucket = yaffs_HashFunction(number); |
| 7380 | - struct ylist_head *i; |
| 7381 | - yaffs_Object *in; |
| 7382 | - |
| 7383 | - ylist_for_each(i, &dev->objectBucket[bucket].list) { |
| 7384 | - /* Look if it is in the list */ |
| 7385 | - if (i) { |
| 7386 | - in = ylist_entry(i, yaffs_Object, hashLink); |
| 7387 | - if (in->objectId == number) { |
| 7388 | -#ifdef __KERNEL__ |
| 7389 | - /* Don't tell the VFS about this one if it is defered free */ |
| 7390 | - if (in->deferedFree) |
| 7391 | - return NULL; |
| 7392 | -#endif |
| 7393 | - |
| 7394 | - return in; |
| 7395 | - } |
| 7396 | - } |
| 7397 | - } |
| 7398 | - |
| 7399 | - return NULL; |
| 7400 | -} |
| 7401 | - |
| 7402 | -yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number, |
| 7403 | - yaffs_ObjectType type) |
| 7404 | -{ |
| 7405 | - yaffs_Object *theObject; |
| 7406 | - yaffs_Tnode *tn = NULL; |
| 7407 | - |
| 7408 | - if (number < 0) |
| 7409 | - number = yaffs_CreateNewObjectNumber(dev); |
| 7410 | - |
| 7411 | - theObject = yaffs_AllocateEmptyObject(dev); |
| 7412 | - if (!theObject) |
| 7413 | - return NULL; |
| 7414 | - |
| 7415 | - if (type == YAFFS_OBJECT_TYPE_FILE) { |
| 7416 | - tn = yaffs_GetTnode(dev); |
| 7417 | - if (!tn) { |
| 7418 | - yaffs_FreeObject(theObject); |
| 7419 | - return NULL; |
| 7420 | - } |
| 7421 | - } |
| 7422 | - |
| 7423 | - if (theObject) { |
| 7424 | - theObject->fake = 0; |
| 7425 | - theObject->renameAllowed = 1; |
| 7426 | - theObject->unlinkAllowed = 1; |
| 7427 | - theObject->objectId = number; |
| 7428 | - yaffs_HashObject(theObject); |
| 7429 | - theObject->variantType = type; |
| 7430 | -#ifdef CONFIG_YAFFS_WINCE |
| 7431 | - yfsd_WinFileTimeNow(theObject->win_atime); |
| 7432 | - theObject->win_ctime[0] = theObject->win_mtime[0] = |
| 7433 | - theObject->win_atime[0]; |
| 7434 | - theObject->win_ctime[1] = theObject->win_mtime[1] = |
| 7435 | - theObject->win_atime[1]; |
| 7436 | - |
| 7437 | -#else |
| 7438 | - |
| 7439 | - theObject->yst_atime = theObject->yst_mtime = |
| 7440 | - theObject->yst_ctime = Y_CURRENT_TIME; |
| 7441 | -#endif |
| 7442 | - switch (type) { |
| 7443 | - case YAFFS_OBJECT_TYPE_FILE: |
| 7444 | - theObject->variant.fileVariant.fileSize = 0; |
| 7445 | - theObject->variant.fileVariant.scannedFileSize = 0; |
| 7446 | - theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */ |
| 7447 | - theObject->variant.fileVariant.topLevel = 0; |
| 7448 | - theObject->variant.fileVariant.top = tn; |
| 7449 | - break; |
| 7450 | - case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 7451 | - YINIT_LIST_HEAD(&theObject->variant.directoryVariant. |
| 7452 | - children); |
| 7453 | - break; |
| 7454 | - case YAFFS_OBJECT_TYPE_SYMLINK: |
| 7455 | - case YAFFS_OBJECT_TYPE_HARDLINK: |
| 7456 | - case YAFFS_OBJECT_TYPE_SPECIAL: |
| 7457 | - /* No action required */ |
| 7458 | - break; |
| 7459 | - case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 7460 | - /* todo this should not happen */ |
| 7461 | - break; |
| 7462 | - } |
| 7463 | - } |
| 7464 | - |
| 7465 | - return theObject; |
| 7466 | -} |
| 7467 | - |
| 7468 | -static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, |
| 7469 | - int number, |
| 7470 | - yaffs_ObjectType type) |
| 7471 | -{ |
| 7472 | - yaffs_Object *theObject = NULL; |
| 7473 | - |
| 7474 | - if (number > 0) |
| 7475 | - theObject = yaffs_FindObjectByNumber(dev, number); |
| 7476 | - |
| 7477 | - if (!theObject) |
| 7478 | - theObject = yaffs_CreateNewObject(dev, number, type); |
| 7479 | - |
| 7480 | - return theObject; |
| 7481 | - |
| 7482 | -} |
| 7483 | - |
| 7484 | - |
| 7485 | -static YCHAR *yaffs_CloneString(const YCHAR *str) |
| 7486 | -{ |
| 7487 | - YCHAR *newStr = NULL; |
| 7488 | - |
| 7489 | - if (str && *str) { |
| 7490 | - newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); |
| 7491 | - if (newStr) |
| 7492 | - yaffs_strcpy(newStr, str); |
| 7493 | - } |
| 7494 | - |
| 7495 | - return newStr; |
| 7496 | - |
| 7497 | -} |
| 7498 | - |
| 7499 | -/* |
| 7500 | - * Mknod (create) a new object. |
| 7501 | - * equivalentObject only has meaning for a hard link; |
| 7502 | - * aliasString only has meaning for a sumlink. |
| 7503 | - * rdev only has meaning for devices (a subset of special objects) |
| 7504 | - */ |
| 7505 | - |
| 7506 | -static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, |
| 7507 | - yaffs_Object *parent, |
| 7508 | - const YCHAR *name, |
| 7509 | - __u32 mode, |
| 7510 | - __u32 uid, |
| 7511 | - __u32 gid, |
| 7512 | - yaffs_Object *equivalentObject, |
| 7513 | - const YCHAR *aliasString, __u32 rdev) |
| 7514 | -{ |
| 7515 | - yaffs_Object *in; |
| 7516 | - YCHAR *str = NULL; |
| 7517 | - |
| 7518 | - yaffs_Device *dev = parent->myDev; |
| 7519 | - |
| 7520 | - /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/ |
| 7521 | - if (yaffs_FindObjectByName(parent, name)) |
| 7522 | - return NULL; |
| 7523 | - |
| 7524 | - in = yaffs_CreateNewObject(dev, -1, type); |
| 7525 | - |
| 7526 | - if (!in) |
| 7527 | - return YAFFS_FAIL; |
| 7528 | - |
| 7529 | - if (type == YAFFS_OBJECT_TYPE_SYMLINK) { |
| 7530 | - str = yaffs_CloneString(aliasString); |
| 7531 | - if (!str) { |
| 7532 | - yaffs_FreeObject(in); |
| 7533 | - return NULL; |
| 7534 | - } |
| 7535 | - } |
| 7536 | - |
| 7537 | - |
| 7538 | - |
| 7539 | - if (in) { |
| 7540 | - in->hdrChunk = 0; |
| 7541 | - in->valid = 1; |
| 7542 | - in->variantType = type; |
| 7543 | - |
| 7544 | - in->yst_mode = mode; |
| 7545 | - |
| 7546 | -#ifdef CONFIG_YAFFS_WINCE |
| 7547 | - yfsd_WinFileTimeNow(in->win_atime); |
| 7548 | - in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0]; |
| 7549 | - in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1]; |
| 7550 | - |
| 7551 | -#else |
| 7552 | - in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME; |
| 7553 | - |
| 7554 | - in->yst_rdev = rdev; |
| 7555 | - in->yst_uid = uid; |
| 7556 | - in->yst_gid = gid; |
| 7557 | -#endif |
| 7558 | - in->nDataChunks = 0; |
| 7559 | - |
| 7560 | - yaffs_SetObjectName(in, name); |
| 7561 | - in->dirty = 1; |
| 7562 | - |
| 7563 | - yaffs_AddObjectToDirectory(parent, in); |
| 7564 | - |
| 7565 | - in->myDev = parent->myDev; |
| 7566 | - |
| 7567 | - switch (type) { |
| 7568 | - case YAFFS_OBJECT_TYPE_SYMLINK: |
| 7569 | - in->variant.symLinkVariant.alias = str; |
| 7570 | - break; |
| 7571 | - case YAFFS_OBJECT_TYPE_HARDLINK: |
| 7572 | - in->variant.hardLinkVariant.equivalentObject = |
| 7573 | - equivalentObject; |
| 7574 | - in->variant.hardLinkVariant.equivalentObjectId = |
| 7575 | - equivalentObject->objectId; |
| 7576 | - ylist_add(&in->hardLinks, &equivalentObject->hardLinks); |
| 7577 | - break; |
| 7578 | - case YAFFS_OBJECT_TYPE_FILE: |
| 7579 | - case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 7580 | - case YAFFS_OBJECT_TYPE_SPECIAL: |
| 7581 | - case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 7582 | - /* do nothing */ |
| 7583 | - break; |
| 7584 | - } |
| 7585 | - |
| 7586 | - if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) { |
| 7587 | - /* Could not create the object header, fail the creation */ |
| 7588 | - yaffs_DeleteObject(in); |
| 7589 | - in = NULL; |
| 7590 | - } |
| 7591 | - |
| 7592 | - } |
| 7593 | - |
| 7594 | - return in; |
| 7595 | -} |
| 7596 | - |
| 7597 | -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name, |
| 7598 | - __u32 mode, __u32 uid, __u32 gid) |
| 7599 | -{ |
| 7600 | - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, |
| 7601 | - uid, gid, NULL, NULL, 0); |
| 7602 | -} |
| 7603 | - |
| 7604 | -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name, |
| 7605 | - __u32 mode, __u32 uid, __u32 gid) |
| 7606 | -{ |
| 7607 | - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, |
| 7608 | - mode, uid, gid, NULL, NULL, 0); |
| 7609 | -} |
| 7610 | - |
| 7611 | -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name, |
| 7612 | - __u32 mode, __u32 uid, __u32 gid, __u32 rdev) |
| 7613 | -{ |
| 7614 | - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, |
| 7615 | - uid, gid, NULL, NULL, rdev); |
| 7616 | -} |
| 7617 | - |
| 7618 | -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name, |
| 7619 | - __u32 mode, __u32 uid, __u32 gid, |
| 7620 | - const YCHAR *alias) |
| 7621 | -{ |
| 7622 | - return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, |
| 7623 | - uid, gid, NULL, alias, 0); |
| 7624 | -} |
| 7625 | - |
| 7626 | -/* yaffs_Link returns the object id of the equivalent object.*/ |
| 7627 | -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, |
| 7628 | - yaffs_Object *equivalentObject) |
| 7629 | -{ |
| 7630 | - /* Get the real object in case we were fed a hard link as an equivalent object */ |
| 7631 | - equivalentObject = yaffs_GetEquivalentObject(equivalentObject); |
| 7632 | - |
| 7633 | - if (yaffs_MknodObject |
| 7634 | - (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0, |
| 7635 | - equivalentObject, NULL, 0)) { |
| 7636 | - return equivalentObject; |
| 7637 | - } else { |
| 7638 | - return NULL; |
| 7639 | - } |
| 7640 | - |
| 7641 | -} |
| 7642 | - |
| 7643 | -static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, |
| 7644 | - const YCHAR *newName, int force, int shadows) |
| 7645 | -{ |
| 7646 | - int unlinkOp; |
| 7647 | - int deleteOp; |
| 7648 | - |
| 7649 | - yaffs_Object *existingTarget; |
| 7650 | - |
| 7651 | - if (newDir == NULL) |
| 7652 | - newDir = obj->parent; /* use the old directory */ |
| 7653 | - |
| 7654 | - if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 7655 | - T(YAFFS_TRACE_ALWAYS, |
| 7656 | - (TSTR |
| 7657 | - ("tragedy: yaffs_ChangeObjectName: newDir is not a directory" |
| 7658 | - TENDSTR))); |
| 7659 | - YBUG(); |
| 7660 | - } |
| 7661 | - |
| 7662 | - /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ |
| 7663 | - if (obj->myDev->isYaffs2) |
| 7664 | - unlinkOp = (newDir == obj->myDev->unlinkedDir); |
| 7665 | - else |
| 7666 | - unlinkOp = (newDir == obj->myDev->unlinkedDir |
| 7667 | - && obj->variantType == YAFFS_OBJECT_TYPE_FILE); |
| 7668 | - |
| 7669 | - deleteOp = (newDir == obj->myDev->deletedDir); |
| 7670 | - |
| 7671 | - existingTarget = yaffs_FindObjectByName(newDir, newName); |
| 7672 | - |
| 7673 | - /* If the object is a file going into the unlinked directory, |
| 7674 | - * then it is OK to just stuff it in since duplicate names are allowed. |
| 7675 | - * else only proceed if the new name does not exist and if we're putting |
| 7676 | - * it into a directory. |
| 7677 | - */ |
| 7678 | - if ((unlinkOp || |
| 7679 | - deleteOp || |
| 7680 | - force || |
| 7681 | - (shadows > 0) || |
| 7682 | - !existingTarget) && |
| 7683 | - newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 7684 | - yaffs_SetObjectName(obj, newName); |
| 7685 | - obj->dirty = 1; |
| 7686 | - |
| 7687 | - yaffs_AddObjectToDirectory(newDir, obj); |
| 7688 | - |
| 7689 | - if (unlinkOp) |
| 7690 | - obj->unlinked = 1; |
| 7691 | - |
| 7692 | - /* If it is a deletion then we mark it as a shrink for gc purposes. */ |
| 7693 | - if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0) |
| 7694 | - return YAFFS_OK; |
| 7695 | - } |
| 7696 | - |
| 7697 | - return YAFFS_FAIL; |
| 7698 | -} |
| 7699 | - |
| 7700 | -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, |
| 7701 | - yaffs_Object *newDir, const YCHAR *newName) |
| 7702 | -{ |
| 7703 | - yaffs_Object *obj = NULL; |
| 7704 | - yaffs_Object *existingTarget = NULL; |
| 7705 | - int force = 0; |
| 7706 | - |
| 7707 | - |
| 7708 | - if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) |
| 7709 | - YBUG(); |
| 7710 | - if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) |
| 7711 | - YBUG(); |
| 7712 | - |
| 7713 | -#ifdef CONFIG_YAFFS_CASE_INSENSITIVE |
| 7714 | - /* Special case for case insemsitive systems (eg. WinCE). |
| 7715 | - * While look-up is case insensitive, the name isn't. |
| 7716 | - * Therefore we might want to change x.txt to X.txt |
| 7717 | - */ |
| 7718 | - if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0) |
| 7719 | - force = 1; |
| 7720 | -#endif |
| 7721 | - |
| 7722 | - else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) |
| 7723 | - /* ENAMETOOLONG */ |
| 7724 | - return YAFFS_FAIL; |
| 7725 | - |
| 7726 | - obj = yaffs_FindObjectByName(oldDir, oldName); |
| 7727 | - |
| 7728 | - if (obj && obj->renameAllowed) { |
| 7729 | - |
| 7730 | - /* Now do the handling for an existing target, if there is one */ |
| 7731 | - |
| 7732 | - existingTarget = yaffs_FindObjectByName(newDir, newName); |
| 7733 | - if (existingTarget && |
| 7734 | - existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && |
| 7735 | - !ylist_empty(&existingTarget->variant.directoryVariant.children)) { |
| 7736 | - /* There is a target that is a non-empty directory, so we fail */ |
| 7737 | - return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */ |
| 7738 | - } else if (existingTarget && existingTarget != obj) { |
| 7739 | - /* Nuke the target first, using shadowing, |
| 7740 | - * but only if it isn't the same object |
| 7741 | - */ |
| 7742 | - yaffs_ChangeObjectName(obj, newDir, newName, force, |
| 7743 | - existingTarget->objectId); |
| 7744 | - yaffs_UnlinkObject(existingTarget); |
| 7745 | - } |
| 7746 | - |
| 7747 | - return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0); |
| 7748 | - } |
| 7749 | - return YAFFS_FAIL; |
| 7750 | -} |
| 7751 | - |
| 7752 | -/*------------------------- Block Management and Page Allocation ----------------*/ |
| 7753 | - |
| 7754 | -static int yaffs_InitialiseBlocks(yaffs_Device *dev) |
| 7755 | -{ |
| 7756 | - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; |
| 7757 | - |
| 7758 | - dev->blockInfo = NULL; |
| 7759 | - dev->chunkBits = NULL; |
| 7760 | - |
| 7761 | - dev->allocationBlock = -1; /* force it to get a new one */ |
| 7762 | - |
| 7763 | - /* If the first allocation strategy fails, thry the alternate one */ |
| 7764 | - dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo)); |
| 7765 | - if (!dev->blockInfo) { |
| 7766 | - dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo)); |
| 7767 | - dev->blockInfoAlt = 1; |
| 7768 | - } else |
| 7769 | - dev->blockInfoAlt = 0; |
| 7770 | - |
| 7771 | - if (dev->blockInfo) { |
| 7772 | - /* Set up dynamic blockinfo stuff. */ |
| 7773 | - dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ |
| 7774 | - dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); |
| 7775 | - if (!dev->chunkBits) { |
| 7776 | - dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); |
| 7777 | - dev->chunkBitsAlt = 1; |
| 7778 | - } else |
| 7779 | - dev->chunkBitsAlt = 0; |
| 7780 | - } |
| 7781 | - |
| 7782 | - if (dev->blockInfo && dev->chunkBits) { |
| 7783 | - memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo)); |
| 7784 | - memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks); |
| 7785 | - return YAFFS_OK; |
| 7786 | - } |
| 7787 | - |
| 7788 | - return YAFFS_FAIL; |
| 7789 | -} |
| 7790 | - |
| 7791 | -static void yaffs_DeinitialiseBlocks(yaffs_Device *dev) |
| 7792 | -{ |
| 7793 | - if (dev->blockInfoAlt && dev->blockInfo) |
| 7794 | - YFREE_ALT(dev->blockInfo); |
| 7795 | - else if (dev->blockInfo) |
| 7796 | - YFREE(dev->blockInfo); |
| 7797 | - |
| 7798 | - dev->blockInfoAlt = 0; |
| 7799 | - |
| 7800 | - dev->blockInfo = NULL; |
| 7801 | - |
| 7802 | - if (dev->chunkBitsAlt && dev->chunkBits) |
| 7803 | - YFREE_ALT(dev->chunkBits); |
| 7804 | - else if (dev->chunkBits) |
| 7805 | - YFREE(dev->chunkBits); |
| 7806 | - dev->chunkBitsAlt = 0; |
| 7807 | - dev->chunkBits = NULL; |
| 7808 | -} |
| 7809 | - |
| 7810 | -static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev, |
| 7811 | - yaffs_BlockInfo *bi) |
| 7812 | -{ |
| 7813 | - int i; |
| 7814 | - __u32 seq; |
| 7815 | - yaffs_BlockInfo *b; |
| 7816 | - |
| 7817 | - if (!dev->isYaffs2) |
| 7818 | - return 1; /* disqualification only applies to yaffs2. */ |
| 7819 | - |
| 7820 | - if (!bi->hasShrinkHeader) |
| 7821 | - return 1; /* can gc */ |
| 7822 | - |
| 7823 | - /* Find the oldest dirty sequence number if we don't know it and save it |
| 7824 | - * so we don't have to keep recomputing it. |
| 7825 | - */ |
| 7826 | - if (!dev->oldestDirtySequence) { |
| 7827 | - seq = dev->sequenceNumber; |
| 7828 | - |
| 7829 | - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; |
| 7830 | - i++) { |
| 7831 | - b = yaffs_GetBlockInfo(dev, i); |
| 7832 | - if (b->blockState == YAFFS_BLOCK_STATE_FULL && |
| 7833 | - (b->pagesInUse - b->softDeletions) < |
| 7834 | - dev->nChunksPerBlock && b->sequenceNumber < seq) { |
| 7835 | - seq = b->sequenceNumber; |
| 7836 | - } |
| 7837 | - } |
| 7838 | - dev->oldestDirtySequence = seq; |
| 7839 | - } |
| 7840 | - |
| 7841 | - /* Can't do gc of this block if there are any blocks older than this one that have |
| 7842 | - * discarded pages. |
| 7843 | - */ |
| 7844 | - return (bi->sequenceNumber <= dev->oldestDirtySequence); |
| 7845 | -} |
| 7846 | - |
| 7847 | -/* FindDiretiestBlock is used to select the dirtiest block (or close enough) |
| 7848 | - * for garbage collection. |
| 7849 | - */ |
| 7850 | - |
| 7851 | -static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev, |
| 7852 | - int aggressive) |
| 7853 | -{ |
| 7854 | - int b = dev->currentDirtyChecker; |
| 7855 | - |
| 7856 | - int i; |
| 7857 | - int iterations; |
| 7858 | - int dirtiest = -1; |
| 7859 | - int pagesInUse = 0; |
| 7860 | - int prioritised = 0; |
| 7861 | - yaffs_BlockInfo *bi; |
| 7862 | - int pendingPrioritisedExist = 0; |
| 7863 | - |
| 7864 | - /* First let's see if we need to grab a prioritised block */ |
| 7865 | - if (dev->hasPendingPrioritisedGCs) { |
| 7866 | - for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) { |
| 7867 | - |
| 7868 | - bi = yaffs_GetBlockInfo(dev, i); |
| 7869 | - /* yaffs_VerifyBlock(dev,bi,i); */ |
| 7870 | - |
| 7871 | - if (bi->gcPrioritise) { |
| 7872 | - pendingPrioritisedExist = 1; |
| 7873 | - if (bi->blockState == YAFFS_BLOCK_STATE_FULL && |
| 7874 | - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { |
| 7875 | - pagesInUse = (bi->pagesInUse - bi->softDeletions); |
| 7876 | - dirtiest = i; |
| 7877 | - prioritised = 1; |
| 7878 | - aggressive = 1; /* Fool the non-aggressive skip logiv below */ |
| 7879 | - } |
| 7880 | - } |
| 7881 | - } |
| 7882 | - |
| 7883 | - if (!pendingPrioritisedExist) /* None found, so we can clear this */ |
| 7884 | - dev->hasPendingPrioritisedGCs = 0; |
| 7885 | - } |
| 7886 | - |
| 7887 | - /* If we're doing aggressive GC then we are happy to take a less-dirty block, and |
| 7888 | - * search harder. |
| 7889 | - * else (we're doing a leasurely gc), then we only bother to do this if the |
| 7890 | - * block has only a few pages in use. |
| 7891 | - */ |
| 7892 | - |
| 7893 | - dev->nonAggressiveSkip--; |
| 7894 | - |
| 7895 | - if (!aggressive && (dev->nonAggressiveSkip > 0)) |
| 7896 | - return -1; |
| 7897 | - |
| 7898 | - if (!prioritised) |
| 7899 | - pagesInUse = |
| 7900 | - (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1; |
| 7901 | - |
| 7902 | - if (aggressive) |
| 7903 | - iterations = |
| 7904 | - dev->internalEndBlock - dev->internalStartBlock + 1; |
| 7905 | - else { |
| 7906 | - iterations = |
| 7907 | - dev->internalEndBlock - dev->internalStartBlock + 1; |
| 7908 | - iterations = iterations / 16; |
| 7909 | - if (iterations > 200) |
| 7910 | - iterations = 200; |
| 7911 | - } |
| 7912 | - |
| 7913 | - for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) { |
| 7914 | - b++; |
| 7915 | - if (b < dev->internalStartBlock || b > dev->internalEndBlock) |
| 7916 | - b = dev->internalStartBlock; |
| 7917 | - |
| 7918 | - if (b < dev->internalStartBlock || b > dev->internalEndBlock) { |
| 7919 | - T(YAFFS_TRACE_ERROR, |
| 7920 | - (TSTR("**>> Block %d is not valid" TENDSTR), b)); |
| 7921 | - YBUG(); |
| 7922 | - } |
| 7923 | - |
| 7924 | - bi = yaffs_GetBlockInfo(dev, b); |
| 7925 | - |
| 7926 | - if (bi->blockState == YAFFS_BLOCK_STATE_FULL && |
| 7927 | - (bi->pagesInUse - bi->softDeletions) < pagesInUse && |
| 7928 | - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { |
| 7929 | - dirtiest = b; |
| 7930 | - pagesInUse = (bi->pagesInUse - bi->softDeletions); |
| 7931 | - } |
| 7932 | - } |
| 7933 | - |
| 7934 | - dev->currentDirtyChecker = b; |
| 7935 | - |
| 7936 | - if (dirtiest > 0) { |
| 7937 | - T(YAFFS_TRACE_GC, |
| 7938 | - (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest, |
| 7939 | - dev->nChunksPerBlock - pagesInUse, prioritised)); |
| 7940 | - } |
| 7941 | - |
| 7942 | - dev->oldestDirtySequence = 0; |
| 7943 | - |
| 7944 | - if (dirtiest > 0) |
| 7945 | - dev->nonAggressiveSkip = 4; |
| 7946 | - |
| 7947 | - return dirtiest; |
| 7948 | -} |
| 7949 | - |
| 7950 | -static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo) |
| 7951 | -{ |
| 7952 | - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo); |
| 7953 | - |
| 7954 | - int erasedOk = 0; |
| 7955 | - |
| 7956 | - /* If the block is still healthy erase it and mark as clean. |
| 7957 | - * If the block has had a data failure, then retire it. |
| 7958 | - */ |
| 7959 | - |
| 7960 | - T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, |
| 7961 | - (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR), |
| 7962 | - blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); |
| 7963 | - |
| 7964 | - bi->blockState = YAFFS_BLOCK_STATE_DIRTY; |
| 7965 | - |
| 7966 | - if (!bi->needsRetiring) { |
| 7967 | - yaffs_InvalidateCheckpoint(dev); |
| 7968 | - erasedOk = yaffs_EraseBlockInNAND(dev, blockNo); |
| 7969 | - if (!erasedOk) { |
| 7970 | - dev->nErasureFailures++; |
| 7971 | - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, |
| 7972 | - (TSTR("**>> Erasure failed %d" TENDSTR), blockNo)); |
| 7973 | - } |
| 7974 | - } |
| 7975 | - |
| 7976 | - if (erasedOk && |
| 7977 | - ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) { |
| 7978 | - int i; |
| 7979 | - for (i = 0; i < dev->nChunksPerBlock; i++) { |
| 7980 | - if (!yaffs_CheckChunkErased |
| 7981 | - (dev, blockNo * dev->nChunksPerBlock + i)) { |
| 7982 | - T(YAFFS_TRACE_ERROR, |
| 7983 | - (TSTR |
| 7984 | - (">>Block %d erasure supposedly OK, but chunk %d not erased" |
| 7985 | - TENDSTR), blockNo, i)); |
| 7986 | - } |
| 7987 | - } |
| 7988 | - } |
| 7989 | - |
| 7990 | - if (erasedOk) { |
| 7991 | - /* Clean it up... */ |
| 7992 | - bi->blockState = YAFFS_BLOCK_STATE_EMPTY; |
| 7993 | - dev->nErasedBlocks++; |
| 7994 | - bi->pagesInUse = 0; |
| 7995 | - bi->softDeletions = 0; |
| 7996 | - bi->hasShrinkHeader = 0; |
| 7997 | - bi->skipErasedCheck = 1; /* This is clean, so no need to check */ |
| 7998 | - bi->gcPrioritise = 0; |
| 7999 | - yaffs_ClearChunkBits(dev, blockNo); |
| 8000 | - |
| 8001 | - T(YAFFS_TRACE_ERASE, |
| 8002 | - (TSTR("Erased block %d" TENDSTR), blockNo)); |
| 8003 | - } else { |
| 8004 | - dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */ |
| 8005 | - |
| 8006 | - yaffs_RetireBlock(dev, blockNo); |
| 8007 | - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, |
| 8008 | - (TSTR("**>> Block %d retired" TENDSTR), blockNo)); |
| 8009 | - } |
| 8010 | -} |
| 8011 | - |
| 8012 | -static int yaffs_FindBlockForAllocation(yaffs_Device *dev) |
| 8013 | -{ |
| 8014 | - int i; |
| 8015 | - |
| 8016 | - yaffs_BlockInfo *bi; |
| 8017 | - |
| 8018 | - if (dev->nErasedBlocks < 1) { |
| 8019 | - /* Hoosterman we've got a problem. |
| 8020 | - * Can't get space to gc |
| 8021 | - */ |
| 8022 | - T(YAFFS_TRACE_ERROR, |
| 8023 | - (TSTR("yaffs tragedy: no more erased blocks" TENDSTR))); |
| 8024 | - |
| 8025 | - return -1; |
| 8026 | - } |
| 8027 | - |
| 8028 | - /* Find an empty block. */ |
| 8029 | - |
| 8030 | - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { |
| 8031 | - dev->allocationBlockFinder++; |
| 8032 | - if (dev->allocationBlockFinder < dev->internalStartBlock |
| 8033 | - || dev->allocationBlockFinder > dev->internalEndBlock) { |
| 8034 | - dev->allocationBlockFinder = dev->internalStartBlock; |
| 8035 | - } |
| 8036 | - |
| 8037 | - bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder); |
| 8038 | - |
| 8039 | - if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { |
| 8040 | - bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING; |
| 8041 | - dev->sequenceNumber++; |
| 8042 | - bi->sequenceNumber = dev->sequenceNumber; |
| 8043 | - dev->nErasedBlocks--; |
| 8044 | - T(YAFFS_TRACE_ALLOCATE, |
| 8045 | - (TSTR("Allocated block %d, seq %d, %d left" TENDSTR), |
| 8046 | - dev->allocationBlockFinder, dev->sequenceNumber, |
| 8047 | - dev->nErasedBlocks)); |
| 8048 | - return dev->allocationBlockFinder; |
| 8049 | - } |
| 8050 | - } |
| 8051 | - |
| 8052 | - T(YAFFS_TRACE_ALWAYS, |
| 8053 | - (TSTR |
| 8054 | - ("yaffs tragedy: no more erased blocks, but there should have been %d" |
| 8055 | - TENDSTR), dev->nErasedBlocks)); |
| 8056 | - |
| 8057 | - return -1; |
| 8058 | -} |
| 8059 | - |
| 8060 | - |
| 8061 | - |
| 8062 | -static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev) |
| 8063 | -{ |
| 8064 | - if (!dev->nCheckpointBlocksRequired && |
| 8065 | - dev->isYaffs2) { |
| 8066 | - /* Not a valid value so recalculate */ |
| 8067 | - int nBytes = 0; |
| 8068 | - int nBlocks; |
| 8069 | - int devBlocks = (dev->endBlock - dev->startBlock + 1); |
| 8070 | - int tnodeSize; |
| 8071 | - |
| 8072 | - tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; |
| 8073 | - |
| 8074 | - if (tnodeSize < sizeof(yaffs_Tnode)) |
| 8075 | - tnodeSize = sizeof(yaffs_Tnode); |
| 8076 | - |
| 8077 | - nBytes += sizeof(yaffs_CheckpointValidity); |
| 8078 | - nBytes += sizeof(yaffs_CheckpointDevice); |
| 8079 | - nBytes += devBlocks * sizeof(yaffs_BlockInfo); |
| 8080 | - nBytes += devBlocks * dev->chunkBitmapStride; |
| 8081 | - nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects); |
| 8082 | - nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes); |
| 8083 | - nBytes += sizeof(yaffs_CheckpointValidity); |
| 8084 | - nBytes += sizeof(__u32); /* checksum*/ |
| 8085 | - |
| 8086 | - /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */ |
| 8087 | - |
| 8088 | - nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3; |
| 8089 | - |
| 8090 | - dev->nCheckpointBlocksRequired = nBlocks; |
| 8091 | - } |
| 8092 | - |
| 8093 | - return dev->nCheckpointBlocksRequired; |
| 8094 | -} |
| 8095 | - |
| 8096 | -/* |
| 8097 | - * Check if there's space to allocate... |
| 8098 | - * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()? |
| 8099 | - */ |
| 8100 | -static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev) |
| 8101 | -{ |
| 8102 | - int reservedChunks; |
| 8103 | - int reservedBlocks = dev->nReservedBlocks; |
| 8104 | - int checkpointBlocks; |
| 8105 | - |
| 8106 | - if (dev->isYaffs2) { |
| 8107 | - checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - |
| 8108 | - dev->blocksInCheckpoint; |
| 8109 | - if (checkpointBlocks < 0) |
| 8110 | - checkpointBlocks = 0; |
| 8111 | - } else { |
| 8112 | - checkpointBlocks = 0; |
| 8113 | - } |
| 8114 | - |
| 8115 | - reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); |
| 8116 | - |
| 8117 | - return (dev->nFreeChunks > reservedChunks); |
| 8118 | -} |
| 8119 | - |
| 8120 | -static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, |
| 8121 | - yaffs_BlockInfo **blockUsedPtr) |
| 8122 | -{ |
| 8123 | - int retVal; |
| 8124 | - yaffs_BlockInfo *bi; |
| 8125 | - |
| 8126 | - if (dev->allocationBlock < 0) { |
| 8127 | - /* Get next block to allocate off */ |
| 8128 | - dev->allocationBlock = yaffs_FindBlockForAllocation(dev); |
| 8129 | - dev->allocationPage = 0; |
| 8130 | - } |
| 8131 | - |
| 8132 | - if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) { |
| 8133 | - /* Not enough space to allocate unless we're allowed to use the reserve. */ |
| 8134 | - return -1; |
| 8135 | - } |
| 8136 | - |
| 8137 | - if (dev->nErasedBlocks < dev->nReservedBlocks |
| 8138 | - && dev->allocationPage == 0) { |
| 8139 | - T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR))); |
| 8140 | - } |
| 8141 | - |
| 8142 | - /* Next page please.... */ |
| 8143 | - if (dev->allocationBlock >= 0) { |
| 8144 | - bi = yaffs_GetBlockInfo(dev, dev->allocationBlock); |
| 8145 | - |
| 8146 | - retVal = (dev->allocationBlock * dev->nChunksPerBlock) + |
| 8147 | - dev->allocationPage; |
| 8148 | - bi->pagesInUse++; |
| 8149 | - yaffs_SetChunkBit(dev, dev->allocationBlock, |
| 8150 | - dev->allocationPage); |
| 8151 | - |
| 8152 | - dev->allocationPage++; |
| 8153 | - |
| 8154 | - dev->nFreeChunks--; |
| 8155 | - |
| 8156 | - /* If the block is full set the state to full */ |
| 8157 | - if (dev->allocationPage >= dev->nChunksPerBlock) { |
| 8158 | - bi->blockState = YAFFS_BLOCK_STATE_FULL; |
| 8159 | - dev->allocationBlock = -1; |
| 8160 | - } |
| 8161 | - |
| 8162 | - if (blockUsedPtr) |
| 8163 | - *blockUsedPtr = bi; |
| 8164 | - |
| 8165 | - return retVal; |
| 8166 | - } |
| 8167 | - |
| 8168 | - T(YAFFS_TRACE_ERROR, |
| 8169 | - (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); |
| 8170 | - |
| 8171 | - return -1; |
| 8172 | -} |
| 8173 | - |
| 8174 | -static int yaffs_GetErasedChunks(yaffs_Device *dev) |
| 8175 | -{ |
| 8176 | - int n; |
| 8177 | - |
| 8178 | - n = dev->nErasedBlocks * dev->nChunksPerBlock; |
| 8179 | - |
| 8180 | - if (dev->allocationBlock > 0) |
| 8181 | - n += (dev->nChunksPerBlock - dev->allocationPage); |
| 8182 | - |
| 8183 | - return n; |
| 8184 | - |
| 8185 | -} |
| 8186 | - |
| 8187 | -static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, |
| 8188 | - int wholeBlock) |
| 8189 | -{ |
| 8190 | - int oldChunk; |
| 8191 | - int newChunk; |
| 8192 | - int markNAND; |
| 8193 | - int retVal = YAFFS_OK; |
| 8194 | - int cleanups = 0; |
| 8195 | - int i; |
| 8196 | - int isCheckpointBlock; |
| 8197 | - int matchingChunk; |
| 8198 | - int maxCopies; |
| 8199 | - |
| 8200 | - int chunksBefore = yaffs_GetErasedChunks(dev); |
| 8201 | - int chunksAfter; |
| 8202 | - |
| 8203 | - yaffs_ExtendedTags tags; |
| 8204 | - |
| 8205 | - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block); |
| 8206 | - |
| 8207 | - yaffs_Object *object; |
| 8208 | - |
| 8209 | - isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT); |
| 8210 | - |
| 8211 | - bi->blockState = YAFFS_BLOCK_STATE_COLLECTING; |
| 8212 | - |
| 8213 | - T(YAFFS_TRACE_TRACING, |
| 8214 | - (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR), |
| 8215 | - block, |
| 8216 | - bi->pagesInUse, |
| 8217 | - bi->hasShrinkHeader, |
| 8218 | - wholeBlock)); |
| 8219 | - |
| 8220 | - /*yaffs_VerifyFreeChunks(dev); */ |
| 8221 | - |
| 8222 | - bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */ |
| 8223 | - |
| 8224 | - /* Take off the number of soft deleted entries because |
| 8225 | - * they're going to get really deleted during GC. |
| 8226 | - */ |
| 8227 | - dev->nFreeChunks -= bi->softDeletions; |
| 8228 | - |
| 8229 | - dev->isDoingGC = 1; |
| 8230 | - |
| 8231 | - if (isCheckpointBlock || |
| 8232 | - !yaffs_StillSomeChunkBits(dev, block)) { |
| 8233 | - T(YAFFS_TRACE_TRACING, |
| 8234 | - (TSTR |
| 8235 | - ("Collecting block %d that has no chunks in use" TENDSTR), |
| 8236 | - block)); |
| 8237 | - yaffs_BlockBecameDirty(dev, block); |
| 8238 | - } else { |
| 8239 | - |
| 8240 | - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); |
| 8241 | - |
| 8242 | - yaffs_VerifyBlock(dev, bi, block); |
| 8243 | - |
| 8244 | - maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10; |
| 8245 | - oldChunk = block * dev->nChunksPerBlock + dev->gcChunk; |
| 8246 | - |
| 8247 | - for (/* init already done */; |
| 8248 | - retVal == YAFFS_OK && |
| 8249 | - dev->gcChunk < dev->nChunksPerBlock && |
| 8250 | - (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) && |
| 8251 | - maxCopies > 0; |
| 8252 | - dev->gcChunk++, oldChunk++) { |
| 8253 | - if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) { |
| 8254 | - |
| 8255 | - /* This page is in use and might need to be copied off */ |
| 8256 | - |
| 8257 | - maxCopies--; |
| 8258 | - |
| 8259 | - markNAND = 1; |
| 8260 | - |
| 8261 | - yaffs_InitialiseTags(&tags); |
| 8262 | - |
| 8263 | - yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk, |
| 8264 | - buffer, &tags); |
| 8265 | - |
| 8266 | - object = |
| 8267 | - yaffs_FindObjectByNumber(dev, |
| 8268 | - tags.objectId); |
| 8269 | - |
| 8270 | - T(YAFFS_TRACE_GC_DETAIL, |
| 8271 | - (TSTR |
| 8272 | - ("Collecting chunk in block %d, %d %d %d " TENDSTR), |
| 8273 | - dev->gcChunk, tags.objectId, tags.chunkId, |
| 8274 | - tags.byteCount)); |
| 8275 | - |
| 8276 | - if (object && !yaffs_SkipVerification(dev)) { |
| 8277 | - if (tags.chunkId == 0) |
| 8278 | - matchingChunk = object->hdrChunk; |
| 8279 | - else if (object->softDeleted) |
| 8280 | - matchingChunk = oldChunk; /* Defeat the test */ |
| 8281 | - else |
| 8282 | - matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL); |
| 8283 | - |
| 8284 | - if (oldChunk != matchingChunk) |
| 8285 | - T(YAFFS_TRACE_ERROR, |
| 8286 | - (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR), |
| 8287 | - oldChunk, matchingChunk, tags.objectId, tags.chunkId)); |
| 8288 | - |
| 8289 | - } |
| 8290 | - |
| 8291 | - if (!object) { |
| 8292 | - T(YAFFS_TRACE_ERROR, |
| 8293 | - (TSTR |
| 8294 | - ("page %d in gc has no object: %d %d %d " |
| 8295 | - TENDSTR), oldChunk, |
| 8296 | - tags.objectId, tags.chunkId, tags.byteCount)); |
| 8297 | - } |
| 8298 | - |
| 8299 | - if (object && |
| 8300 | - object->deleted && |
| 8301 | - object->softDeleted && |
| 8302 | - tags.chunkId != 0) { |
| 8303 | - /* Data chunk in a soft deleted file, throw it away |
| 8304 | - * It's a soft deleted data chunk, |
| 8305 | - * No need to copy this, just forget about it and |
| 8306 | - * fix up the object. |
| 8307 | - */ |
| 8308 | - |
| 8309 | - object->nDataChunks--; |
| 8310 | - |
| 8311 | - if (object->nDataChunks <= 0) { |
| 8312 | - /* remeber to clean up the object */ |
| 8313 | - dev->gcCleanupList[cleanups] = |
| 8314 | - tags.objectId; |
| 8315 | - cleanups++; |
| 8316 | - } |
| 8317 | - markNAND = 0; |
| 8318 | - } else if (0) { |
| 8319 | - /* Todo object && object->deleted && object->nDataChunks == 0 */ |
| 8320 | - /* Deleted object header with no data chunks. |
| 8321 | - * Can be discarded and the file deleted. |
| 8322 | - */ |
| 8323 | - object->hdrChunk = 0; |
| 8324 | - yaffs_FreeTnode(object->myDev, |
| 8325 | - object->variant. |
| 8326 | - fileVariant.top); |
| 8327 | - object->variant.fileVariant.top = NULL; |
| 8328 | - yaffs_DoGenericObjectDeletion(object); |
| 8329 | - |
| 8330 | - } else if (object) { |
| 8331 | - /* It's either a data chunk in a live file or |
| 8332 | - * an ObjectHeader, so we're interested in it. |
| 8333 | - * NB Need to keep the ObjectHeaders of deleted files |
| 8334 | - * until the whole file has been deleted off |
| 8335 | - */ |
| 8336 | - tags.serialNumber++; |
| 8337 | - |
| 8338 | - dev->nGCCopies++; |
| 8339 | - |
| 8340 | - if (tags.chunkId == 0) { |
| 8341 | - /* It is an object Id, |
| 8342 | - * We need to nuke the shrinkheader flags first |
| 8343 | - * We no longer want the shrinkHeader flag since its work is done |
| 8344 | - * and if it is left in place it will mess up scanning. |
| 8345 | - */ |
| 8346 | - |
| 8347 | - yaffs_ObjectHeader *oh; |
| 8348 | - oh = (yaffs_ObjectHeader *)buffer; |
| 8349 | - oh->isShrink = 0; |
| 8350 | - tags.extraIsShrinkHeader = 0; |
| 8351 | - |
| 8352 | - yaffs_VerifyObjectHeader(object, oh, &tags, 1); |
| 8353 | - } |
| 8354 | - |
| 8355 | - newChunk = |
| 8356 | - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1); |
| 8357 | - |
| 8358 | - if (newChunk < 0) { |
| 8359 | - retVal = YAFFS_FAIL; |
| 8360 | - } else { |
| 8361 | - |
| 8362 | - /* Ok, now fix up the Tnodes etc. */ |
| 8363 | - |
| 8364 | - if (tags.chunkId == 0) { |
| 8365 | - /* It's a header */ |
| 8366 | - object->hdrChunk = newChunk; |
| 8367 | - object->serial = tags.serialNumber; |
| 8368 | - } else { |
| 8369 | - /* It's a data chunk */ |
| 8370 | - yaffs_PutChunkIntoFile |
| 8371 | - (object, |
| 8372 | - tags.chunkId, |
| 8373 | - newChunk, 0); |
| 8374 | - } |
| 8375 | - } |
| 8376 | - } |
| 8377 | - |
| 8378 | - if (retVal == YAFFS_OK) |
| 8379 | - yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__); |
| 8380 | - |
| 8381 | - } |
| 8382 | - } |
| 8383 | - |
| 8384 | - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); |
| 8385 | - |
| 8386 | - |
| 8387 | - /* Do any required cleanups */ |
| 8388 | - for (i = 0; i < cleanups; i++) { |
| 8389 | - /* Time to delete the file too */ |
| 8390 | - object = |
| 8391 | - yaffs_FindObjectByNumber(dev, |
| 8392 | - dev->gcCleanupList[i]); |
| 8393 | - if (object) { |
| 8394 | - yaffs_FreeTnode(dev, |
| 8395 | - object->variant.fileVariant. |
| 8396 | - top); |
| 8397 | - object->variant.fileVariant.top = NULL; |
| 8398 | - T(YAFFS_TRACE_GC, |
| 8399 | - (TSTR |
| 8400 | - ("yaffs: About to finally delete object %d" |
| 8401 | - TENDSTR), object->objectId)); |
| 8402 | - yaffs_DoGenericObjectDeletion(object); |
| 8403 | - object->myDev->nDeletedFiles--; |
| 8404 | - } |
| 8405 | - |
| 8406 | - } |
| 8407 | - |
| 8408 | - } |
| 8409 | - |
| 8410 | - yaffs_VerifyCollectedBlock(dev, bi, block); |
| 8411 | - |
| 8412 | - chunksAfter = yaffs_GetErasedChunks(dev); |
| 8413 | - if (chunksBefore >= chunksAfter) { |
| 8414 | - T(YAFFS_TRACE_GC, |
| 8415 | - (TSTR |
| 8416 | - ("gc did not increase free chunks before %d after %d" |
| 8417 | - TENDSTR), chunksBefore, chunksAfter)); |
| 8418 | - } |
| 8419 | - |
| 8420 | - /* If the gc completed then clear the current gcBlock so that we find another. */ |
| 8421 | - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) { |
| 8422 | - dev->gcBlock = -1; |
| 8423 | - dev->gcChunk = 0; |
| 8424 | - } |
| 8425 | - |
| 8426 | - dev->isDoingGC = 0; |
| 8427 | - |
| 8428 | - return retVal; |
| 8429 | -} |
| 8430 | - |
| 8431 | -/* New garbage collector |
| 8432 | - * If we're very low on erased blocks then we do aggressive garbage collection |
| 8433 | - * otherwise we do "leasurely" garbage collection. |
| 8434 | - * Aggressive gc looks further (whole array) and will accept less dirty blocks. |
| 8435 | - * Passive gc only inspects smaller areas and will only accept more dirty blocks. |
| 8436 | - * |
| 8437 | - * The idea is to help clear out space in a more spread-out manner. |
| 8438 | - * Dunno if it really does anything useful. |
| 8439 | - */ |
| 8440 | -static int yaffs_CheckGarbageCollection(yaffs_Device *dev) |
| 8441 | -{ |
| 8442 | - int block; |
| 8443 | - int aggressive; |
| 8444 | - int gcOk = YAFFS_OK; |
| 8445 | - int maxTries = 0; |
| 8446 | - |
| 8447 | - int checkpointBlockAdjust; |
| 8448 | - |
| 8449 | - if (dev->isDoingGC) { |
| 8450 | - /* Bail out so we don't get recursive gc */ |
| 8451 | - return YAFFS_OK; |
| 8452 | - } |
| 8453 | - |
| 8454 | - /* This loop should pass the first time. |
| 8455 | - * We'll only see looping here if the erase of the collected block fails. |
| 8456 | - */ |
| 8457 | - |
| 8458 | - do { |
| 8459 | - maxTries++; |
| 8460 | - |
| 8461 | - checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; |
| 8462 | - if (checkpointBlockAdjust < 0) |
| 8463 | - checkpointBlockAdjust = 0; |
| 8464 | - |
| 8465 | - if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) { |
| 8466 | - /* We need a block soon...*/ |
| 8467 | - aggressive = 1; |
| 8468 | - } else { |
| 8469 | - /* We're in no hurry */ |
| 8470 | - aggressive = 0; |
| 8471 | - } |
| 8472 | - |
| 8473 | - if (dev->gcBlock <= 0) { |
| 8474 | - dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive); |
| 8475 | - dev->gcChunk = 0; |
| 8476 | - } |
| 8477 | - |
| 8478 | - block = dev->gcBlock; |
| 8479 | - |
| 8480 | - if (block > 0) { |
| 8481 | - dev->garbageCollections++; |
| 8482 | - if (!aggressive) |
| 8483 | - dev->passiveGarbageCollections++; |
| 8484 | - |
| 8485 | - T(YAFFS_TRACE_GC, |
| 8486 | - (TSTR |
| 8487 | - ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR), |
| 8488 | - dev->nErasedBlocks, aggressive)); |
| 8489 | - |
| 8490 | - gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive); |
| 8491 | - } |
| 8492 | - |
| 8493 | - if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) { |
| 8494 | - T(YAFFS_TRACE_GC, |
| 8495 | - (TSTR |
| 8496 | - ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" |
| 8497 | - TENDSTR), dev->nErasedBlocks, maxTries, block)); |
| 8498 | - } |
| 8499 | - } while ((dev->nErasedBlocks < dev->nReservedBlocks) && |
| 8500 | - (block > 0) && |
| 8501 | - (maxTries < 2)); |
| 8502 | - |
| 8503 | - return aggressive ? gcOk : YAFFS_OK; |
| 8504 | -} |
| 8505 | - |
| 8506 | -/*------------------------- TAGS --------------------------------*/ |
| 8507 | - |
| 8508 | -static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, |
| 8509 | - int chunkInObject) |
| 8510 | -{ |
| 8511 | - return (tags->chunkId == chunkInObject && |
| 8512 | - tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0; |
| 8513 | - |
| 8514 | -} |
| 8515 | - |
| 8516 | - |
| 8517 | -/*-------------------- Data file manipulation -----------------*/ |
| 8518 | - |
| 8519 | -static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode, |
| 8520 | - yaffs_ExtendedTags *tags) |
| 8521 | -{ |
| 8522 | - /*Get the Tnode, then get the level 0 offset chunk offset */ |
| 8523 | - yaffs_Tnode *tn; |
| 8524 | - int theChunk = -1; |
| 8525 | - yaffs_ExtendedTags localTags; |
| 8526 | - int retVal = -1; |
| 8527 | - |
| 8528 | - yaffs_Device *dev = in->myDev; |
| 8529 | - |
| 8530 | - if (!tags) { |
| 8531 | - /* Passed a NULL, so use our own tags space */ |
| 8532 | - tags = &localTags; |
| 8533 | - } |
| 8534 | - |
| 8535 | - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); |
| 8536 | - |
| 8537 | - if (tn) { |
| 8538 | - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); |
| 8539 | - |
| 8540 | - retVal = |
| 8541 | - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, |
| 8542 | - chunkInInode); |
| 8543 | - } |
| 8544 | - return retVal; |
| 8545 | -} |
| 8546 | - |
| 8547 | -static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode, |
| 8548 | - yaffs_ExtendedTags *tags) |
| 8549 | -{ |
| 8550 | - /* Get the Tnode, then get the level 0 offset chunk offset */ |
| 8551 | - yaffs_Tnode *tn; |
| 8552 | - int theChunk = -1; |
| 8553 | - yaffs_ExtendedTags localTags; |
| 8554 | - |
| 8555 | - yaffs_Device *dev = in->myDev; |
| 8556 | - int retVal = -1; |
| 8557 | - |
| 8558 | - if (!tags) { |
| 8559 | - /* Passed a NULL, so use our own tags space */ |
| 8560 | - tags = &localTags; |
| 8561 | - } |
| 8562 | - |
| 8563 | - tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); |
| 8564 | - |
| 8565 | - if (tn) { |
| 8566 | - |
| 8567 | - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); |
| 8568 | - |
| 8569 | - retVal = |
| 8570 | - yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, |
| 8571 | - chunkInInode); |
| 8572 | - |
| 8573 | - /* Delete the entry in the filestructure (if found) */ |
| 8574 | - if (retVal != -1) |
| 8575 | - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0); |
| 8576 | - } |
| 8577 | - |
| 8578 | - return retVal; |
| 8579 | -} |
| 8580 | - |
| 8581 | -#ifdef YAFFS_PARANOID |
| 8582 | - |
| 8583 | -static int yaffs_CheckFileSanity(yaffs_Object *in) |
| 8584 | -{ |
| 8585 | - int chunk; |
| 8586 | - int nChunks; |
| 8587 | - int fSize; |
| 8588 | - int failed = 0; |
| 8589 | - int objId; |
| 8590 | - yaffs_Tnode *tn; |
| 8591 | - yaffs_Tags localTags; |
| 8592 | - yaffs_Tags *tags = &localTags; |
| 8593 | - int theChunk; |
| 8594 | - int chunkDeleted; |
| 8595 | - |
| 8596 | - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) |
| 8597 | - return YAFFS_FAIL; |
| 8598 | - |
| 8599 | - objId = in->objectId; |
| 8600 | - fSize = in->variant.fileVariant.fileSize; |
| 8601 | - nChunks = |
| 8602 | - (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk; |
| 8603 | - |
| 8604 | - for (chunk = 1; chunk <= nChunks; chunk++) { |
| 8605 | - tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant, |
| 8606 | - chunk); |
| 8607 | - |
| 8608 | - if (tn) { |
| 8609 | - |
| 8610 | - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk); |
| 8611 | - |
| 8612 | - if (yaffs_CheckChunkBits |
| 8613 | - (dev, theChunk / dev->nChunksPerBlock, |
| 8614 | - theChunk % dev->nChunksPerBlock)) { |
| 8615 | - |
| 8616 | - yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk, |
| 8617 | - tags, |
| 8618 | - &chunkDeleted); |
| 8619 | - if (yaffs_TagsMatch |
| 8620 | - (tags, in->objectId, chunk, chunkDeleted)) { |
| 8621 | - /* found it; */ |
| 8622 | - |
| 8623 | - } |
| 8624 | - } else { |
| 8625 | - |
| 8626 | - failed = 1; |
| 8627 | - } |
| 8628 | - |
| 8629 | - } else { |
| 8630 | - /* T(("No level 0 found for %d\n", chunk)); */ |
| 8631 | - } |
| 8632 | - } |
| 8633 | - |
| 8634 | - return failed ? YAFFS_FAIL : YAFFS_OK; |
| 8635 | -} |
| 8636 | - |
| 8637 | -#endif |
| 8638 | - |
| 8639 | -static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, |
| 8640 | - int chunkInNAND, int inScan) |
| 8641 | -{ |
| 8642 | - /* NB inScan is zero unless scanning. |
| 8643 | - * For forward scanning, inScan is > 0; |
| 8644 | - * for backward scanning inScan is < 0 |
| 8645 | - */ |
| 8646 | - |
| 8647 | - yaffs_Tnode *tn; |
| 8648 | - yaffs_Device *dev = in->myDev; |
| 8649 | - int existingChunk; |
| 8650 | - yaffs_ExtendedTags existingTags; |
| 8651 | - yaffs_ExtendedTags newTags; |
| 8652 | - unsigned existingSerial, newSerial; |
| 8653 | - |
| 8654 | - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { |
| 8655 | - /* Just ignore an attempt at putting a chunk into a non-file during scanning |
| 8656 | - * If it is not during Scanning then something went wrong! |
| 8657 | - */ |
| 8658 | - if (!inScan) { |
| 8659 | - T(YAFFS_TRACE_ERROR, |
| 8660 | - (TSTR |
| 8661 | - ("yaffs tragedy:attempt to put data chunk into a non-file" |
| 8662 | - TENDSTR))); |
| 8663 | - YBUG(); |
| 8664 | - } |
| 8665 | - |
| 8666 | - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); |
| 8667 | - return YAFFS_OK; |
| 8668 | - } |
| 8669 | - |
| 8670 | - tn = yaffs_AddOrFindLevel0Tnode(dev, |
| 8671 | - &in->variant.fileVariant, |
| 8672 | - chunkInInode, |
| 8673 | - NULL); |
| 8674 | - if (!tn) |
| 8675 | - return YAFFS_FAIL; |
| 8676 | - |
| 8677 | - existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); |
| 8678 | - |
| 8679 | - if (inScan != 0) { |
| 8680 | - /* If we're scanning then we need to test for duplicates |
| 8681 | - * NB This does not need to be efficient since it should only ever |
| 8682 | - * happen when the power fails during a write, then only one |
| 8683 | - * chunk should ever be affected. |
| 8684 | - * |
| 8685 | - * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO |
| 8686 | - * Update: For backward scanning we don't need to re-read tags so this is quite cheap. |
| 8687 | - */ |
| 8688 | - |
| 8689 | - if (existingChunk > 0) { |
| 8690 | - /* NB Right now existing chunk will not be real chunkId if the device >= 32MB |
| 8691 | - * thus we have to do a FindChunkInFile to get the real chunk id. |
| 8692 | - * |
| 8693 | - * We have a duplicate now we need to decide which one to use: |
| 8694 | - * |
| 8695 | - * Backwards scanning YAFFS2: The old one is what we use, dump the new one. |
| 8696 | - * Forward scanning YAFFS2: The new one is what we use, dump the old one. |
| 8697 | - * YAFFS1: Get both sets of tags and compare serial numbers. |
| 8698 | - */ |
| 8699 | - |
| 8700 | - if (inScan > 0) { |
| 8701 | - /* Only do this for forward scanning */ |
| 8702 | - yaffs_ReadChunkWithTagsFromNAND(dev, |
| 8703 | - chunkInNAND, |
| 8704 | - NULL, &newTags); |
| 8705 | - |
| 8706 | - /* Do a proper find */ |
| 8707 | - existingChunk = |
| 8708 | - yaffs_FindChunkInFile(in, chunkInInode, |
| 8709 | - &existingTags); |
| 8710 | - } |
| 8711 | - |
| 8712 | - if (existingChunk <= 0) { |
| 8713 | - /*Hoosterman - how did this happen? */ |
| 8714 | - |
| 8715 | - T(YAFFS_TRACE_ERROR, |
| 8716 | - (TSTR |
| 8717 | - ("yaffs tragedy: existing chunk < 0 in scan" |
| 8718 | - TENDSTR))); |
| 8719 | - |
| 8720 | - } |
| 8721 | - |
| 8722 | - /* NB The deleted flags should be false, otherwise the chunks will |
| 8723 | - * not be loaded during a scan |
| 8724 | - */ |
| 8725 | - |
| 8726 | - if (inScan > 0) { |
| 8727 | - newSerial = newTags.serialNumber; |
| 8728 | - existingSerial = existingTags.serialNumber; |
| 8729 | - } |
| 8730 | - |
| 8731 | - if ((inScan > 0) && |
| 8732 | - (in->myDev->isYaffs2 || |
| 8733 | - existingChunk <= 0 || |
| 8734 | - ((existingSerial + 1) & 3) == newSerial)) { |
| 8735 | - /* Forward scanning. |
| 8736 | - * Use new |
| 8737 | - * Delete the old one and drop through to update the tnode |
| 8738 | - */ |
| 8739 | - yaffs_DeleteChunk(dev, existingChunk, 1, |
| 8740 | - __LINE__); |
| 8741 | - } else { |
| 8742 | - /* Backward scanning or we want to use the existing one |
| 8743 | - * Use existing. |
| 8744 | - * Delete the new one and return early so that the tnode isn't changed |
| 8745 | - */ |
| 8746 | - yaffs_DeleteChunk(dev, chunkInNAND, 1, |
| 8747 | - __LINE__); |
| 8748 | - return YAFFS_OK; |
| 8749 | - } |
| 8750 | - } |
| 8751 | - |
| 8752 | - } |
| 8753 | - |
| 8754 | - if (existingChunk == 0) |
| 8755 | - in->nDataChunks++; |
| 8756 | - |
| 8757 | - yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND); |
| 8758 | - |
| 8759 | - return YAFFS_OK; |
| 8760 | -} |
| 8761 | - |
| 8762 | -static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode, |
| 8763 | - __u8 *buffer) |
| 8764 | -{ |
| 8765 | - int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL); |
| 8766 | - |
| 8767 | - if (chunkInNAND >= 0) |
| 8768 | - return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND, |
| 8769 | - buffer, NULL); |
| 8770 | - else { |
| 8771 | - T(YAFFS_TRACE_NANDACCESS, |
| 8772 | - (TSTR("Chunk %d not found zero instead" TENDSTR), |
| 8773 | - chunkInNAND)); |
| 8774 | - /* get sane (zero) data if you read a hole */ |
| 8775 | - memset(buffer, 0, in->myDev->nDataBytesPerChunk); |
| 8776 | - return 0; |
| 8777 | - } |
| 8778 | - |
| 8779 | -} |
| 8780 | - |
| 8781 | -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn) |
| 8782 | -{ |
| 8783 | - int block; |
| 8784 | - int page; |
| 8785 | - yaffs_ExtendedTags tags; |
| 8786 | - yaffs_BlockInfo *bi; |
| 8787 | - |
| 8788 | - if (chunkId <= 0) |
| 8789 | - return; |
| 8790 | - |
| 8791 | - dev->nDeletions++; |
| 8792 | - block = chunkId / dev->nChunksPerBlock; |
| 8793 | - page = chunkId % dev->nChunksPerBlock; |
| 8794 | - |
| 8795 | - |
| 8796 | - if (!yaffs_CheckChunkBit(dev, block, page)) |
| 8797 | - T(YAFFS_TRACE_VERIFY, |
| 8798 | - (TSTR("Deleting invalid chunk %d"TENDSTR), |
| 8799 | - chunkId)); |
| 8800 | - |
| 8801 | - bi = yaffs_GetBlockInfo(dev, block); |
| 8802 | - |
| 8803 | - T(YAFFS_TRACE_DELETION, |
| 8804 | - (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId)); |
| 8805 | - |
| 8806 | - if (markNAND && |
| 8807 | - bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) { |
| 8808 | - |
| 8809 | - yaffs_InitialiseTags(&tags); |
| 8810 | - |
| 8811 | - tags.chunkDeleted = 1; |
| 8812 | - |
| 8813 | - yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags); |
| 8814 | - yaffs_HandleUpdateChunk(dev, chunkId, &tags); |
| 8815 | - } else { |
| 8816 | - dev->nUnmarkedDeletions++; |
| 8817 | - } |
| 8818 | - |
| 8819 | - /* Pull out of the management area. |
| 8820 | - * If the whole block became dirty, this will kick off an erasure. |
| 8821 | - */ |
| 8822 | - if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || |
| 8823 | - bi->blockState == YAFFS_BLOCK_STATE_FULL || |
| 8824 | - bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING || |
| 8825 | - bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { |
| 8826 | - dev->nFreeChunks++; |
| 8827 | - |
| 8828 | - yaffs_ClearChunkBit(dev, block, page); |
| 8829 | - |
| 8830 | - bi->pagesInUse--; |
| 8831 | - |
| 8832 | - if (bi->pagesInUse == 0 && |
| 8833 | - !bi->hasShrinkHeader && |
| 8834 | - bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING && |
| 8835 | - bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) { |
| 8836 | - yaffs_BlockBecameDirty(dev, block); |
| 8837 | - } |
| 8838 | - |
| 8839 | - } |
| 8840 | - |
| 8841 | -} |
| 8842 | - |
| 8843 | -static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, |
| 8844 | - const __u8 *buffer, int nBytes, |
| 8845 | - int useReserve) |
| 8846 | -{ |
| 8847 | - /* Find old chunk Need to do this to get serial number |
| 8848 | - * Write new one and patch into tree. |
| 8849 | - * Invalidate old tags. |
| 8850 | - */ |
| 8851 | - |
| 8852 | - int prevChunkId; |
| 8853 | - yaffs_ExtendedTags prevTags; |
| 8854 | - |
| 8855 | - int newChunkId; |
| 8856 | - yaffs_ExtendedTags newTags; |
| 8857 | - |
| 8858 | - yaffs_Device *dev = in->myDev; |
| 8859 | - |
| 8860 | - yaffs_CheckGarbageCollection(dev); |
| 8861 | - |
| 8862 | - /* Get the previous chunk at this location in the file if it exists */ |
| 8863 | - prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags); |
| 8864 | - |
| 8865 | - /* Set up new tags */ |
| 8866 | - yaffs_InitialiseTags(&newTags); |
| 8867 | - |
| 8868 | - newTags.chunkId = chunkInInode; |
| 8869 | - newTags.objectId = in->objectId; |
| 8870 | - newTags.serialNumber = |
| 8871 | - (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1; |
| 8872 | - newTags.byteCount = nBytes; |
| 8873 | - |
| 8874 | - if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) { |
| 8875 | - T(YAFFS_TRACE_ERROR, |
| 8876 | - (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes)); |
| 8877 | - YBUG(); |
| 8878 | - } |
| 8879 | - |
| 8880 | - newChunkId = |
| 8881 | - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, |
| 8882 | - useReserve); |
| 8883 | - |
| 8884 | - if (newChunkId >= 0) { |
| 8885 | - yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0); |
| 8886 | - |
| 8887 | - if (prevChunkId >= 0) |
| 8888 | - yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__); |
| 8889 | - |
| 8890 | - yaffs_CheckFileSanity(in); |
| 8891 | - } |
| 8892 | - return newChunkId; |
| 8893 | - |
| 8894 | -} |
| 8895 | - |
| 8896 | -/* UpdateObjectHeader updates the header on NAND for an object. |
| 8897 | - * If name is not NULL, then that new name is used. |
| 8898 | - */ |
| 8899 | -int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, |
| 8900 | - int isShrink, int shadows) |
| 8901 | -{ |
| 8902 | - |
| 8903 | - yaffs_BlockInfo *bi; |
| 8904 | - |
| 8905 | - yaffs_Device *dev = in->myDev; |
| 8906 | - |
| 8907 | - int prevChunkId; |
| 8908 | - int retVal = 0; |
| 8909 | - int result = 0; |
| 8910 | - |
| 8911 | - int newChunkId; |
| 8912 | - yaffs_ExtendedTags newTags; |
| 8913 | - yaffs_ExtendedTags oldTags; |
| 8914 | - |
| 8915 | - __u8 *buffer = NULL; |
| 8916 | - YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1]; |
| 8917 | - |
| 8918 | - yaffs_ObjectHeader *oh = NULL; |
| 8919 | + yaffs_obj_t *in; |
| 8920 | + YCHAR *str = NULL; |
| 8921 | |
| 8922 | - yaffs_strcpy(oldName, _Y("silly old name")); |
| 8923 | + yaffs_dev_t *dev = parent->my_dev; |
| 8924 | |
| 8925 | + /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/ |
| 8926 | + if (yaffs_find_by_name(parent, name)) |
| 8927 | + return NULL; |
| 8928 | |
| 8929 | - if (!in->fake || |
| 8930 | - in == dev->rootDir || /* The rootDir should also be saved */ |
| 8931 | - force) { |
| 8932 | + if (type == YAFFS_OBJECT_TYPE_SYMLINK) { |
| 8933 | + str = yaffs_clone_str(aliasString); |
| 8934 | + if (!str) |
| 8935 | + return NULL; |
| 8936 | + } |
| 8937 | |
| 8938 | - yaffs_CheckGarbageCollection(dev); |
| 8939 | - yaffs_CheckObjectDetailsLoaded(in); |
| 8940 | + in = yaffs_new_obj(dev, -1, type); |
| 8941 | |
| 8942 | - buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); |
| 8943 | - oh = (yaffs_ObjectHeader *) buffer; |
| 8944 | + if (!in){ |
| 8945 | + if(str) |
| 8946 | + YFREE(str); |
| 8947 | + return NULL; |
| 8948 | + } |
| 8949 | |
| 8950 | - prevChunkId = in->hdrChunk; |
| 8951 | |
| 8952 | - if (prevChunkId > 0) { |
| 8953 | - result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId, |
| 8954 | - buffer, &oldTags); |
| 8955 | |
| 8956 | - yaffs_VerifyObjectHeader(in, oh, &oldTags, 0); |
| 8957 | |
| 8958 | - memcpy(oldName, oh->name, sizeof(oh->name)); |
| 8959 | - } |
| 8960 | |
| 8961 | - memset(buffer, 0xFF, dev->nDataBytesPerChunk); |
| 8962 | + if (in) { |
| 8963 | + in->hdr_chunk = 0; |
| 8964 | + in->valid = 1; |
| 8965 | + in->variant_type = type; |
| 8966 | |
| 8967 | - oh->type = in->variantType; |
| 8968 | - oh->yst_mode = in->yst_mode; |
| 8969 | - oh->shadowsObject = oh->inbandShadowsObject = shadows; |
| 8970 | + in->yst_mode = mode; |
| 8971 | |
| 8972 | #ifdef CONFIG_YAFFS_WINCE |
| 8973 | - oh->win_atime[0] = in->win_atime[0]; |
| 8974 | - oh->win_ctime[0] = in->win_ctime[0]; |
| 8975 | - oh->win_mtime[0] = in->win_mtime[0]; |
| 8976 | - oh->win_atime[1] = in->win_atime[1]; |
| 8977 | - oh->win_ctime[1] = in->win_ctime[1]; |
| 8978 | - oh->win_mtime[1] = in->win_mtime[1]; |
| 8979 | + yfsd_win_file_time_now(in->win_atime); |
| 8980 | + in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0]; |
| 8981 | + in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1]; |
| 8982 | + |
| 8983 | #else |
| 8984 | - oh->yst_uid = in->yst_uid; |
| 8985 | - oh->yst_gid = in->yst_gid; |
| 8986 | - oh->yst_atime = in->yst_atime; |
| 8987 | - oh->yst_mtime = in->yst_mtime; |
| 8988 | - oh->yst_ctime = in->yst_ctime; |
| 8989 | - oh->yst_rdev = in->yst_rdev; |
| 8990 | + in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME; |
| 8991 | + |
| 8992 | + in->yst_rdev = rdev; |
| 8993 | + in->yst_uid = uid; |
| 8994 | + in->yst_gid = gid; |
| 8995 | #endif |
| 8996 | - if (in->parent) |
| 8997 | - oh->parentObjectId = in->parent->objectId; |
| 8998 | - else |
| 8999 | - oh->parentObjectId = 0; |
| 9000 | + in->n_data_chunks = 0; |
| 9001 | |
| 9002 | - if (name && *name) { |
| 9003 | - memset(oh->name, 0, sizeof(oh->name)); |
| 9004 | - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); |
| 9005 | - } else if (prevChunkId >= 0) |
| 9006 | - memcpy(oh->name, oldName, sizeof(oh->name)); |
| 9007 | - else |
| 9008 | - memset(oh->name, 0, sizeof(oh->name)); |
| 9009 | + yaffs_set_obj_name(in, name); |
| 9010 | + in->dirty = 1; |
| 9011 | |
| 9012 | - oh->isShrink = isShrink; |
| 9013 | + yaffs_add_obj_to_dir(parent, in); |
| 9014 | |
| 9015 | - switch (in->variantType) { |
| 9016 | - case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 9017 | - /* Should not happen */ |
| 9018 | - break; |
| 9019 | - case YAFFS_OBJECT_TYPE_FILE: |
| 9020 | - oh->fileSize = |
| 9021 | - (oh->parentObjectId == YAFFS_OBJECTID_DELETED |
| 9022 | - || oh->parentObjectId == |
| 9023 | - YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant. |
| 9024 | - fileVariant.fileSize; |
| 9025 | + in->my_dev = parent->my_dev; |
| 9026 | + |
| 9027 | + switch (type) { |
| 9028 | + case YAFFS_OBJECT_TYPE_SYMLINK: |
| 9029 | + in->variant.symlink_variant.alias = str; |
| 9030 | break; |
| 9031 | case YAFFS_OBJECT_TYPE_HARDLINK: |
| 9032 | - oh->equivalentObjectId = |
| 9033 | - in->variant.hardLinkVariant.equivalentObjectId; |
| 9034 | - break; |
| 9035 | - case YAFFS_OBJECT_TYPE_SPECIAL: |
| 9036 | - /* Do nothing */ |
| 9037 | + in->variant.hardlink_variant.equiv_obj = |
| 9038 | + equiv_obj; |
| 9039 | + in->variant.hardlink_variant.equiv_id = |
| 9040 | + equiv_obj->obj_id; |
| 9041 | + ylist_add(&in->hard_links, &equiv_obj->hard_links); |
| 9042 | break; |
| 9043 | + case YAFFS_OBJECT_TYPE_FILE: |
| 9044 | case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 9045 | - /* Do nothing */ |
| 9046 | - break; |
| 9047 | - case YAFFS_OBJECT_TYPE_SYMLINK: |
| 9048 | - yaffs_strncpy(oh->alias, |
| 9049 | - in->variant.symLinkVariant.alias, |
| 9050 | - YAFFS_MAX_ALIAS_LENGTH); |
| 9051 | - oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; |
| 9052 | + case YAFFS_OBJECT_TYPE_SPECIAL: |
| 9053 | + case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 9054 | + /* do nothing */ |
| 9055 | break; |
| 9056 | } |
| 9057 | |
| 9058 | - /* Tags */ |
| 9059 | - yaffs_InitialiseTags(&newTags); |
| 9060 | - in->serial++; |
| 9061 | - newTags.chunkId = 0; |
| 9062 | - newTags.objectId = in->objectId; |
| 9063 | - newTags.serialNumber = in->serial; |
| 9064 | - |
| 9065 | - /* Add extra info for file header */ |
| 9066 | - |
| 9067 | - newTags.extraHeaderInfoAvailable = 1; |
| 9068 | - newTags.extraParentObjectId = oh->parentObjectId; |
| 9069 | - newTags.extraFileLength = oh->fileSize; |
| 9070 | - newTags.extraIsShrinkHeader = oh->isShrink; |
| 9071 | - newTags.extraEquivalentObjectId = oh->equivalentObjectId; |
| 9072 | - newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0; |
| 9073 | - newTags.extraObjectType = in->variantType; |
| 9074 | - |
| 9075 | - yaffs_VerifyObjectHeader(in, oh, &newTags, 1); |
| 9076 | - |
| 9077 | - /* Create new chunk in NAND */ |
| 9078 | - newChunkId = |
| 9079 | - yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, |
| 9080 | - (prevChunkId >= 0) ? 1 : 0); |
| 9081 | - |
| 9082 | - if (newChunkId >= 0) { |
| 9083 | - |
| 9084 | - in->hdrChunk = newChunkId; |
| 9085 | - |
| 9086 | - if (prevChunkId >= 0) { |
| 9087 | - yaffs_DeleteChunk(dev, prevChunkId, 1, |
| 9088 | - __LINE__); |
| 9089 | - } |
| 9090 | - |
| 9091 | - if (!yaffs_ObjectHasCachedWriteData(in)) |
| 9092 | - in->dirty = 0; |
| 9093 | - |
| 9094 | - /* If this was a shrink, then mark the block that the chunk lives on */ |
| 9095 | - if (isShrink) { |
| 9096 | - bi = yaffs_GetBlockInfo(in->myDev, |
| 9097 | - newChunkId / in->myDev->nChunksPerBlock); |
| 9098 | - bi->hasShrinkHeader = 1; |
| 9099 | - } |
| 9100 | - |
| 9101 | + if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) { |
| 9102 | + /* Could not create the object header, fail the creation */ |
| 9103 | + yaffs_del_obj(in); |
| 9104 | + in = NULL; |
| 9105 | } |
| 9106 | |
| 9107 | - retVal = newChunkId; |
| 9108 | - |
| 9109 | + yaffs_update_parent(parent); |
| 9110 | } |
| 9111 | |
| 9112 | - if (buffer) |
| 9113 | - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); |
| 9114 | - |
| 9115 | - return retVal; |
| 9116 | + return in; |
| 9117 | } |
| 9118 | |
| 9119 | -/*------------------------ Short Operations Cache ---------------------------------------- |
| 9120 | - * In many situations where there is no high level buffering (eg WinCE) a lot of |
| 9121 | - * reads might be short sequential reads, and a lot of writes may be short |
| 9122 | - * sequential writes. eg. scanning/writing a jpeg file. |
| 9123 | - * In these cases, a short read/write cache can provide a huge perfomance benefit |
| 9124 | - * with dumb-as-a-rock code. |
| 9125 | - * In Linux, the page cache provides read buffering aand the short op cache provides write |
| 9126 | - * buffering. |
| 9127 | - * |
| 9128 | - * There are a limited number (~10) of cache chunks per device so that we don't |
| 9129 | - * need a very intelligent search. |
| 9130 | - */ |
| 9131 | - |
| 9132 | -static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj) |
| 9133 | +yaffs_obj_t *yaffs_create_file(yaffs_obj_t *parent, const YCHAR *name, |
| 9134 | + __u32 mode, __u32 uid, __u32 gid) |
| 9135 | { |
| 9136 | - yaffs_Device *dev = obj->myDev; |
| 9137 | - int i; |
| 9138 | - yaffs_ChunkCache *cache; |
| 9139 | - int nCaches = obj->myDev->nShortOpCaches; |
| 9140 | - |
| 9141 | - for (i = 0; i < nCaches; i++) { |
| 9142 | - cache = &dev->srCache[i]; |
| 9143 | - if (cache->object == obj && |
| 9144 | - cache->dirty) |
| 9145 | - return 1; |
| 9146 | - } |
| 9147 | + return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, |
| 9148 | + uid, gid, NULL, NULL, 0); |
| 9149 | +} |
| 9150 | |
| 9151 | - return 0; |
| 9152 | +yaffs_obj_t *yaffs_create_dir(yaffs_obj_t *parent, const YCHAR *name, |
| 9153 | + __u32 mode, __u32 uid, __u32 gid) |
| 9154 | +{ |
| 9155 | + return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, |
| 9156 | + mode, uid, gid, NULL, NULL, 0); |
| 9157 | } |
| 9158 | |
| 9159 | +yaffs_obj_t *yaffs_create_special(yaffs_obj_t *parent, const YCHAR *name, |
| 9160 | + __u32 mode, __u32 uid, __u32 gid, __u32 rdev) |
| 9161 | +{ |
| 9162 | + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, |
| 9163 | + uid, gid, NULL, NULL, rdev); |
| 9164 | +} |
| 9165 | |
| 9166 | -static void yaffs_FlushFilesChunkCache(yaffs_Object *obj) |
| 9167 | +yaffs_obj_t *yaffs_create_symlink(yaffs_obj_t *parent, const YCHAR *name, |
| 9168 | + __u32 mode, __u32 uid, __u32 gid, |
| 9169 | + const YCHAR *alias) |
| 9170 | { |
| 9171 | - yaffs_Device *dev = obj->myDev; |
| 9172 | - int lowest = -99; /* Stop compiler whining. */ |
| 9173 | - int i; |
| 9174 | - yaffs_ChunkCache *cache; |
| 9175 | - int chunkWritten = 0; |
| 9176 | - int nCaches = obj->myDev->nShortOpCaches; |
| 9177 | + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, |
| 9178 | + uid, gid, NULL, alias, 0); |
| 9179 | +} |
| 9180 | |
| 9181 | - if (nCaches > 0) { |
| 9182 | - do { |
| 9183 | - cache = NULL; |
| 9184 | +/* yaffs_link_obj returns the object id of the equivalent object.*/ |
| 9185 | +yaffs_obj_t *yaffs_link_obj(yaffs_obj_t *parent, const YCHAR *name, |
| 9186 | + yaffs_obj_t *equiv_obj) |
| 9187 | +{ |
| 9188 | + /* Get the real object in case we were fed a hard link as an equivalent object */ |
| 9189 | + equiv_obj = yaffs_get_equivalent_obj(equiv_obj); |
| 9190 | |
| 9191 | - /* Find the dirty cache for this object with the lowest chunk id. */ |
| 9192 | - for (i = 0; i < nCaches; i++) { |
| 9193 | - if (dev->srCache[i].object == obj && |
| 9194 | - dev->srCache[i].dirty) { |
| 9195 | - if (!cache |
| 9196 | - || dev->srCache[i].chunkId < |
| 9197 | - lowest) { |
| 9198 | - cache = &dev->srCache[i]; |
| 9199 | - lowest = cache->chunkId; |
| 9200 | - } |
| 9201 | - } |
| 9202 | - } |
| 9203 | + if (yaffs_create_obj |
| 9204 | + (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0, |
| 9205 | + equiv_obj, NULL, 0)) { |
| 9206 | + return equiv_obj; |
| 9207 | + } else { |
| 9208 | + return NULL; |
| 9209 | + } |
| 9210 | |
| 9211 | - if (cache && !cache->locked) { |
| 9212 | - /* Write it out and free it up */ |
| 9213 | +} |
| 9214 | |
| 9215 | - chunkWritten = |
| 9216 | - yaffs_WriteChunkDataToObject(cache->object, |
| 9217 | - cache->chunkId, |
| 9218 | - cache->data, |
| 9219 | - cache->nBytes, |
| 9220 | - 1); |
| 9221 | - cache->dirty = 0; |
| 9222 | - cache->object = NULL; |
| 9223 | - } |
| 9224 | +static int yaffs_change_obj_name(yaffs_obj_t *obj, yaffs_obj_t *new_dir, |
| 9225 | + const YCHAR *new_name, int force, int shadows) |
| 9226 | +{ |
| 9227 | + int unlinkOp; |
| 9228 | + int deleteOp; |
| 9229 | |
| 9230 | - } while (cache && chunkWritten > 0); |
| 9231 | + yaffs_obj_t *existingTarget; |
| 9232 | |
| 9233 | - if (cache) { |
| 9234 | - /* Hoosterman, disk full while writing cache out. */ |
| 9235 | - T(YAFFS_TRACE_ERROR, |
| 9236 | - (TSTR("yaffs tragedy: no space during cache write" TENDSTR))); |
| 9237 | + if (new_dir == NULL) |
| 9238 | + new_dir = obj->parent; /* use the old directory */ |
| 9239 | |
| 9240 | - } |
| 9241 | + if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 9242 | + T(YAFFS_TRACE_ALWAYS, |
| 9243 | + (TSTR |
| 9244 | + ("tragedy: yaffs_change_obj_name: new_dir is not a directory" |
| 9245 | + TENDSTR))); |
| 9246 | + YBUG(); |
| 9247 | } |
| 9248 | |
| 9249 | -} |
| 9250 | + /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ |
| 9251 | + if (obj->my_dev->param.is_yaffs2) |
| 9252 | + unlinkOp = (new_dir == obj->my_dev->unlinked_dir); |
| 9253 | + else |
| 9254 | + unlinkOp = (new_dir == obj->my_dev->unlinked_dir |
| 9255 | + && obj->variant_type == YAFFS_OBJECT_TYPE_FILE); |
| 9256 | |
| 9257 | -/*yaffs_FlushEntireDeviceCache(dev) |
| 9258 | - * |
| 9259 | - * |
| 9260 | - */ |
| 9261 | + deleteOp = (new_dir == obj->my_dev->del_dir); |
| 9262 | |
| 9263 | -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev) |
| 9264 | -{ |
| 9265 | - yaffs_Object *obj; |
| 9266 | - int nCaches = dev->nShortOpCaches; |
| 9267 | - int i; |
| 9268 | + existingTarget = yaffs_find_by_name(new_dir, new_name); |
| 9269 | |
| 9270 | - /* Find a dirty object in the cache and flush it... |
| 9271 | - * until there are no further dirty objects. |
| 9272 | + /* If the object is a file going into the unlinked directory, |
| 9273 | + * then it is OK to just stuff it in since duplicate names are allowed. |
| 9274 | + * else only proceed if the new name does not exist and if we're putting |
| 9275 | + * it into a directory. |
| 9276 | */ |
| 9277 | - do { |
| 9278 | - obj = NULL; |
| 9279 | - for (i = 0; i < nCaches && !obj; i++) { |
| 9280 | - if (dev->srCache[i].object && |
| 9281 | - dev->srCache[i].dirty) |
| 9282 | - obj = dev->srCache[i].object; |
| 9283 | - |
| 9284 | - } |
| 9285 | - if (obj) |
| 9286 | - yaffs_FlushFilesChunkCache(obj); |
| 9287 | - |
| 9288 | - } while (obj); |
| 9289 | - |
| 9290 | -} |
| 9291 | + if ((unlinkOp || |
| 9292 | + deleteOp || |
| 9293 | + force || |
| 9294 | + (shadows > 0) || |
| 9295 | + !existingTarget) && |
| 9296 | + new_dir->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 9297 | + yaffs_set_obj_name(obj, new_name); |
| 9298 | + obj->dirty = 1; |
| 9299 | |
| 9300 | + yaffs_add_obj_to_dir(new_dir, obj); |
| 9301 | |
| 9302 | -/* Grab us a cache chunk for use. |
| 9303 | - * First look for an empty one. |
| 9304 | - * Then look for the least recently used non-dirty one. |
| 9305 | - * Then look for the least recently used dirty one...., flush and look again. |
| 9306 | - */ |
| 9307 | -static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev) |
| 9308 | -{ |
| 9309 | - int i; |
| 9310 | + if (unlinkOp) |
| 9311 | + obj->unlinked = 1; |
| 9312 | |
| 9313 | - if (dev->nShortOpCaches > 0) { |
| 9314 | - for (i = 0; i < dev->nShortOpCaches; i++) { |
| 9315 | - if (!dev->srCache[i].object) |
| 9316 | - return &dev->srCache[i]; |
| 9317 | - } |
| 9318 | + /* If it is a deletion then we mark it as a shrink for gc purposes. */ |
| 9319 | + if (yaffs_update_oh(obj, new_name, 0, deleteOp, shadows, NULL) >= 0) |
| 9320 | + return YAFFS_OK; |
| 9321 | } |
| 9322 | |
| 9323 | - return NULL; |
| 9324 | + return YAFFS_FAIL; |
| 9325 | } |
| 9326 | |
| 9327 | -static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev) |
| 9328 | +int yaffs_rename_obj(yaffs_obj_t *old_dir, const YCHAR *old_name, |
| 9329 | + yaffs_obj_t *new_dir, const YCHAR *new_name) |
| 9330 | { |
| 9331 | - yaffs_ChunkCache *cache; |
| 9332 | - yaffs_Object *theObj; |
| 9333 | - int usage; |
| 9334 | - int i; |
| 9335 | - int pushout; |
| 9336 | - |
| 9337 | - if (dev->nShortOpCaches > 0) { |
| 9338 | - /* Try find a non-dirty one... */ |
| 9339 | - |
| 9340 | - cache = yaffs_GrabChunkCacheWorker(dev); |
| 9341 | + yaffs_obj_t *obj = NULL; |
| 9342 | + yaffs_obj_t *existingTarget = NULL; |
| 9343 | + int force = 0; |
| 9344 | + int result; |
| 9345 | + yaffs_dev_t *dev; |
| 9346 | |
| 9347 | - if (!cache) { |
| 9348 | - /* They were all dirty, find the last recently used object and flush |
| 9349 | - * its cache, then find again. |
| 9350 | - * NB what's here is not very accurate, we actually flush the object |
| 9351 | - * the last recently used page. |
| 9352 | - */ |
| 9353 | |
| 9354 | - /* With locking we can't assume we can use entry zero */ |
| 9355 | + if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) |
| 9356 | + YBUG(); |
| 9357 | + if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) |
| 9358 | + YBUG(); |
| 9359 | |
| 9360 | - theObj = NULL; |
| 9361 | - usage = -1; |
| 9362 | - cache = NULL; |
| 9363 | - pushout = -1; |
| 9364 | + dev = old_dir->my_dev; |
| 9365 | |
| 9366 | - for (i = 0; i < dev->nShortOpCaches; i++) { |
| 9367 | - if (dev->srCache[i].object && |
| 9368 | - !dev->srCache[i].locked && |
| 9369 | - (dev->srCache[i].lastUse < usage || !cache)) { |
| 9370 | - usage = dev->srCache[i].lastUse; |
| 9371 | - theObj = dev->srCache[i].object; |
| 9372 | - cache = &dev->srCache[i]; |
| 9373 | - pushout = i; |
| 9374 | - } |
| 9375 | - } |
| 9376 | +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE |
| 9377 | + /* Special case for case insemsitive systems (eg. WinCE). |
| 9378 | + * While look-up is case insensitive, the name isn't. |
| 9379 | + * Therefore we might want to change x.txt to X.txt |
| 9380 | + */ |
| 9381 | + if (old_dir == new_dir && yaffs_strcmp(old_name, new_name) == 0) |
| 9382 | + force = 1; |
| 9383 | +#endif |
| 9384 | |
| 9385 | - if (!cache || cache->dirty) { |
| 9386 | - /* Flush and try again */ |
| 9387 | - yaffs_FlushFilesChunkCache(theObj); |
| 9388 | - cache = yaffs_GrabChunkCacheWorker(dev); |
| 9389 | - } |
| 9390 | + if(yaffs_strnlen(new_name,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH) |
| 9391 | + /* ENAMETOOLONG */ |
| 9392 | + return YAFFS_FAIL; |
| 9393 | |
| 9394 | - } |
| 9395 | - return cache; |
| 9396 | - } else |
| 9397 | - return NULL; |
| 9398 | + obj = yaffs_find_by_name(old_dir, old_name); |
| 9399 | |
| 9400 | -} |
| 9401 | + if (obj && obj->rename_allowed) { |
| 9402 | |
| 9403 | -/* Find a cached chunk */ |
| 9404 | -static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, |
| 9405 | - int chunkId) |
| 9406 | -{ |
| 9407 | - yaffs_Device *dev = obj->myDev; |
| 9408 | - int i; |
| 9409 | - if (dev->nShortOpCaches > 0) { |
| 9410 | - for (i = 0; i < dev->nShortOpCaches; i++) { |
| 9411 | - if (dev->srCache[i].object == obj && |
| 9412 | - dev->srCache[i].chunkId == chunkId) { |
| 9413 | - dev->cacheHits++; |
| 9414 | + /* Now do the handling for an existing target, if there is one */ |
| 9415 | |
| 9416 | - return &dev->srCache[i]; |
| 9417 | - } |
| 9418 | + existingTarget = yaffs_find_by_name(new_dir, new_name); |
| 9419 | + if (existingTarget && |
| 9420 | + existingTarget->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY && |
| 9421 | + !ylist_empty(&existingTarget->variant.dir_variant.children)) { |
| 9422 | + /* There is a target that is a non-empty directory, so we fail */ |
| 9423 | + return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */ |
| 9424 | + } else if (existingTarget && existingTarget != obj) { |
| 9425 | + /* Nuke the target first, using shadowing, |
| 9426 | + * but only if it isn't the same object. |
| 9427 | + * |
| 9428 | + * Note we must disable gc otherwise it can mess up the shadowing. |
| 9429 | + * |
| 9430 | + */ |
| 9431 | + dev->gc_disable=1; |
| 9432 | + yaffs_change_obj_name(obj, new_dir, new_name, force, |
| 9433 | + existingTarget->obj_id); |
| 9434 | + existingTarget->is_shadowed = 1; |
| 9435 | + yaffs_unlink_obj(existingTarget); |
| 9436 | + dev->gc_disable=0; |
| 9437 | } |
| 9438 | + |
| 9439 | + result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0); |
| 9440 | + |
| 9441 | + yaffs_update_parent(old_dir); |
| 9442 | + if(new_dir != old_dir) |
| 9443 | + yaffs_update_parent(new_dir); |
| 9444 | + |
| 9445 | + return result; |
| 9446 | } |
| 9447 | - return NULL; |
| 9448 | + return YAFFS_FAIL; |
| 9449 | } |
| 9450 | |
| 9451 | -/* Mark the chunk for the least recently used algorithym */ |
| 9452 | -static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, |
| 9453 | - int isAWrite) |
| 9454 | +/*------------------------- Block Management and Page Allocation ----------------*/ |
| 9455 | + |
| 9456 | +static int yaffs_init_blocks(yaffs_dev_t *dev) |
| 9457 | { |
| 9458 | + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1; |
| 9459 | |
| 9460 | - if (dev->nShortOpCaches > 0) { |
| 9461 | - if (dev->srLastUse < 0 || dev->srLastUse > 100000000) { |
| 9462 | - /* Reset the cache usages */ |
| 9463 | - int i; |
| 9464 | - for (i = 1; i < dev->nShortOpCaches; i++) |
| 9465 | - dev->srCache[i].lastUse = 0; |
| 9466 | + dev->block_info = NULL; |
| 9467 | + dev->chunk_bits = NULL; |
| 9468 | |
| 9469 | - dev->srLastUse = 0; |
| 9470 | - } |
| 9471 | + dev->alloc_block = -1; /* force it to get a new one */ |
| 9472 | |
| 9473 | - dev->srLastUse++; |
| 9474 | + /* If the first allocation strategy fails, thry the alternate one */ |
| 9475 | + dev->block_info = YMALLOC(nBlocks * sizeof(yaffs_block_info_t)); |
| 9476 | + if (!dev->block_info) { |
| 9477 | + dev->block_info = YMALLOC_ALT(nBlocks * sizeof(yaffs_block_info_t)); |
| 9478 | + dev->block_info_alt = 1; |
| 9479 | + } else |
| 9480 | + dev->block_info_alt = 0; |
| 9481 | |
| 9482 | - cache->lastUse = dev->srLastUse; |
| 9483 | + if (dev->block_info) { |
| 9484 | + /* Set up dynamic blockinfo stuff. */ |
| 9485 | + dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; /* round up bytes */ |
| 9486 | + dev->chunk_bits = YMALLOC(dev->chunk_bit_stride * nBlocks); |
| 9487 | + if (!dev->chunk_bits) { |
| 9488 | + dev->chunk_bits = YMALLOC_ALT(dev->chunk_bit_stride * nBlocks); |
| 9489 | + dev->chunk_bits_alt = 1; |
| 9490 | + } else |
| 9491 | + dev->chunk_bits_alt = 0; |
| 9492 | + } |
| 9493 | |
| 9494 | - if (isAWrite) |
| 9495 | - cache->dirty = 1; |
| 9496 | + if (dev->block_info && dev->chunk_bits) { |
| 9497 | + memset(dev->block_info, 0, nBlocks * sizeof(yaffs_block_info_t)); |
| 9498 | + memset(dev->chunk_bits, 0, dev->chunk_bit_stride * nBlocks); |
| 9499 | + return YAFFS_OK; |
| 9500 | } |
| 9501 | + |
| 9502 | + return YAFFS_FAIL; |
| 9503 | } |
| 9504 | |
| 9505 | -/* Invalidate a single cache page. |
| 9506 | - * Do this when a whole page gets written, |
| 9507 | - * ie the short cache for this page is no longer valid. |
| 9508 | - */ |
| 9509 | -static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId) |
| 9510 | +static void yaffs_deinit_blocks(yaffs_dev_t *dev) |
| 9511 | { |
| 9512 | - if (object->myDev->nShortOpCaches > 0) { |
| 9513 | - yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId); |
| 9514 | + if (dev->block_info_alt && dev->block_info) |
| 9515 | + YFREE_ALT(dev->block_info); |
| 9516 | + else if (dev->block_info) |
| 9517 | + YFREE(dev->block_info); |
| 9518 | |
| 9519 | - if (cache) |
| 9520 | - cache->object = NULL; |
| 9521 | - } |
| 9522 | -} |
| 9523 | + dev->block_info_alt = 0; |
| 9524 | |
| 9525 | -/* Invalidate all the cache pages associated with this object |
| 9526 | - * Do this whenever ther file is deleted or resized. |
| 9527 | - */ |
| 9528 | -static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in) |
| 9529 | -{ |
| 9530 | - int i; |
| 9531 | - yaffs_Device *dev = in->myDev; |
| 9532 | + dev->block_info = NULL; |
| 9533 | |
| 9534 | - if (dev->nShortOpCaches > 0) { |
| 9535 | - /* Invalidate it. */ |
| 9536 | - for (i = 0; i < dev->nShortOpCaches; i++) { |
| 9537 | - if (dev->srCache[i].object == in) |
| 9538 | - dev->srCache[i].object = NULL; |
| 9539 | - } |
| 9540 | - } |
| 9541 | + if (dev->chunk_bits_alt && dev->chunk_bits) |
| 9542 | + YFREE_ALT(dev->chunk_bits); |
| 9543 | + else if (dev->chunk_bits) |
| 9544 | + YFREE(dev->chunk_bits); |
| 9545 | + dev->chunk_bits_alt = 0; |
| 9546 | + dev->chunk_bits = NULL; |
| 9547 | } |
| 9548 | |
| 9549 | -/*--------------------- Checkpointing --------------------*/ |
| 9550 | +void yaffs_block_became_dirty(yaffs_dev_t *dev, int block_no) |
| 9551 | +{ |
| 9552 | + yaffs_block_info_t *bi = yaffs_get_block_info(dev, block_no); |
| 9553 | |
| 9554 | + int erasedOk = 0; |
| 9555 | |
| 9556 | -static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head) |
| 9557 | -{ |
| 9558 | - yaffs_CheckpointValidity cp; |
| 9559 | + /* If the block is still healthy erase it and mark as clean. |
| 9560 | + * If the block has had a data failure, then retire it. |
| 9561 | + */ |
| 9562 | |
| 9563 | - memset(&cp, 0, sizeof(cp)); |
| 9564 | + T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, |
| 9565 | + (TSTR("yaffs_block_became_dirty block %d state %d %s"TENDSTR), |
| 9566 | + block_no, bi->block_state, (bi->needs_retiring) ? "needs retiring" : "")); |
| 9567 | |
| 9568 | - cp.structType = sizeof(cp); |
| 9569 | - cp.magic = YAFFS_MAGIC; |
| 9570 | - cp.version = YAFFS_CHECKPOINT_VERSION; |
| 9571 | - cp.head = (head) ? 1 : 0; |
| 9572 | + yaffs2_clear_oldest_dirty_seq(dev,bi); |
| 9573 | |
| 9574 | - return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ? |
| 9575 | - 1 : 0; |
| 9576 | -} |
| 9577 | + bi->block_state = YAFFS_BLOCK_STATE_DIRTY; |
| 9578 | |
| 9579 | -static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head) |
| 9580 | -{ |
| 9581 | - yaffs_CheckpointValidity cp; |
| 9582 | - int ok; |
| 9583 | + /* If this is the block being garbage collected then stop gc'ing this block */ |
| 9584 | + if(block_no == dev->gc_block) |
| 9585 | + dev->gc_block = 0; |
| 9586 | |
| 9587 | - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 9588 | + /* If this block is currently the best candidate for gc then drop as a candidate */ |
| 9589 | + if(block_no == dev->gc_dirtiest){ |
| 9590 | + dev->gc_dirtiest = 0; |
| 9591 | + dev->gc_pages_in_use = 0; |
| 9592 | + } |
| 9593 | |
| 9594 | - if (ok) |
| 9595 | - ok = (cp.structType == sizeof(cp)) && |
| 9596 | - (cp.magic == YAFFS_MAGIC) && |
| 9597 | - (cp.version == YAFFS_CHECKPOINT_VERSION) && |
| 9598 | - (cp.head == ((head) ? 1 : 0)); |
| 9599 | - return ok ? 1 : 0; |
| 9600 | -} |
| 9601 | + if (!bi->needs_retiring) { |
| 9602 | + yaffs2_checkpt_invalidate(dev); |
| 9603 | + erasedOk = yaffs_erase_block(dev, block_no); |
| 9604 | + if (!erasedOk) { |
| 9605 | + dev->n_erase_failures++; |
| 9606 | + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, |
| 9607 | + (TSTR("**>> Erasure failed %d" TENDSTR), block_no)); |
| 9608 | + } |
| 9609 | + } |
| 9610 | |
| 9611 | -static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, |
| 9612 | - yaffs_Device *dev) |
| 9613 | -{ |
| 9614 | - cp->nErasedBlocks = dev->nErasedBlocks; |
| 9615 | - cp->allocationBlock = dev->allocationBlock; |
| 9616 | - cp->allocationPage = dev->allocationPage; |
| 9617 | - cp->nFreeChunks = dev->nFreeChunks; |
| 9618 | + if (erasedOk && |
| 9619 | + ((yaffs_trace_mask & YAFFS_TRACE_ERASE) || !yaffs_skip_verification(dev))) { |
| 9620 | + int i; |
| 9621 | + for (i = 0; i < dev->param.chunks_per_block; i++) { |
| 9622 | + if (!yaffs_check_chunk_erased |
| 9623 | + (dev, block_no * dev->param.chunks_per_block + i)) { |
| 9624 | + T(YAFFS_TRACE_ERROR, |
| 9625 | + (TSTR |
| 9626 | + (">>Block %d erasure supposedly OK, but chunk %d not erased" |
| 9627 | + TENDSTR), block_no, i)); |
| 9628 | + } |
| 9629 | + } |
| 9630 | + } |
| 9631 | + |
| 9632 | + if (erasedOk) { |
| 9633 | + /* Clean it up... */ |
| 9634 | + bi->block_state = YAFFS_BLOCK_STATE_EMPTY; |
| 9635 | + bi->seq_number = 0; |
| 9636 | + dev->n_erased_blocks++; |
| 9637 | + bi->pages_in_use = 0; |
| 9638 | + bi->soft_del_pages = 0; |
| 9639 | + bi->has_shrink_hdr = 0; |
| 9640 | + bi->skip_erased_check = 1; /* This is clean, so no need to check */ |
| 9641 | + bi->gc_prioritise = 0; |
| 9642 | + yaffs_clear_chunk_bits(dev, block_no); |
| 9643 | |
| 9644 | - cp->nDeletedFiles = dev->nDeletedFiles; |
| 9645 | - cp->nUnlinkedFiles = dev->nUnlinkedFiles; |
| 9646 | - cp->nBackgroundDeletions = dev->nBackgroundDeletions; |
| 9647 | - cp->sequenceNumber = dev->sequenceNumber; |
| 9648 | - cp->oldestDirtySequence = dev->oldestDirtySequence; |
| 9649 | + T(YAFFS_TRACE_ERASE, |
| 9650 | + (TSTR("Erased block %d" TENDSTR), block_no)); |
| 9651 | + } else { |
| 9652 | + dev->n_free_chunks -= dev->param.chunks_per_block; /* We lost a block of free space */ |
| 9653 | |
| 9654 | + yaffs_retire_block(dev, block_no); |
| 9655 | + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, |
| 9656 | + (TSTR("**>> Block %d retired" TENDSTR), block_no)); |
| 9657 | + } |
| 9658 | } |
| 9659 | |
| 9660 | -static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev, |
| 9661 | - yaffs_CheckpointDevice *cp) |
| 9662 | +static int yaffs_find_alloc_block(yaffs_dev_t *dev) |
| 9663 | { |
| 9664 | - dev->nErasedBlocks = cp->nErasedBlocks; |
| 9665 | - dev->allocationBlock = cp->allocationBlock; |
| 9666 | - dev->allocationPage = cp->allocationPage; |
| 9667 | - dev->nFreeChunks = cp->nFreeChunks; |
| 9668 | - |
| 9669 | - dev->nDeletedFiles = cp->nDeletedFiles; |
| 9670 | - dev->nUnlinkedFiles = cp->nUnlinkedFiles; |
| 9671 | - dev->nBackgroundDeletions = cp->nBackgroundDeletions; |
| 9672 | - dev->sequenceNumber = cp->sequenceNumber; |
| 9673 | - dev->oldestDirtySequence = cp->oldestDirtySequence; |
| 9674 | -} |
| 9675 | + int i; |
| 9676 | |
| 9677 | + yaffs_block_info_t *bi; |
| 9678 | |
| 9679 | -static int yaffs_WriteCheckpointDevice(yaffs_Device *dev) |
| 9680 | -{ |
| 9681 | - yaffs_CheckpointDevice cp; |
| 9682 | - __u32 nBytes; |
| 9683 | - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); |
| 9684 | + if (dev->n_erased_blocks < 1) { |
| 9685 | + /* Hoosterman we've got a problem. |
| 9686 | + * Can't get space to gc |
| 9687 | + */ |
| 9688 | + T(YAFFS_TRACE_ERROR, |
| 9689 | + (TSTR("yaffs tragedy: no more erased blocks" TENDSTR))); |
| 9690 | |
| 9691 | - int ok; |
| 9692 | + return -1; |
| 9693 | + } |
| 9694 | |
| 9695 | - /* Write device runtime values*/ |
| 9696 | - yaffs_DeviceToCheckpointDevice(&cp, dev); |
| 9697 | - cp.structType = sizeof(cp); |
| 9698 | + /* Find an empty block. */ |
| 9699 | |
| 9700 | - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 9701 | + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { |
| 9702 | + dev->alloc_block_finder++; |
| 9703 | + if (dev->alloc_block_finder < dev->internal_start_block |
| 9704 | + || dev->alloc_block_finder > dev->internal_end_block) { |
| 9705 | + dev->alloc_block_finder = dev->internal_start_block; |
| 9706 | + } |
| 9707 | |
| 9708 | - /* Write block info */ |
| 9709 | - if (ok) { |
| 9710 | - nBytes = nBlocks * sizeof(yaffs_BlockInfo); |
| 9711 | - ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes); |
| 9712 | + bi = yaffs_get_block_info(dev, dev->alloc_block_finder); |
| 9713 | + |
| 9714 | + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { |
| 9715 | + bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING; |
| 9716 | + dev->seq_number++; |
| 9717 | + bi->seq_number = dev->seq_number; |
| 9718 | + dev->n_erased_blocks--; |
| 9719 | + T(YAFFS_TRACE_ALLOCATE, |
| 9720 | + (TSTR("Allocated block %d, seq %d, %d left" TENDSTR), |
| 9721 | + dev->alloc_block_finder, dev->seq_number, |
| 9722 | + dev->n_erased_blocks)); |
| 9723 | + return dev->alloc_block_finder; |
| 9724 | + } |
| 9725 | } |
| 9726 | |
| 9727 | - /* Write chunk bits */ |
| 9728 | - if (ok) { |
| 9729 | - nBytes = nBlocks * dev->chunkBitmapStride; |
| 9730 | - ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes); |
| 9731 | - } |
| 9732 | - return ok ? 1 : 0; |
| 9733 | + T(YAFFS_TRACE_ALWAYS, |
| 9734 | + (TSTR |
| 9735 | + ("yaffs tragedy: no more erased blocks, but there should have been %d" |
| 9736 | + TENDSTR), dev->n_erased_blocks)); |
| 9737 | |
| 9738 | + return -1; |
| 9739 | } |
| 9740 | |
| 9741 | -static int yaffs_ReadCheckpointDevice(yaffs_Device *dev) |
| 9742 | + |
| 9743 | +/* |
| 9744 | + * Check if there's space to allocate... |
| 9745 | + * Thinks.... do we need top make this ths same as yaffs_get_free_chunks()? |
| 9746 | + */ |
| 9747 | +int yaffs_check_alloc_available(yaffs_dev_t *dev, int n_chunks) |
| 9748 | { |
| 9749 | - yaffs_CheckpointDevice cp; |
| 9750 | - __u32 nBytes; |
| 9751 | - __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); |
| 9752 | + int reservedChunks; |
| 9753 | + int reservedBlocks = dev->param.n_reserved_blocks; |
| 9754 | + int checkpointBlocks; |
| 9755 | |
| 9756 | - int ok; |
| 9757 | + checkpointBlocks = yaffs_calc_checkpt_blocks_required(dev); |
| 9758 | |
| 9759 | - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 9760 | - if (!ok) |
| 9761 | - return 0; |
| 9762 | + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.chunks_per_block); |
| 9763 | |
| 9764 | - if (cp.structType != sizeof(cp)) |
| 9765 | - return 0; |
| 9766 | + return (dev->n_free_chunks > (reservedChunks + n_chunks)); |
| 9767 | +} |
| 9768 | + |
| 9769 | +static int yaffs_alloc_chunk(yaffs_dev_t *dev, int useReserve, |
| 9770 | + yaffs_block_info_t **blockUsedPtr) |
| 9771 | +{ |
| 9772 | + int retVal; |
| 9773 | + yaffs_block_info_t *bi; |
| 9774 | + |
| 9775 | + if (dev->alloc_block < 0) { |
| 9776 | + /* Get next block to allocate off */ |
| 9777 | + dev->alloc_block = yaffs_find_alloc_block(dev); |
| 9778 | + dev->alloc_page = 0; |
| 9779 | + } |
| 9780 | |
| 9781 | + if (!useReserve && !yaffs_check_alloc_available(dev, 1)) { |
| 9782 | + /* Not enough space to allocate unless we're allowed to use the reserve. */ |
| 9783 | + return -1; |
| 9784 | + } |
| 9785 | |
| 9786 | - yaffs_CheckpointDeviceToDevice(dev, &cp); |
| 9787 | + if (dev->n_erased_blocks < dev->param.n_reserved_blocks |
| 9788 | + && dev->alloc_page == 0) { |
| 9789 | + T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR))); |
| 9790 | + } |
| 9791 | |
| 9792 | - nBytes = nBlocks * sizeof(yaffs_BlockInfo); |
| 9793 | + /* Next page please.... */ |
| 9794 | + if (dev->alloc_block >= 0) { |
| 9795 | + bi = yaffs_get_block_info(dev, dev->alloc_block); |
| 9796 | |
| 9797 | - ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes); |
| 9798 | + retVal = (dev->alloc_block * dev->param.chunks_per_block) + |
| 9799 | + dev->alloc_page; |
| 9800 | + bi->pages_in_use++; |
| 9801 | + yaffs_set_chunk_bit(dev, dev->alloc_block, |
| 9802 | + dev->alloc_page); |
| 9803 | |
| 9804 | - if (!ok) |
| 9805 | - return 0; |
| 9806 | - nBytes = nBlocks * dev->chunkBitmapStride; |
| 9807 | + dev->alloc_page++; |
| 9808 | |
| 9809 | - ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes); |
| 9810 | + dev->n_free_chunks--; |
| 9811 | |
| 9812 | - return ok ? 1 : 0; |
| 9813 | -} |
| 9814 | + /* If the block is full set the state to full */ |
| 9815 | + if (dev->alloc_page >= dev->param.chunks_per_block) { |
| 9816 | + bi->block_state = YAFFS_BLOCK_STATE_FULL; |
| 9817 | + dev->alloc_block = -1; |
| 9818 | + } |
| 9819 | |
| 9820 | -static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp, |
| 9821 | - yaffs_Object *obj) |
| 9822 | -{ |
| 9823 | + if (blockUsedPtr) |
| 9824 | + *blockUsedPtr = bi; |
| 9825 | + |
| 9826 | + return retVal; |
| 9827 | + } |
| 9828 | |
| 9829 | - cp->objectId = obj->objectId; |
| 9830 | - cp->parentId = (obj->parent) ? obj->parent->objectId : 0; |
| 9831 | - cp->hdrChunk = obj->hdrChunk; |
| 9832 | - cp->variantType = obj->variantType; |
| 9833 | - cp->deleted = obj->deleted; |
| 9834 | - cp->softDeleted = obj->softDeleted; |
| 9835 | - cp->unlinked = obj->unlinked; |
| 9836 | - cp->fake = obj->fake; |
| 9837 | - cp->renameAllowed = obj->renameAllowed; |
| 9838 | - cp->unlinkAllowed = obj->unlinkAllowed; |
| 9839 | - cp->serial = obj->serial; |
| 9840 | - cp->nDataChunks = obj->nDataChunks; |
| 9841 | + T(YAFFS_TRACE_ERROR, |
| 9842 | + (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); |
| 9843 | |
| 9844 | - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) |
| 9845 | - cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize; |
| 9846 | - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) |
| 9847 | - cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId; |
| 9848 | + return -1; |
| 9849 | } |
| 9850 | |
| 9851 | -static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp) |
| 9852 | +static int yaffs_get_erased_chunks(yaffs_dev_t *dev) |
| 9853 | { |
| 9854 | + int n; |
| 9855 | |
| 9856 | - yaffs_Object *parent; |
| 9857 | + n = dev->n_erased_blocks * dev->param.chunks_per_block; |
| 9858 | |
| 9859 | - if (obj->variantType != cp->variantType) { |
| 9860 | - T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d " |
| 9861 | - TCONT("chunk %d does not match existing object type %d") |
| 9862 | - TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk, |
| 9863 | - obj->variantType)); |
| 9864 | - return 0; |
| 9865 | - } |
| 9866 | + if (dev->alloc_block > 0) |
| 9867 | + n += (dev->param.chunks_per_block - dev->alloc_page); |
| 9868 | |
| 9869 | - obj->objectId = cp->objectId; |
| 9870 | + return n; |
| 9871 | |
| 9872 | - if (cp->parentId) |
| 9873 | - parent = yaffs_FindOrCreateObjectByNumber( |
| 9874 | - obj->myDev, |
| 9875 | - cp->parentId, |
| 9876 | - YAFFS_OBJECT_TYPE_DIRECTORY); |
| 9877 | - else |
| 9878 | - parent = NULL; |
| 9879 | +} |
| 9880 | |
| 9881 | - if (parent) { |
| 9882 | - if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 9883 | - T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d" |
| 9884 | - TCONT(" chunk %d Parent type, %d, not directory") |
| 9885 | - TENDSTR), |
| 9886 | - cp->objectId, cp->parentId, cp->variantType, |
| 9887 | - cp->hdrChunk, parent->variantType)); |
| 9888 | - return 0; |
| 9889 | +/* |
| 9890 | + * yaffs_skip_rest_of_block() skips over the rest of the allocation block |
| 9891 | + * if we don't want to write to it. |
| 9892 | + */ |
| 9893 | +void yaffs_skip_rest_of_block(yaffs_dev_t *dev) |
| 9894 | +{ |
| 9895 | + if(dev->alloc_block > 0){ |
| 9896 | + yaffs_block_info_t *bi = yaffs_get_block_info(dev, dev->alloc_block); |
| 9897 | + if(bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING){ |
| 9898 | + bi->block_state = YAFFS_BLOCK_STATE_FULL; |
| 9899 | + dev->alloc_block = -1; |
| 9900 | } |
| 9901 | - yaffs_AddObjectToDirectory(parent, obj); |
| 9902 | } |
| 9903 | - |
| 9904 | - obj->hdrChunk = cp->hdrChunk; |
| 9905 | - obj->variantType = cp->variantType; |
| 9906 | - obj->deleted = cp->deleted; |
| 9907 | - obj->softDeleted = cp->softDeleted; |
| 9908 | - obj->unlinked = cp->unlinked; |
| 9909 | - obj->fake = cp->fake; |
| 9910 | - obj->renameAllowed = cp->renameAllowed; |
| 9911 | - obj->unlinkAllowed = cp->unlinkAllowed; |
| 9912 | - obj->serial = cp->serial; |
| 9913 | - obj->nDataChunks = cp->nDataChunks; |
| 9914 | - |
| 9915 | - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) |
| 9916 | - obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId; |
| 9917 | - else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) |
| 9918 | - obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId; |
| 9919 | - |
| 9920 | - if (obj->hdrChunk > 0) |
| 9921 | - obj->lazyLoaded = 1; |
| 9922 | - return 1; |
| 9923 | } |
| 9924 | |
| 9925 | |
| 9926 | - |
| 9927 | -static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn, |
| 9928 | - __u32 level, int chunkOffset) |
| 9929 | +static int yaffs_gc_block(yaffs_dev_t *dev, int block, |
| 9930 | + int wholeBlock) |
| 9931 | { |
| 9932 | + int oldChunk; |
| 9933 | + int newChunk; |
| 9934 | + int mark_flash; |
| 9935 | + int retVal = YAFFS_OK; |
| 9936 | int i; |
| 9937 | - yaffs_Device *dev = in->myDev; |
| 9938 | - int ok = 1; |
| 9939 | - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; |
| 9940 | - |
| 9941 | - if (tnodeSize < sizeof(yaffs_Tnode)) |
| 9942 | - tnodeSize = sizeof(yaffs_Tnode); |
| 9943 | + int isCheckpointBlock; |
| 9944 | + int matchingChunk; |
| 9945 | + int maxCopies; |
| 9946 | |
| 9947 | + int chunksBefore = yaffs_get_erased_chunks(dev); |
| 9948 | + int chunksAfter; |
| 9949 | |
| 9950 | - if (tn) { |
| 9951 | - if (level > 0) { |
| 9952 | + yaffs_ext_tags tags; |
| 9953 | |
| 9954 | - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { |
| 9955 | - if (tn->internal[i]) { |
| 9956 | - ok = yaffs_CheckpointTnodeWorker(in, |
| 9957 | - tn->internal[i], |
| 9958 | - level - 1, |
| 9959 | - (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i); |
| 9960 | - } |
| 9961 | - } |
| 9962 | - } else if (level == 0) { |
| 9963 | - __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS; |
| 9964 | - ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset)); |
| 9965 | - if (ok) |
| 9966 | - ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize); |
| 9967 | - } |
| 9968 | - } |
| 9969 | + yaffs_block_info_t *bi = yaffs_get_block_info(dev, block); |
| 9970 | |
| 9971 | - return ok; |
| 9972 | + yaffs_obj_t *object; |
| 9973 | |
| 9974 | -} |
| 9975 | + isCheckpointBlock = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT); |
| 9976 | |
| 9977 | -static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj) |
| 9978 | -{ |
| 9979 | - __u32 endMarker = ~0; |
| 9980 | - int ok = 1; |
| 9981 | |
| 9982 | - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) { |
| 9983 | - ok = yaffs_CheckpointTnodeWorker(obj, |
| 9984 | - obj->variant.fileVariant.top, |
| 9985 | - obj->variant.fileVariant.topLevel, |
| 9986 | - 0); |
| 9987 | - if (ok) |
| 9988 | - ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) == |
| 9989 | - sizeof(endMarker)); |
| 9990 | - } |
| 9991 | + T(YAFFS_TRACE_TRACING, |
| 9992 | + (TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR), |
| 9993 | + block, |
| 9994 | + bi->pages_in_use, |
| 9995 | + bi->has_shrink_hdr, |
| 9996 | + wholeBlock)); |
| 9997 | |
| 9998 | - return ok ? 1 : 0; |
| 9999 | -} |
| 10000 | + /*yaffs_verify_free_chunks(dev); */ |
| 10001 | |
| 10002 | -static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj) |
| 10003 | -{ |
| 10004 | - __u32 baseChunk; |
| 10005 | - int ok = 1; |
| 10006 | - yaffs_Device *dev = obj->myDev; |
| 10007 | - yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant; |
| 10008 | - yaffs_Tnode *tn; |
| 10009 | - int nread = 0; |
| 10010 | - int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; |
| 10011 | + if(bi->block_state == YAFFS_BLOCK_STATE_FULL) |
| 10012 | + bi->block_state = YAFFS_BLOCK_STATE_COLLECTING; |
| 10013 | + |
| 10014 | + bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */ |
| 10015 | |
| 10016 | - if (tnodeSize < sizeof(yaffs_Tnode)) |
| 10017 | - tnodeSize = sizeof(yaffs_Tnode); |
| 10018 | + dev->gc_disable = 1; |
| 10019 | |
| 10020 | - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk)); |
| 10021 | + if (isCheckpointBlock || |
| 10022 | + !yaffs_still_some_chunks(dev, block)) { |
| 10023 | + T(YAFFS_TRACE_TRACING, |
| 10024 | + (TSTR |
| 10025 | + ("Collecting block %d that has no chunks in use" TENDSTR), |
| 10026 | + block)); |
| 10027 | + yaffs_block_became_dirty(dev, block); |
| 10028 | + } else { |
| 10029 | |
| 10030 | - while (ok && (~baseChunk)) { |
| 10031 | - nread++; |
| 10032 | - /* Read level 0 tnode */ |
| 10033 | + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__); |
| 10034 | |
| 10035 | + yaffs_verify_blk(dev, bi, block); |
| 10036 | |
| 10037 | - tn = yaffs_GetTnodeRaw(dev); |
| 10038 | - if (tn) |
| 10039 | - ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize); |
| 10040 | - else |
| 10041 | - ok = 0; |
| 10042 | + maxCopies = (wholeBlock) ? dev->param.chunks_per_block : 5; |
| 10043 | + oldChunk = block * dev->param.chunks_per_block + dev->gc_chunk; |
| 10044 | |
| 10045 | - if (tn && ok) |
| 10046 | - ok = yaffs_AddOrFindLevel0Tnode(dev, |
| 10047 | - fileStructPtr, |
| 10048 | - baseChunk, |
| 10049 | - tn) ? 1 : 0; |
| 10050 | + for (/* init already done */; |
| 10051 | + retVal == YAFFS_OK && |
| 10052 | + dev->gc_chunk < dev->param.chunks_per_block && |
| 10053 | + (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) && |
| 10054 | + maxCopies > 0; |
| 10055 | + dev->gc_chunk++, oldChunk++) { |
| 10056 | + if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) { |
| 10057 | |
| 10058 | - if (ok) |
| 10059 | - ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk)); |
| 10060 | + /* This page is in use and might need to be copied off */ |
| 10061 | |
| 10062 | - } |
| 10063 | + maxCopies--; |
| 10064 | |
| 10065 | - T(YAFFS_TRACE_CHECKPOINT, ( |
| 10066 | - TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR), |
| 10067 | - nread, baseChunk, ok)); |
| 10068 | + mark_flash = 1; |
| 10069 | |
| 10070 | - return ok ? 1 : 0; |
| 10071 | -} |
| 10072 | + yaffs_init_tags(&tags); |
| 10073 | |
| 10074 | + yaffs_rd_chunk_tags_nand(dev, oldChunk, |
| 10075 | + buffer, &tags); |
| 10076 | |
| 10077 | -static int yaffs_WriteCheckpointObjects(yaffs_Device *dev) |
| 10078 | -{ |
| 10079 | - yaffs_Object *obj; |
| 10080 | - yaffs_CheckpointObject cp; |
| 10081 | - int i; |
| 10082 | - int ok = 1; |
| 10083 | - struct ylist_head *lh; |
| 10084 | + object = |
| 10085 | + yaffs_find_by_number(dev, |
| 10086 | + tags.obj_id); |
| 10087 | |
| 10088 | + T(YAFFS_TRACE_GC_DETAIL, |
| 10089 | + (TSTR |
| 10090 | + ("Collecting chunk in block %d, %d %d %d " TENDSTR), |
| 10091 | + dev->gc_chunk, tags.obj_id, tags.chunk_id, |
| 10092 | + tags.n_bytes)); |
| 10093 | |
| 10094 | - /* Iterate through the objects in each hash entry, |
| 10095 | - * dumping them to the checkpointing stream. |
| 10096 | - */ |
| 10097 | + if (object && !yaffs_skip_verification(dev)) { |
| 10098 | + if (tags.chunk_id == 0) |
| 10099 | + matchingChunk = object->hdr_chunk; |
| 10100 | + else if (object->soft_del) |
| 10101 | + matchingChunk = oldChunk; /* Defeat the test */ |
| 10102 | + else |
| 10103 | + matchingChunk = yaffs_find_chunk_in_file(object, tags.chunk_id, NULL); |
| 10104 | |
| 10105 | - for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) { |
| 10106 | - ylist_for_each(lh, &dev->objectBucket[i].list) { |
| 10107 | - if (lh) { |
| 10108 | - obj = ylist_entry(lh, yaffs_Object, hashLink); |
| 10109 | - if (!obj->deferedFree) { |
| 10110 | - yaffs_ObjectToCheckpointObject(&cp, obj); |
| 10111 | - cp.structType = sizeof(cp); |
| 10112 | - |
| 10113 | - T(YAFFS_TRACE_CHECKPOINT, ( |
| 10114 | - TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR), |
| 10115 | - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj)); |
| 10116 | + if (oldChunk != matchingChunk) |
| 10117 | + T(YAFFS_TRACE_ERROR, |
| 10118 | + (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR), |
| 10119 | + oldChunk, matchingChunk, tags.obj_id, tags.chunk_id)); |
| 10120 | |
| 10121 | - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 10122 | + } |
| 10123 | |
| 10124 | - if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE) |
| 10125 | - ok = yaffs_WriteCheckpointTnodes(obj); |
| 10126 | + if (!object) { |
| 10127 | + T(YAFFS_TRACE_ERROR, |
| 10128 | + (TSTR |
| 10129 | + ("page %d in gc has no object: %d %d %d " |
| 10130 | + TENDSTR), oldChunk, |
| 10131 | + tags.obj_id, tags.chunk_id, tags.n_bytes)); |
| 10132 | } |
| 10133 | - } |
| 10134 | - } |
| 10135 | - } |
| 10136 | |
| 10137 | - /* Dump end of list */ |
| 10138 | - memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject)); |
| 10139 | - cp.structType = sizeof(cp); |
| 10140 | + if (object && |
| 10141 | + object->deleted && |
| 10142 | + object->soft_del && |
| 10143 | + tags.chunk_id != 0) { |
| 10144 | + /* Data chunk in a soft deleted file, throw it away |
| 10145 | + * It's a soft deleted data chunk, |
| 10146 | + * No need to copy this, just forget about it and |
| 10147 | + * fix up the object. |
| 10148 | + */ |
| 10149 | + |
| 10150 | + /* Free chunks already includes softdeleted chunks. |
| 10151 | + * How ever this chunk is going to soon be really deleted |
| 10152 | + * which will increment free chunks. |
| 10153 | + * We have to decrement free chunks so this works out properly. |
| 10154 | + */ |
| 10155 | + dev->n_free_chunks--; |
| 10156 | + bi->soft_del_pages--; |
| 10157 | + |
| 10158 | + object->n_data_chunks--; |
| 10159 | |
| 10160 | - if (ok) |
| 10161 | - ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 10162 | + if (object->n_data_chunks <= 0) { |
| 10163 | + /* remeber to clean up the object */ |
| 10164 | + dev->gc_cleanup_list[dev->n_clean_ups] = |
| 10165 | + tags.obj_id; |
| 10166 | + dev->n_clean_ups++; |
| 10167 | + } |
| 10168 | + mark_flash = 0; |
| 10169 | + } else if (0) { |
| 10170 | + /* Todo object && object->deleted && object->n_data_chunks == 0 */ |
| 10171 | + /* Deleted object header with no data chunks. |
| 10172 | + * Can be discarded and the file deleted. |
| 10173 | + */ |
| 10174 | + object->hdr_chunk = 0; |
| 10175 | + yaffs_free_tnode(object->my_dev, |
| 10176 | + object->variant. |
| 10177 | + file_variant.top); |
| 10178 | + object->variant.file_variant.top = NULL; |
| 10179 | + yaffs_generic_obj_del(object); |
| 10180 | |
| 10181 | - return ok ? 1 : 0; |
| 10182 | -} |
| 10183 | + } else if (object) { |
| 10184 | + /* It's either a data chunk in a live file or |
| 10185 | + * an ObjectHeader, so we're interested in it. |
| 10186 | + * NB Need to keep the ObjectHeaders of deleted files |
| 10187 | + * until the whole file has been deleted off |
| 10188 | + */ |
| 10189 | + tags.serial_number++; |
| 10190 | |
| 10191 | -static int yaffs_ReadCheckpointObjects(yaffs_Device *dev) |
| 10192 | -{ |
| 10193 | - yaffs_Object *obj; |
| 10194 | - yaffs_CheckpointObject cp; |
| 10195 | - int ok = 1; |
| 10196 | - int done = 0; |
| 10197 | - yaffs_Object *hardList = NULL; |
| 10198 | + dev->n_gc_copies++; |
| 10199 | |
| 10200 | - while (ok && !done) { |
| 10201 | - ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 10202 | - if (cp.structType != sizeof(cp)) { |
| 10203 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR), |
| 10204 | - cp.structType, sizeof(cp), ok)); |
| 10205 | - ok = 0; |
| 10206 | - } |
| 10207 | - |
| 10208 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR), |
| 10209 | - cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk)); |
| 10210 | - |
| 10211 | - if (ok && cp.objectId == ~0) |
| 10212 | - done = 1; |
| 10213 | - else if (ok) { |
| 10214 | - obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType); |
| 10215 | - if (obj) { |
| 10216 | - ok = yaffs_CheckpointObjectToObject(obj, &cp); |
| 10217 | - if (!ok) |
| 10218 | - break; |
| 10219 | - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) { |
| 10220 | - ok = yaffs_ReadCheckpointTnodes(obj); |
| 10221 | - } else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { |
| 10222 | - obj->hardLinks.next = |
| 10223 | - (struct ylist_head *) hardList; |
| 10224 | - hardList = obj; |
| 10225 | - } |
| 10226 | - } else |
| 10227 | - ok = 0; |
| 10228 | - } |
| 10229 | - } |
| 10230 | + if (tags.chunk_id == 0) { |
| 10231 | + /* It is an object Id, |
| 10232 | + * We need to nuke the shrinkheader flags first |
| 10233 | + * Also need to clean up shadowing. |
| 10234 | + * We no longer want the shrinkHeader flag since its work is done |
| 10235 | + * and if it is left in place it will mess up scanning. |
| 10236 | + */ |
| 10237 | |
| 10238 | - if (ok) |
| 10239 | - yaffs_HardlinkFixup(dev, hardList); |
| 10240 | + yaffs_obj_header *oh; |
| 10241 | + oh = (yaffs_obj_header *)buffer; |
| 10242 | |
| 10243 | - return ok ? 1 : 0; |
| 10244 | -} |
| 10245 | + oh->is_shrink = 0; |
| 10246 | + tags.extra_is_shrink = 0; |
| 10247 | |
| 10248 | -static int yaffs_WriteCheckpointSum(yaffs_Device *dev) |
| 10249 | -{ |
| 10250 | - __u32 checkpointSum; |
| 10251 | - int ok; |
| 10252 | + oh->shadows_obj = 0; |
| 10253 | + oh->inband_shadowed_obj_id = 0; |
| 10254 | + tags.extra_shadows = 0; |
| 10255 | + |
| 10256 | + /* Update file size */ |
| 10257 | + if(object->variant_type == YAFFS_OBJECT_TYPE_FILE){ |
| 10258 | + oh->file_size = object->variant.file_variant.file_size; |
| 10259 | + tags.extra_length = oh->file_size; |
| 10260 | + } |
| 10261 | + |
| 10262 | + yaffs_verify_oh(object, oh, &tags, 1); |
| 10263 | + newChunk = |
| 10264 | + yaffs_write_new_chunk(dev,(__u8 *) oh, &tags, 1); |
| 10265 | + } else |
| 10266 | + newChunk = |
| 10267 | + yaffs_write_new_chunk(dev, buffer, &tags, 1); |
| 10268 | + |
| 10269 | + if (newChunk < 0) { |
| 10270 | + retVal = YAFFS_FAIL; |
| 10271 | + } else { |
| 10272 | |
| 10273 | - yaffs_GetCheckpointSum(dev, &checkpointSum); |
| 10274 | + /* Ok, now fix up the Tnodes etc. */ |
| 10275 | |
| 10276 | - ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum)); |
| 10277 | + if (tags.chunk_id == 0) { |
| 10278 | + /* It's a header */ |
| 10279 | + object->hdr_chunk = newChunk; |
| 10280 | + object->serial = tags.serial_number; |
| 10281 | + } else { |
| 10282 | + /* It's a data chunk */ |
| 10283 | + int ok; |
| 10284 | + ok = yaffs_put_chunk_in_file |
| 10285 | + (object, |
| 10286 | + tags.chunk_id, |
| 10287 | + newChunk, 0); |
| 10288 | + } |
| 10289 | + } |
| 10290 | + } |
| 10291 | |
| 10292 | - if (!ok) |
| 10293 | - return 0; |
| 10294 | + if (retVal == YAFFS_OK) |
| 10295 | + yaffs_chunk_del(dev, oldChunk, mark_flash, __LINE__); |
| 10296 | |
| 10297 | - return 1; |
| 10298 | -} |
| 10299 | + } |
| 10300 | + } |
| 10301 | |
| 10302 | -static int yaffs_ReadCheckpointSum(yaffs_Device *dev) |
| 10303 | -{ |
| 10304 | - __u32 checkpointSum0; |
| 10305 | - __u32 checkpointSum1; |
| 10306 | - int ok; |
| 10307 | + yaffs_release_temp_buffer(dev, buffer, __LINE__); |
| 10308 | |
| 10309 | - yaffs_GetCheckpointSum(dev, &checkpointSum0); |
| 10310 | |
| 10311 | - ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1)); |
| 10312 | |
| 10313 | - if (!ok) |
| 10314 | - return 0; |
| 10315 | + } |
| 10316 | |
| 10317 | - if (checkpointSum0 != checkpointSum1) |
| 10318 | - return 0; |
| 10319 | + yaffs_verify_collected_blk(dev, bi, block); |
| 10320 | |
| 10321 | - return 1; |
| 10322 | -} |
| 10323 | |
| 10324 | |
| 10325 | -static int yaffs_WriteCheckpointData(yaffs_Device *dev) |
| 10326 | -{ |
| 10327 | - int ok = 1; |
| 10328 | + if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { |
| 10329 | + /* |
| 10330 | + * The gc did not complete. Set block state back to FULL |
| 10331 | + * because checkpointing does not restore gc. |
| 10332 | + */ |
| 10333 | + bi->block_state = YAFFS_BLOCK_STATE_FULL; |
| 10334 | + } else { |
| 10335 | + /* The gc completed. */ |
| 10336 | + /* Do any required cleanups */ |
| 10337 | + for (i = 0; i < dev->n_clean_ups; i++) { |
| 10338 | + /* Time to delete the file too */ |
| 10339 | + object = |
| 10340 | + yaffs_find_by_number(dev, |
| 10341 | + dev->gc_cleanup_list[i]); |
| 10342 | + if (object) { |
| 10343 | + yaffs_free_tnode(dev, |
| 10344 | + object->variant.file_variant. |
| 10345 | + top); |
| 10346 | + object->variant.file_variant.top = NULL; |
| 10347 | + T(YAFFS_TRACE_GC, |
| 10348 | + (TSTR |
| 10349 | + ("yaffs: About to finally delete object %d" |
| 10350 | + TENDSTR), object->obj_id)); |
| 10351 | + yaffs_generic_obj_del(object); |
| 10352 | + object->my_dev->n_deleted_files--; |
| 10353 | + } |
| 10354 | |
| 10355 | - if (dev->skipCheckpointWrite || !dev->isYaffs2) { |
| 10356 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR))); |
| 10357 | - ok = 0; |
| 10358 | - } |
| 10359 | + } |
| 10360 | |
| 10361 | - if (ok) |
| 10362 | - ok = yaffs_CheckpointOpen(dev, 1); |
| 10363 | |
| 10364 | - if (ok) { |
| 10365 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); |
| 10366 | - ok = yaffs_WriteCheckpointValidityMarker(dev, 1); |
| 10367 | - } |
| 10368 | - if (ok) { |
| 10369 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR))); |
| 10370 | - ok = yaffs_WriteCheckpointDevice(dev); |
| 10371 | - } |
| 10372 | - if (ok) { |
| 10373 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR))); |
| 10374 | - ok = yaffs_WriteCheckpointObjects(dev); |
| 10375 | - } |
| 10376 | - if (ok) { |
| 10377 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); |
| 10378 | - ok = yaffs_WriteCheckpointValidityMarker(dev, 0); |
| 10379 | + chunksAfter = yaffs_get_erased_chunks(dev); |
| 10380 | + if (chunksBefore >= chunksAfter) { |
| 10381 | + T(YAFFS_TRACE_GC, |
| 10382 | + (TSTR |
| 10383 | + ("gc did not increase free chunks before %d after %d" |
| 10384 | + TENDSTR), chunksBefore, chunksAfter)); |
| 10385 | + } |
| 10386 | + dev->gc_block = 0; |
| 10387 | + dev->gc_chunk = 0; |
| 10388 | + dev->n_clean_ups = 0; |
| 10389 | } |
| 10390 | |
| 10391 | - if (ok) |
| 10392 | - ok = yaffs_WriteCheckpointSum(dev); |
| 10393 | - |
| 10394 | - if (!yaffs_CheckpointClose(dev)) |
| 10395 | - ok = 0; |
| 10396 | - |
| 10397 | - if (ok) |
| 10398 | - dev->isCheckpointed = 1; |
| 10399 | - else |
| 10400 | - dev->isCheckpointed = 0; |
| 10401 | + dev->gc_disable = 0; |
| 10402 | |
| 10403 | - return dev->isCheckpointed; |
| 10404 | + return retVal; |
| 10405 | } |
| 10406 | |
| 10407 | -static int yaffs_ReadCheckpointData(yaffs_Device *dev) |
| 10408 | +/* |
| 10409 | + * FindBlockForgarbageCollection is used to select the dirtiest block (or close enough) |
| 10410 | + * for garbage collection. |
| 10411 | + */ |
| 10412 | + |
| 10413 | +static unsigned yaffs_find_gc_block(yaffs_dev_t *dev, |
| 10414 | + int aggressive, |
| 10415 | + int background) |
| 10416 | { |
| 10417 | - int ok = 1; |
| 10418 | + int i; |
| 10419 | + int iterations; |
| 10420 | + unsigned selected = 0; |
| 10421 | + int prioritised = 0; |
| 10422 | + int prioritisedExists = 0; |
| 10423 | + yaffs_block_info_t *bi; |
| 10424 | + int threshold; |
| 10425 | |
| 10426 | - if (dev->skipCheckpointRead || !dev->isYaffs2) { |
| 10427 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR))); |
| 10428 | - ok = 0; |
| 10429 | - } |
| 10430 | + /* First let's see if we need to grab a prioritised block */ |
| 10431 | + if (dev->has_pending_prioritised_gc && !aggressive) { |
| 10432 | + dev->gc_dirtiest = 0; |
| 10433 | + bi = dev->block_info; |
| 10434 | + for (i = dev->internal_start_block; |
| 10435 | + i <= dev->internal_end_block && !selected; |
| 10436 | + i++) { |
| 10437 | + |
| 10438 | + if (bi->gc_prioritise) { |
| 10439 | + prioritisedExists = 1; |
| 10440 | + if (bi->block_state == YAFFS_BLOCK_STATE_FULL && |
| 10441 | + yaffs_block_ok_for_gc(dev, bi)) { |
| 10442 | + selected = i; |
| 10443 | + prioritised = 1; |
| 10444 | + } |
| 10445 | + } |
| 10446 | + bi++; |
| 10447 | + } |
| 10448 | |
| 10449 | - if (ok) |
| 10450 | - ok = yaffs_CheckpointOpen(dev, 0); /* open for read */ |
| 10451 | + /* |
| 10452 | + * If there is a prioritised block and none was selected then |
| 10453 | + * this happened because there is at least one old dirty block gumming |
| 10454 | + * up the works. Let's gc the oldest dirty block. |
| 10455 | + */ |
| 10456 | |
| 10457 | - if (ok) { |
| 10458 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); |
| 10459 | - ok = yaffs_ReadCheckpointValidityMarker(dev, 1); |
| 10460 | - } |
| 10461 | - if (ok) { |
| 10462 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR))); |
| 10463 | - ok = yaffs_ReadCheckpointDevice(dev); |
| 10464 | - } |
| 10465 | - if (ok) { |
| 10466 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR))); |
| 10467 | - ok = yaffs_ReadCheckpointObjects(dev); |
| 10468 | - } |
| 10469 | - if (ok) { |
| 10470 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); |
| 10471 | - ok = yaffs_ReadCheckpointValidityMarker(dev, 0); |
| 10472 | - } |
| 10473 | + if(prioritisedExists && |
| 10474 | + !selected && |
| 10475 | + dev->oldest_dirty_block > 0) |
| 10476 | + selected = dev->oldest_dirty_block; |
| 10477 | |
| 10478 | - if (ok) { |
| 10479 | - ok = yaffs_ReadCheckpointSum(dev); |
| 10480 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok)); |
| 10481 | + if (!prioritisedExists) /* None found, so we can clear this */ |
| 10482 | + dev->has_pending_prioritised_gc = 0; |
| 10483 | } |
| 10484 | |
| 10485 | - if (!yaffs_CheckpointClose(dev)) |
| 10486 | - ok = 0; |
| 10487 | - |
| 10488 | - if (ok) |
| 10489 | - dev->isCheckpointed = 1; |
| 10490 | - else |
| 10491 | - dev->isCheckpointed = 0; |
| 10492 | - |
| 10493 | - return ok ? 1 : 0; |
| 10494 | + /* If we're doing aggressive GC then we are happy to take a less-dirty block, and |
| 10495 | + * search harder. |
| 10496 | + * else (we're doing a leasurely gc), then we only bother to do this if the |
| 10497 | + * block has only a few pages in use. |
| 10498 | + */ |
| 10499 | |
| 10500 | -} |
| 10501 | + if (!selected){ |
| 10502 | + int pagesUsed; |
| 10503 | + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1; |
| 10504 | + if (aggressive){ |
| 10505 | + threshold = dev->param.chunks_per_block; |
| 10506 | + iterations = nBlocks; |
| 10507 | + } else { |
| 10508 | + int maxThreshold; |
| 10509 | |
| 10510 | -static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) |
| 10511 | -{ |
| 10512 | - if (dev->isCheckpointed || |
| 10513 | - dev->blocksInCheckpoint > 0) { |
| 10514 | - dev->isCheckpointed = 0; |
| 10515 | - yaffs_CheckpointInvalidateStream(dev); |
| 10516 | - if (dev->superBlock && dev->markSuperBlockDirty) |
| 10517 | - dev->markSuperBlockDirty(dev->superBlock); |
| 10518 | - } |
| 10519 | -} |
| 10520 | + if(background) |
| 10521 | + maxThreshold = dev->param.chunks_per_block/2; |
| 10522 | + else |
| 10523 | + maxThreshold = dev->param.chunks_per_block/8; |
| 10524 | |
| 10525 | + if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD) |
| 10526 | + maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD; |
| 10527 | |
| 10528 | -int yaffs_CheckpointSave(yaffs_Device *dev) |
| 10529 | -{ |
| 10530 | + threshold = background ? |
| 10531 | + (dev->gc_not_done + 2) * 2 : 0; |
| 10532 | + if(threshold <YAFFS_GC_PASSIVE_THRESHOLD) |
| 10533 | + threshold = YAFFS_GC_PASSIVE_THRESHOLD; |
| 10534 | + if(threshold > maxThreshold) |
| 10535 | + threshold = maxThreshold; |
| 10536 | |
| 10537 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); |
| 10538 | + iterations = nBlocks / 16 + 1; |
| 10539 | + if (iterations > 100) |
| 10540 | + iterations = 100; |
| 10541 | + } |
| 10542 | |
| 10543 | - yaffs_VerifyObjects(dev); |
| 10544 | - yaffs_VerifyBlocks(dev); |
| 10545 | - yaffs_VerifyFreeChunks(dev); |
| 10546 | + for (i = 0; |
| 10547 | + i < iterations && |
| 10548 | + (dev->gc_dirtiest < 1 || |
| 10549 | + dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH); |
| 10550 | + i++) { |
| 10551 | + dev->gc_block_finder++; |
| 10552 | + if (dev->gc_block_finder < dev->internal_start_block || |
| 10553 | + dev->gc_block_finder > dev->internal_end_block) |
| 10554 | + dev->gc_block_finder = dev->internal_start_block; |
| 10555 | |
| 10556 | - if (!dev->isCheckpointed) { |
| 10557 | - yaffs_InvalidateCheckpoint(dev); |
| 10558 | - yaffs_WriteCheckpointData(dev); |
| 10559 | - } |
| 10560 | + bi = yaffs_get_block_info(dev, dev->gc_block_finder); |
| 10561 | |
| 10562 | - T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); |
| 10563 | + pagesUsed = bi->pages_in_use - bi->soft_del_pages; |
| 10564 | |
| 10565 | - return dev->isCheckpointed; |
| 10566 | -} |
| 10567 | + if (bi->block_state == YAFFS_BLOCK_STATE_FULL && |
| 10568 | + pagesUsed < dev->param.chunks_per_block && |
| 10569 | + (dev->gc_dirtiest < 1 || pagesUsed < dev->gc_pages_in_use) && |
| 10570 | + yaffs_block_ok_for_gc(dev, bi)) { |
| 10571 | + dev->gc_dirtiest = dev->gc_block_finder; |
| 10572 | + dev->gc_pages_in_use = pagesUsed; |
| 10573 | + } |
| 10574 | + } |
| 10575 | |
| 10576 | -int yaffs_CheckpointRestore(yaffs_Device *dev) |
| 10577 | -{ |
| 10578 | - int retval; |
| 10579 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); |
| 10580 | + if(dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold) |
| 10581 | + selected = dev->gc_dirtiest; |
| 10582 | + } |
| 10583 | |
| 10584 | - retval = yaffs_ReadCheckpointData(dev); |
| 10585 | + /* |
| 10586 | + * If nothing has been selected for a while, try selecting the oldest dirty |
| 10587 | + * because that's gumming up the works. |
| 10588 | + */ |
| 10589 | |
| 10590 | - if (dev->isCheckpointed) { |
| 10591 | - yaffs_VerifyObjects(dev); |
| 10592 | - yaffs_VerifyBlocks(dev); |
| 10593 | - yaffs_VerifyFreeChunks(dev); |
| 10594 | + if(!selected && dev->param.is_yaffs2 && |
| 10595 | + dev->gc_not_done >= ( background ? 10 : 20)){ |
| 10596 | + yaffs2_find_oldest_dirty_seq(dev); |
| 10597 | + if(dev->oldest_dirty_block > 0) { |
| 10598 | + selected = dev->oldest_dirty_block; |
| 10599 | + dev->gc_dirtiest = selected; |
| 10600 | + dev->oldest_dirty_gc_count++; |
| 10601 | + bi = yaffs_get_block_info(dev, selected); |
| 10602 | + dev->gc_pages_in_use = bi->pages_in_use - bi->soft_del_pages; |
| 10603 | + } else |
| 10604 | + dev->gc_not_done = 0; |
| 10605 | } |
| 10606 | |
| 10607 | - T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed)); |
| 10608 | + if(selected){ |
| 10609 | + T(YAFFS_TRACE_GC, |
| 10610 | + (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), |
| 10611 | + selected, |
| 10612 | + dev->param.chunks_per_block - dev->gc_pages_in_use, |
| 10613 | + prioritised)); |
| 10614 | + |
| 10615 | + dev->n_gc_blocks++; |
| 10616 | + if(background) |
| 10617 | + dev->bg_gcs++; |
| 10618 | + |
| 10619 | + dev->gc_dirtiest = 0; |
| 10620 | + dev->gc_pages_in_use = 0; |
| 10621 | + dev->gc_not_done = 0; |
| 10622 | + if(dev->refresh_skip > 0) |
| 10623 | + dev->refresh_skip--; |
| 10624 | + } else{ |
| 10625 | + dev->gc_not_done++; |
| 10626 | + T(YAFFS_TRACE_GC, |
| 10627 | + (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR), |
| 10628 | + dev->gc_block_finder, dev->gc_not_done, |
| 10629 | + threshold, |
| 10630 | + dev->gc_dirtiest, dev->gc_pages_in_use, |
| 10631 | + dev->oldest_dirty_block, |
| 10632 | + background ? " bg" : "")); |
| 10633 | + } |
| 10634 | |
| 10635 | - return retval; |
| 10636 | + return selected; |
| 10637 | } |
| 10638 | |
| 10639 | -/*--------------------- File read/write ------------------------ |
| 10640 | - * Read and write have very similar structures. |
| 10641 | - * In general the read/write has three parts to it |
| 10642 | - * An incomplete chunk to start with (if the read/write is not chunk-aligned) |
| 10643 | - * Some complete chunks |
| 10644 | - * An incomplete chunk to end off with |
| 10645 | +/* New garbage collector |
| 10646 | + * If we're very low on erased blocks then we do aggressive garbage collection |
| 10647 | + * otherwise we do "leasurely" garbage collection. |
| 10648 | + * Aggressive gc looks further (whole array) and will accept less dirty blocks. |
| 10649 | + * Passive gc only inspects smaller areas and will only accept more dirty blocks. |
| 10650 | * |
| 10651 | - * Curve-balls: the first chunk might also be the last chunk. |
| 10652 | + * The idea is to help clear out space in a more spread-out manner. |
| 10653 | + * Dunno if it really does anything useful. |
| 10654 | */ |
| 10655 | - |
| 10656 | -int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset, |
| 10657 | - int nBytes) |
| 10658 | +static int yaffs_check_gc(yaffs_dev_t *dev, int background) |
| 10659 | { |
| 10660 | + int aggressive = 0; |
| 10661 | + int gcOk = YAFFS_OK; |
| 10662 | + int maxTries = 0; |
| 10663 | + int minErased; |
| 10664 | + int erasedChunks; |
| 10665 | + int checkpointBlockAdjust; |
| 10666 | |
| 10667 | - int chunk; |
| 10668 | - __u32 start; |
| 10669 | - int nToCopy; |
| 10670 | - int n = nBytes; |
| 10671 | - int nDone = 0; |
| 10672 | - yaffs_ChunkCache *cache; |
| 10673 | - |
| 10674 | - yaffs_Device *dev; |
| 10675 | - |
| 10676 | - dev = in->myDev; |
| 10677 | - |
| 10678 | - while (n > 0) { |
| 10679 | - /* chunk = offset / dev->nDataBytesPerChunk + 1; */ |
| 10680 | - /* start = offset % dev->nDataBytesPerChunk; */ |
| 10681 | - yaffs_AddrToChunk(dev, offset, &chunk, &start); |
| 10682 | - chunk++; |
| 10683 | - |
| 10684 | - /* OK now check for the curveball where the start and end are in |
| 10685 | - * the same chunk. |
| 10686 | - */ |
| 10687 | - if ((start + n) < dev->nDataBytesPerChunk) |
| 10688 | - nToCopy = n; |
| 10689 | - else |
| 10690 | - nToCopy = dev->nDataBytesPerChunk - start; |
| 10691 | - |
| 10692 | - cache = yaffs_FindChunkCache(in, chunk); |
| 10693 | - |
| 10694 | - /* If the chunk is already in the cache or it is less than a whole chunk |
| 10695 | - * or we're using inband tags then use the cache (if there is caching) |
| 10696 | - * else bypass the cache. |
| 10697 | - */ |
| 10698 | - if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) { |
| 10699 | - if (dev->nShortOpCaches > 0) { |
| 10700 | - |
| 10701 | - /* If we can't find the data in the cache, then load it up. */ |
| 10702 | + if(dev->param.gc_control && |
| 10703 | + (dev->param.gc_control(dev) & 1) == 0) |
| 10704 | + return YAFFS_OK; |
| 10705 | |
| 10706 | - if (!cache) { |
| 10707 | - cache = yaffs_GrabChunkCache(in->myDev); |
| 10708 | - cache->object = in; |
| 10709 | - cache->chunkId = chunk; |
| 10710 | - cache->dirty = 0; |
| 10711 | - cache->locked = 0; |
| 10712 | - yaffs_ReadChunkDataFromObject(in, chunk, |
| 10713 | - cache-> |
| 10714 | - data); |
| 10715 | - cache->nBytes = 0; |
| 10716 | - } |
| 10717 | + if (dev->gc_disable) { |
| 10718 | + /* Bail out so we don't get recursive gc */ |
| 10719 | + return YAFFS_OK; |
| 10720 | + } |
| 10721 | |
| 10722 | - yaffs_UseChunkCache(dev, cache, 0); |
| 10723 | + /* This loop should pass the first time. |
| 10724 | + * We'll only see looping here if the collection does not increase space. |
| 10725 | + */ |
| 10726 | |
| 10727 | - cache->locked = 1; |
| 10728 | + do { |
| 10729 | + maxTries++; |
| 10730 | |
| 10731 | + checkpointBlockAdjust = yaffs_calc_checkpt_blocks_required(dev); |
| 10732 | |
| 10733 | - memcpy(buffer, &cache->data[start], nToCopy); |
| 10734 | + minErased = dev->param.n_reserved_blocks + checkpointBlockAdjust + 1; |
| 10735 | + erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block; |
| 10736 | |
| 10737 | - cache->locked = 0; |
| 10738 | - } else { |
| 10739 | - /* Read into the local buffer then copy..*/ |
| 10740 | + /* If we need a block soon then do aggressive gc.*/ |
| 10741 | + if (dev->n_erased_blocks < minErased) |
| 10742 | + aggressive = 1; |
| 10743 | + else { |
| 10744 | + if(!background && erasedChunks > (dev->n_free_chunks / 4)) |
| 10745 | + break; |
| 10746 | |
| 10747 | - __u8 *localBuffer = |
| 10748 | - yaffs_GetTempBuffer(dev, __LINE__); |
| 10749 | - yaffs_ReadChunkDataFromObject(in, chunk, |
| 10750 | - localBuffer); |
| 10751 | + if(dev->gc_skip > 20) |
| 10752 | + dev->gc_skip = 20; |
| 10753 | + if(erasedChunks < dev->n_free_chunks/2 || |
| 10754 | + dev->gc_skip < 1 || |
| 10755 | + background) |
| 10756 | + aggressive = 0; |
| 10757 | + else { |
| 10758 | + dev->gc_skip--; |
| 10759 | + break; |
| 10760 | + } |
| 10761 | + } |
| 10762 | |
| 10763 | - memcpy(buffer, &localBuffer[start], nToCopy); |
| 10764 | + dev->gc_skip = 5; |
| 10765 | |
| 10766 | + /* If we don't already have a block being gc'd then see if we should start another */ |
| 10767 | |
| 10768 | - yaffs_ReleaseTempBuffer(dev, localBuffer, |
| 10769 | - __LINE__); |
| 10770 | - } |
| 10771 | + if (dev->gc_block < 1 && !aggressive) { |
| 10772 | + dev->gc_block = yaffs2_find_refresh_block(dev); |
| 10773 | + dev->gc_chunk = 0; |
| 10774 | + dev->n_clean_ups=0; |
| 10775 | + } |
| 10776 | + if (dev->gc_block < 1) { |
| 10777 | + dev->gc_block = yaffs_find_gc_block(dev, aggressive, background); |
| 10778 | + dev->gc_chunk = 0; |
| 10779 | + dev->n_clean_ups=0; |
| 10780 | + } |
| 10781 | |
| 10782 | - } else { |
| 10783 | + if (dev->gc_block > 0) { |
| 10784 | + dev->all_gcs++; |
| 10785 | + if (!aggressive) |
| 10786 | + dev->passive_gc_count++; |
| 10787 | |
| 10788 | - /* A full chunk. Read directly into the supplied buffer. */ |
| 10789 | - yaffs_ReadChunkDataFromObject(in, chunk, buffer); |
| 10790 | + T(YAFFS_TRACE_GC, |
| 10791 | + (TSTR |
| 10792 | + ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR), |
| 10793 | + dev->n_erased_blocks, aggressive)); |
| 10794 | |
| 10795 | + gcOk = yaffs_gc_block(dev, dev->gc_block, aggressive); |
| 10796 | } |
| 10797 | |
| 10798 | - n -= nToCopy; |
| 10799 | - offset += nToCopy; |
| 10800 | - buffer += nToCopy; |
| 10801 | - nDone += nToCopy; |
| 10802 | - |
| 10803 | - } |
| 10804 | + if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) && dev->gc_block > 0) { |
| 10805 | + T(YAFFS_TRACE_GC, |
| 10806 | + (TSTR |
| 10807 | + ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" |
| 10808 | + TENDSTR), dev->n_erased_blocks, maxTries, dev->gc_block)); |
| 10809 | + } |
| 10810 | + } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) && |
| 10811 | + (dev->gc_block > 0) && |
| 10812 | + (maxTries < 2)); |
| 10813 | |
| 10814 | - return nDone; |
| 10815 | + return aggressive ? gcOk : YAFFS_OK; |
| 10816 | } |
| 10817 | |
| 10818 | -int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, |
| 10819 | - int nBytes, int writeThrough) |
| 10820 | +/* |
| 10821 | + * yaffs_bg_gc() |
| 10822 | + * Garbage collects. Intended to be called from a background thread. |
| 10823 | + * Returns non-zero if at least half the free chunks are erased. |
| 10824 | + */ |
| 10825 | +int yaffs_bg_gc(yaffs_dev_t *dev, unsigned urgency) |
| 10826 | { |
| 10827 | + int erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block; |
| 10828 | |
| 10829 | - int chunk; |
| 10830 | - __u32 start; |
| 10831 | - int nToCopy; |
| 10832 | - int n = nBytes; |
| 10833 | - int nDone = 0; |
| 10834 | - int nToWriteBack; |
| 10835 | - int startOfWrite = offset; |
| 10836 | - int chunkWritten = 0; |
| 10837 | - __u32 nBytesRead; |
| 10838 | - __u32 chunkStart; |
| 10839 | + T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR),urgency)); |
| 10840 | |
| 10841 | - yaffs_Device *dev; |
| 10842 | + yaffs_check_gc(dev, 1); |
| 10843 | + return erasedChunks > dev->n_free_chunks/2; |
| 10844 | +} |
| 10845 | |
| 10846 | - dev = in->myDev; |
| 10847 | +/*------------------------- TAGS --------------------------------*/ |
| 10848 | |
| 10849 | - while (n > 0 && chunkWritten >= 0) { |
| 10850 | - /* chunk = offset / dev->nDataBytesPerChunk + 1; */ |
| 10851 | - /* start = offset % dev->nDataBytesPerChunk; */ |
| 10852 | - yaffs_AddrToChunk(dev, offset, &chunk, &start); |
| 10853 | +static int yaffs_tags_match(const yaffs_ext_tags *tags, int obj_id, |
| 10854 | + int chunkInObject) |
| 10855 | +{ |
| 10856 | + return (tags->chunk_id == chunkInObject && |
| 10857 | + tags->obj_id == obj_id && !tags->is_deleted) ? 1 : 0; |
| 10858 | |
| 10859 | - if (chunk * dev->nDataBytesPerChunk + start != offset || |
| 10860 | - start >= dev->nDataBytesPerChunk) { |
| 10861 | - T(YAFFS_TRACE_ERROR, ( |
| 10862 | - TSTR("AddrToChunk of offset %d gives chunk %d start %d" |
| 10863 | - TENDSTR), |
| 10864 | - (int)offset, chunk, start)); |
| 10865 | - } |
| 10866 | - chunk++; |
| 10867 | +} |
| 10868 | |
| 10869 | - /* OK now check for the curveball where the start and end are in |
| 10870 | - * the same chunk. |
| 10871 | - */ |
| 10872 | |
| 10873 | - if ((start + n) < dev->nDataBytesPerChunk) { |
| 10874 | - nToCopy = n; |
| 10875 | +/*-------------------- Data file manipulation -----------------*/ |
| 10876 | |
| 10877 | - /* Now folks, to calculate how many bytes to write back.... |
| 10878 | - * If we're overwriting and not writing to then end of file then |
| 10879 | - * we need to write back as much as was there before. |
| 10880 | - */ |
| 10881 | +static int yaffs_find_chunk_in_file(yaffs_obj_t *in, int inode_chunk, |
| 10882 | + yaffs_ext_tags *tags) |
| 10883 | +{ |
| 10884 | + /*Get the Tnode, then get the level 0 offset chunk offset */ |
| 10885 | + yaffs_tnode_t *tn; |
| 10886 | + int theChunk = -1; |
| 10887 | + yaffs_ext_tags localTags; |
| 10888 | + int retVal = -1; |
| 10889 | |
| 10890 | - chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk); |
| 10891 | + yaffs_dev_t *dev = in->my_dev; |
| 10892 | |
| 10893 | - if (chunkStart > in->variant.fileVariant.fileSize) |
| 10894 | - nBytesRead = 0; /* Past end of file */ |
| 10895 | - else |
| 10896 | - nBytesRead = in->variant.fileVariant.fileSize - chunkStart; |
| 10897 | + if (!tags) { |
| 10898 | + /* Passed a NULL, so use our own tags space */ |
| 10899 | + tags = &localTags; |
| 10900 | + } |
| 10901 | |
| 10902 | - if (nBytesRead > dev->nDataBytesPerChunk) |
| 10903 | - nBytesRead = dev->nDataBytesPerChunk; |
| 10904 | + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); |
| 10905 | |
| 10906 | - nToWriteBack = |
| 10907 | - (nBytesRead > |
| 10908 | - (start + n)) ? nBytesRead : (start + n); |
| 10909 | + if (tn) { |
| 10910 | + theChunk = yaffs_get_group_base(dev, tn, inode_chunk); |
| 10911 | |
| 10912 | - if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk) |
| 10913 | - YBUG(); |
| 10914 | + retVal = |
| 10915 | + yaffs_find_chunk_in_group(dev, theChunk, tags, in->obj_id, |
| 10916 | + inode_chunk); |
| 10917 | + } |
| 10918 | + return retVal; |
| 10919 | +} |
| 10920 | |
| 10921 | - } else { |
| 10922 | - nToCopy = dev->nDataBytesPerChunk - start; |
| 10923 | - nToWriteBack = dev->nDataBytesPerChunk; |
| 10924 | - } |
| 10925 | +static int yaffs_find_del_file_chunk(yaffs_obj_t *in, int inode_chunk, |
| 10926 | + yaffs_ext_tags *tags) |
| 10927 | +{ |
| 10928 | + /* Get the Tnode, then get the level 0 offset chunk offset */ |
| 10929 | + yaffs_tnode_t *tn; |
| 10930 | + int theChunk = -1; |
| 10931 | + yaffs_ext_tags localTags; |
| 10932 | |
| 10933 | - if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) { |
| 10934 | - /* An incomplete start or end chunk (or maybe both start and end chunk), |
| 10935 | - * or we're using inband tags, so we want to use the cache buffers. |
| 10936 | - */ |
| 10937 | - if (dev->nShortOpCaches > 0) { |
| 10938 | - yaffs_ChunkCache *cache; |
| 10939 | - /* If we can't find the data in the cache, then load the cache */ |
| 10940 | - cache = yaffs_FindChunkCache(in, chunk); |
| 10941 | + yaffs_dev_t *dev = in->my_dev; |
| 10942 | + int retVal = -1; |
| 10943 | |
| 10944 | - if (!cache |
| 10945 | - && yaffs_CheckSpaceForAllocation(in-> |
| 10946 | - myDev)) { |
| 10947 | - cache = yaffs_GrabChunkCache(in->myDev); |
| 10948 | - cache->object = in; |
| 10949 | - cache->chunkId = chunk; |
| 10950 | - cache->dirty = 0; |
| 10951 | - cache->locked = 0; |
| 10952 | - yaffs_ReadChunkDataFromObject(in, chunk, |
| 10953 | - cache-> |
| 10954 | - data); |
| 10955 | - } else if (cache && |
| 10956 | - !cache->dirty && |
| 10957 | - !yaffs_CheckSpaceForAllocation(in->myDev)) { |
| 10958 | - /* Drop the cache if it was a read cache item and |
| 10959 | - * no space check has been made for it. |
| 10960 | - */ |
| 10961 | - cache = NULL; |
| 10962 | - } |
| 10963 | + if (!tags) { |
| 10964 | + /* Passed a NULL, so use our own tags space */ |
| 10965 | + tags = &localTags; |
| 10966 | + } |
| 10967 | |
| 10968 | - if (cache) { |
| 10969 | - yaffs_UseChunkCache(dev, cache, 1); |
| 10970 | - cache->locked = 1; |
| 10971 | + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); |
| 10972 | |
| 10973 | + if (tn) { |
| 10974 | |
| 10975 | - memcpy(&cache->data[start], buffer, |
| 10976 | - nToCopy); |
| 10977 | + theChunk = yaffs_get_group_base(dev, tn, inode_chunk); |
| 10978 | |
| 10979 | + retVal = |
| 10980 | + yaffs_find_chunk_in_group(dev, theChunk, tags, in->obj_id, |
| 10981 | + inode_chunk); |
| 10982 | |
| 10983 | - cache->locked = 0; |
| 10984 | - cache->nBytes = nToWriteBack; |
| 10985 | + /* Delete the entry in the filestructure (if found) */ |
| 10986 | + if (retVal != -1) |
| 10987 | + yaffs_load_tnode_0(dev, tn, inode_chunk, 0); |
| 10988 | + } |
| 10989 | |
| 10990 | - if (writeThrough) { |
| 10991 | - chunkWritten = |
| 10992 | - yaffs_WriteChunkDataToObject |
| 10993 | - (cache->object, |
| 10994 | - cache->chunkId, |
| 10995 | - cache->data, cache->nBytes, |
| 10996 | - 1); |
| 10997 | - cache->dirty = 0; |
| 10998 | - } |
| 10999 | + return retVal; |
| 11000 | +} |
| 11001 | |
| 11002 | - } else { |
| 11003 | - chunkWritten = -1; /* fail the write */ |
| 11004 | - } |
| 11005 | - } else { |
| 11006 | - /* An incomplete start or end chunk (or maybe both start and end chunk) |
| 11007 | - * Read into the local buffer then copy, then copy over and write back. |
| 11008 | - */ |
| 11009 | |
| 11010 | - __u8 *localBuffer = |
| 11011 | - yaffs_GetTempBuffer(dev, __LINE__); |
| 11012 | +int yaffs_put_chunk_in_file(yaffs_obj_t *in, int inode_chunk, |
| 11013 | + int nand_chunk, int in_scan) |
| 11014 | +{ |
| 11015 | + /* NB in_scan is zero unless scanning. |
| 11016 | + * For forward scanning, in_scan is > 0; |
| 11017 | + * for backward scanning in_scan is < 0 |
| 11018 | + * |
| 11019 | + * nand_chunk = 0 is a dummy insert to make sure the tnodes are there. |
| 11020 | + */ |
| 11021 | |
| 11022 | - yaffs_ReadChunkDataFromObject(in, chunk, |
| 11023 | - localBuffer); |
| 11024 | + yaffs_tnode_t *tn; |
| 11025 | + yaffs_dev_t *dev = in->my_dev; |
| 11026 | + int existingChunk; |
| 11027 | + yaffs_ext_tags existingTags; |
| 11028 | + yaffs_ext_tags newTags; |
| 11029 | + unsigned existingSerial, newSerial; |
| 11030 | |
| 11031 | + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) { |
| 11032 | + /* Just ignore an attempt at putting a chunk into a non-file during scanning |
| 11033 | + * If it is not during Scanning then something went wrong! |
| 11034 | + */ |
| 11035 | + if (!in_scan) { |
| 11036 | + T(YAFFS_TRACE_ERROR, |
| 11037 | + (TSTR |
| 11038 | + ("yaffs tragedy:attempt to put data chunk into a non-file" |
| 11039 | + TENDSTR))); |
| 11040 | + YBUG(); |
| 11041 | + } |
| 11042 | |
| 11043 | + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); |
| 11044 | + return YAFFS_OK; |
| 11045 | + } |
| 11046 | |
| 11047 | - memcpy(&localBuffer[start], buffer, nToCopy); |
| 11048 | + tn = yaffs_add_find_tnode_0(dev, |
| 11049 | + &in->variant.file_variant, |
| 11050 | + inode_chunk, |
| 11051 | + NULL); |
| 11052 | + if (!tn) |
| 11053 | + return YAFFS_FAIL; |
| 11054 | + |
| 11055 | + if(!nand_chunk) |
| 11056 | + /* Dummy insert, bail now */ |
| 11057 | + return YAFFS_OK; |
| 11058 | |
| 11059 | - chunkWritten = |
| 11060 | - yaffs_WriteChunkDataToObject(in, chunk, |
| 11061 | - localBuffer, |
| 11062 | - nToWriteBack, |
| 11063 | - 0); |
| 11064 | + existingChunk = yaffs_get_group_base(dev, tn, inode_chunk); |
| 11065 | |
| 11066 | - yaffs_ReleaseTempBuffer(dev, localBuffer, |
| 11067 | - __LINE__); |
| 11068 | + if (in_scan != 0) { |
| 11069 | + /* If we're scanning then we need to test for duplicates |
| 11070 | + * NB This does not need to be efficient since it should only ever |
| 11071 | + * happen when the power fails during a write, then only one |
| 11072 | + * chunk should ever be affected. |
| 11073 | + * |
| 11074 | + * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO |
| 11075 | + * Update: For backward scanning we don't need to re-read tags so this is quite cheap. |
| 11076 | + */ |
| 11077 | + |
| 11078 | + if (existingChunk > 0) { |
| 11079 | + /* NB Right now existing chunk will not be real chunk_id if the chunk group size > 1 |
| 11080 | + * thus we have to do a FindChunkInFile to get the real chunk id. |
| 11081 | + * |
| 11082 | + * We have a duplicate now we need to decide which one to use: |
| 11083 | + * |
| 11084 | + * Backwards scanning YAFFS2: The old one is what we use, dump the new one. |
| 11085 | + * Forward scanning YAFFS2: The new one is what we use, dump the old one. |
| 11086 | + * YAFFS1: Get both sets of tags and compare serial numbers. |
| 11087 | + */ |
| 11088 | + |
| 11089 | + if (in_scan > 0) { |
| 11090 | + /* Only do this for forward scanning */ |
| 11091 | + yaffs_rd_chunk_tags_nand(dev, |
| 11092 | + nand_chunk, |
| 11093 | + NULL, &newTags); |
| 11094 | |
| 11095 | + /* Do a proper find */ |
| 11096 | + existingChunk = |
| 11097 | + yaffs_find_chunk_in_file(in, inode_chunk, |
| 11098 | + &existingTags); |
| 11099 | } |
| 11100 | |
| 11101 | - } else { |
| 11102 | - /* A full chunk. Write directly from the supplied buffer. */ |
| 11103 | + if (existingChunk <= 0) { |
| 11104 | + /*Hoosterman - how did this happen? */ |
| 11105 | |
| 11106 | + T(YAFFS_TRACE_ERROR, |
| 11107 | + (TSTR |
| 11108 | + ("yaffs tragedy: existing chunk < 0 in scan" |
| 11109 | + TENDSTR))); |
| 11110 | |
| 11111 | + } |
| 11112 | |
| 11113 | - chunkWritten = |
| 11114 | - yaffs_WriteChunkDataToObject(in, chunk, buffer, |
| 11115 | - dev->nDataBytesPerChunk, |
| 11116 | - 0); |
| 11117 | + /* NB The deleted flags should be false, otherwise the chunks will |
| 11118 | + * not be loaded during a scan |
| 11119 | + */ |
| 11120 | |
| 11121 | - /* Since we've overwritten the cached data, we better invalidate it. */ |
| 11122 | - yaffs_InvalidateChunkCache(in, chunk); |
| 11123 | - } |
| 11124 | + if (in_scan > 0) { |
| 11125 | + newSerial = newTags.serial_number; |
| 11126 | + existingSerial = existingTags.serial_number; |
| 11127 | + } |
| 11128 | |
| 11129 | - if (chunkWritten >= 0) { |
| 11130 | - n -= nToCopy; |
| 11131 | - offset += nToCopy; |
| 11132 | - buffer += nToCopy; |
| 11133 | - nDone += nToCopy; |
| 11134 | + if ((in_scan > 0) && |
| 11135 | + (existingChunk <= 0 || |
| 11136 | + ((existingSerial + 1) & 3) == newSerial)) { |
| 11137 | + /* Forward scanning. |
| 11138 | + * Use new |
| 11139 | + * Delete the old one and drop through to update the tnode |
| 11140 | + */ |
| 11141 | + yaffs_chunk_del(dev, existingChunk, 1, |
| 11142 | + __LINE__); |
| 11143 | + } else { |
| 11144 | + /* Backward scanning or we want to use the existing one |
| 11145 | + * Use existing. |
| 11146 | + * Delete the new one and return early so that the tnode isn't changed |
| 11147 | + */ |
| 11148 | + yaffs_chunk_del(dev, nand_chunk, 1, |
| 11149 | + __LINE__); |
| 11150 | + return YAFFS_OK; |
| 11151 | + } |
| 11152 | } |
| 11153 | |
| 11154 | } |
| 11155 | |
| 11156 | - /* Update file object */ |
| 11157 | - |
| 11158 | - if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize) |
| 11159 | - in->variant.fileVariant.fileSize = (startOfWrite + nDone); |
| 11160 | + if (existingChunk == 0) |
| 11161 | + in->n_data_chunks++; |
| 11162 | |
| 11163 | - in->dirty = 1; |
| 11164 | + yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk); |
| 11165 | |
| 11166 | - return nDone; |
| 11167 | + return YAFFS_OK; |
| 11168 | } |
| 11169 | |
| 11170 | +static int yaffs_rd_data_obj(yaffs_obj_t *in, int inode_chunk, |
| 11171 | + __u8 *buffer) |
| 11172 | +{ |
| 11173 | + int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL); |
| 11174 | |
| 11175 | -/* ---------------------- File resizing stuff ------------------ */ |
| 11176 | + if (nand_chunk >= 0) |
| 11177 | + return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk, |
| 11178 | + buffer, NULL); |
| 11179 | + else { |
| 11180 | + T(YAFFS_TRACE_NANDACCESS, |
| 11181 | + (TSTR("Chunk %d not found zero instead" TENDSTR), |
| 11182 | + nand_chunk)); |
| 11183 | + /* get sane (zero) data if you read a hole */ |
| 11184 | + memset(buffer, 0, in->my_dev->data_bytes_per_chunk); |
| 11185 | + return 0; |
| 11186 | + } |
| 11187 | + |
| 11188 | +} |
| 11189 | |
| 11190 | -static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize) |
| 11191 | +void yaffs_chunk_del(yaffs_dev_t *dev, int chunk_id, int mark_flash, int lyn) |
| 11192 | { |
| 11193 | + int block; |
| 11194 | + int page; |
| 11195 | + yaffs_ext_tags tags; |
| 11196 | + yaffs_block_info_t *bi; |
| 11197 | |
| 11198 | - yaffs_Device *dev = in->myDev; |
| 11199 | - int oldFileSize = in->variant.fileVariant.fileSize; |
| 11200 | + if (chunk_id <= 0) |
| 11201 | + return; |
| 11202 | |
| 11203 | - int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk; |
| 11204 | + dev->n_deletions++; |
| 11205 | + block = chunk_id / dev->param.chunks_per_block; |
| 11206 | + page = chunk_id % dev->param.chunks_per_block; |
| 11207 | |
| 11208 | - int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) / |
| 11209 | - dev->nDataBytesPerChunk; |
| 11210 | - int i; |
| 11211 | - int chunkId; |
| 11212 | |
| 11213 | - /* Delete backwards so that we don't end up with holes if |
| 11214 | - * power is lost part-way through the operation. |
| 11215 | + if (!yaffs_check_chunk_bit(dev, block, page)) |
| 11216 | + T(YAFFS_TRACE_VERIFY, |
| 11217 | + (TSTR("Deleting invalid chunk %d"TENDSTR), |
| 11218 | + chunk_id)); |
| 11219 | + |
| 11220 | + bi = yaffs_get_block_info(dev, block); |
| 11221 | + |
| 11222 | + yaffs2_update_oldest_dirty_seq(dev, block, bi); |
| 11223 | + |
| 11224 | + T(YAFFS_TRACE_DELETION, |
| 11225 | + (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunk_id)); |
| 11226 | + |
| 11227 | + if (!dev->param.is_yaffs2 && mark_flash && |
| 11228 | + bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) { |
| 11229 | + |
| 11230 | + yaffs_init_tags(&tags); |
| 11231 | + |
| 11232 | + tags.is_deleted = 1; |
| 11233 | + |
| 11234 | + yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags); |
| 11235 | + yaffs_handle_chunk_update(dev, chunk_id, &tags); |
| 11236 | + } else { |
| 11237 | + dev->n_unmarked_deletions++; |
| 11238 | + } |
| 11239 | + |
| 11240 | + /* Pull out of the management area. |
| 11241 | + * If the whole block became dirty, this will kick off an erasure. |
| 11242 | */ |
| 11243 | - for (i = lastDel; i >= startDel; i--) { |
| 11244 | - /* NB this could be optimised somewhat, |
| 11245 | - * eg. could retrieve the tags and write them without |
| 11246 | - * using yaffs_DeleteChunk |
| 11247 | - */ |
| 11248 | + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING || |
| 11249 | + bi->block_state == YAFFS_BLOCK_STATE_FULL || |
| 11250 | + bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || |
| 11251 | + bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { |
| 11252 | + dev->n_free_chunks++; |
| 11253 | |
| 11254 | - chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL); |
| 11255 | - if (chunkId > 0) { |
| 11256 | - if (chunkId < |
| 11257 | - (dev->internalStartBlock * dev->nChunksPerBlock) |
| 11258 | - || chunkId >= |
| 11259 | - ((dev->internalEndBlock + |
| 11260 | - 1) * dev->nChunksPerBlock)) { |
| 11261 | - T(YAFFS_TRACE_ALWAYS, |
| 11262 | - (TSTR("Found daft chunkId %d for %d" TENDSTR), |
| 11263 | - chunkId, i)); |
| 11264 | - } else { |
| 11265 | - in->nDataChunks--; |
| 11266 | - yaffs_DeleteChunk(dev, chunkId, 1, __LINE__); |
| 11267 | - } |
| 11268 | + yaffs_clear_chunk_bit(dev, block, page); |
| 11269 | + |
| 11270 | + bi->pages_in_use--; |
| 11271 | + |
| 11272 | + if (bi->pages_in_use == 0 && |
| 11273 | + !bi->has_shrink_hdr && |
| 11274 | + bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING && |
| 11275 | + bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCANNING) { |
| 11276 | + yaffs_block_became_dirty(dev, block); |
| 11277 | } |
| 11278 | + |
| 11279 | } |
| 11280 | |
| 11281 | } |
| 11282 | |
| 11283 | -int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize) |
| 11284 | +static int yaffs_wr_data_obj(yaffs_obj_t *in, int inode_chunk, |
| 11285 | + const __u8 *buffer, int n_bytes, |
| 11286 | + int useReserve) |
| 11287 | { |
| 11288 | + /* Find old chunk Need to do this to get serial number |
| 11289 | + * Write new one and patch into tree. |
| 11290 | + * Invalidate old tags. |
| 11291 | + */ |
| 11292 | |
| 11293 | - int oldFileSize = in->variant.fileVariant.fileSize; |
| 11294 | - __u32 newSizeOfPartialChunk; |
| 11295 | - int newFullChunks; |
| 11296 | + int prevChunkId; |
| 11297 | + yaffs_ext_tags prevTags; |
| 11298 | |
| 11299 | - yaffs_Device *dev = in->myDev; |
| 11300 | + int newChunkId; |
| 11301 | + yaffs_ext_tags newTags; |
| 11302 | |
| 11303 | - yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk); |
| 11304 | + yaffs_dev_t *dev = in->my_dev; |
| 11305 | |
| 11306 | - yaffs_FlushFilesChunkCache(in); |
| 11307 | - yaffs_InvalidateWholeChunkCache(in); |
| 11308 | + yaffs_check_gc(dev,0); |
| 11309 | |
| 11310 | - yaffs_CheckGarbageCollection(dev); |
| 11311 | + /* Get the previous chunk at this location in the file if it exists. |
| 11312 | + * If it does not exist then put a zero into the tree. This creates |
| 11313 | + * the tnode now, rather than later when it is harder to clean up. |
| 11314 | + */ |
| 11315 | + prevChunkId = yaffs_find_chunk_in_file(in, inode_chunk, &prevTags); |
| 11316 | + if(prevChunkId < 1 && |
| 11317 | + !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0)) |
| 11318 | + return 0; |
| 11319 | |
| 11320 | - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) |
| 11321 | - return YAFFS_FAIL; |
| 11322 | + /* Set up new tags */ |
| 11323 | + yaffs_init_tags(&newTags); |
| 11324 | |
| 11325 | - if (newSize == oldFileSize) |
| 11326 | - return YAFFS_OK; |
| 11327 | + newTags.chunk_id = inode_chunk; |
| 11328 | + newTags.obj_id = in->obj_id; |
| 11329 | + newTags.serial_number = |
| 11330 | + (prevChunkId > 0) ? prevTags.serial_number + 1 : 1; |
| 11331 | + newTags.n_bytes = n_bytes; |
| 11332 | |
| 11333 | - if (newSize < oldFileSize) { |
| 11334 | + if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) { |
| 11335 | + T(YAFFS_TRACE_ERROR, |
| 11336 | + (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), n_bytes)); |
| 11337 | + YBUG(); |
| 11338 | + } |
| 11339 | + |
| 11340 | + |
| 11341 | + newChunkId = |
| 11342 | + yaffs_write_new_chunk(dev, buffer, &newTags, |
| 11343 | + useReserve); |
| 11344 | |
| 11345 | - yaffs_PruneResizedChunks(in, newSize); |
| 11346 | + if (newChunkId > 0) { |
| 11347 | + yaffs_put_chunk_in_file(in, inode_chunk, newChunkId, 0); |
| 11348 | |
| 11349 | - if (newSizeOfPartialChunk != 0) { |
| 11350 | - int lastChunk = 1 + newFullChunks; |
| 11351 | + if (prevChunkId > 0) |
| 11352 | + yaffs_chunk_del(dev, prevChunkId, 1, __LINE__); |
| 11353 | |
| 11354 | - __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); |
| 11355 | + yaffs_verify_file_sane(in); |
| 11356 | + } |
| 11357 | + return newChunkId; |
| 11358 | |
| 11359 | - /* Got to read and rewrite the last chunk with its new size and zero pad */ |
| 11360 | - yaffs_ReadChunkDataFromObject(in, lastChunk, |
| 11361 | - localBuffer); |
| 11362 | +} |
| 11363 | |
| 11364 | - memset(localBuffer + newSizeOfPartialChunk, 0, |
| 11365 | - dev->nDataBytesPerChunk - newSizeOfPartialChunk); |
| 11366 | +/* UpdateObjectHeader updates the header on NAND for an object. |
| 11367 | + * If name is not NULL, then that new name is used. |
| 11368 | + */ |
| 11369 | +int yaffs_update_oh(yaffs_obj_t *in, const YCHAR *name, int force, |
| 11370 | + int is_shrink, int shadows, yaffs_xattr_mod *xmod) |
| 11371 | +{ |
| 11372 | |
| 11373 | - yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer, |
| 11374 | - newSizeOfPartialChunk, 1); |
| 11375 | + yaffs_block_info_t *bi; |
| 11376 | |
| 11377 | - yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); |
| 11378 | - } |
| 11379 | + yaffs_dev_t *dev = in->my_dev; |
| 11380 | |
| 11381 | - in->variant.fileVariant.fileSize = newSize; |
| 11382 | + int prevChunkId; |
| 11383 | + int retVal = 0; |
| 11384 | + int result = 0; |
| 11385 | |
| 11386 | - yaffs_PruneFileStructure(dev, &in->variant.fileVariant); |
| 11387 | - } else { |
| 11388 | - /* newsSize > oldFileSize */ |
| 11389 | - in->variant.fileVariant.fileSize = newSize; |
| 11390 | - } |
| 11391 | + int newChunkId; |
| 11392 | + yaffs_ext_tags newTags; |
| 11393 | + yaffs_ext_tags oldTags; |
| 11394 | + const YCHAR *alias = NULL; |
| 11395 | |
| 11396 | + __u8 *buffer = NULL; |
| 11397 | + YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1]; |
| 11398 | |
| 11399 | - /* Write a new object header. |
| 11400 | - * show we've shrunk the file, if need be |
| 11401 | - * Do this only if the file is not in the deleted directories. |
| 11402 | - */ |
| 11403 | - if (in->parent && |
| 11404 | - in->parent->objectId != YAFFS_OBJECTID_UNLINKED && |
| 11405 | - in->parent->objectId != YAFFS_OBJECTID_DELETED) |
| 11406 | - yaffs_UpdateObjectHeader(in, NULL, 0, |
| 11407 | - (newSize < oldFileSize) ? 1 : 0, 0); |
| 11408 | + yaffs_obj_header *oh = NULL; |
| 11409 | |
| 11410 | - return YAFFS_OK; |
| 11411 | -} |
| 11412 | + yaffs_strcpy(old_name, _Y("silly old name")); |
| 11413 | |
| 11414 | -loff_t yaffs_GetFileSize(yaffs_Object *obj) |
| 11415 | -{ |
| 11416 | - obj = yaffs_GetEquivalentObject(obj); |
| 11417 | |
| 11418 | - switch (obj->variantType) { |
| 11419 | - case YAFFS_OBJECT_TYPE_FILE: |
| 11420 | - return obj->variant.fileVariant.fileSize; |
| 11421 | - case YAFFS_OBJECT_TYPE_SYMLINK: |
| 11422 | - return yaffs_strlen(obj->variant.symLinkVariant.alias); |
| 11423 | - default: |
| 11424 | - return 0; |
| 11425 | - } |
| 11426 | -} |
| 11427 | + if (!in->fake || |
| 11428 | + in == dev->root_dir || /* The root_dir should also be saved */ |
| 11429 | + force || xmod) { |
| 11430 | |
| 11431 | + yaffs_check_gc(dev,0); |
| 11432 | + yaffs_check_obj_details_loaded(in); |
| 11433 | |
| 11434 | + buffer = yaffs_get_temp_buffer(in->my_dev, __LINE__); |
| 11435 | + oh = (yaffs_obj_header *) buffer; |
| 11436 | + |
| 11437 | + prevChunkId = in->hdr_chunk; |
| 11438 | + |
| 11439 | + if (prevChunkId > 0) { |
| 11440 | + result = yaffs_rd_chunk_tags_nand(dev, prevChunkId, |
| 11441 | + buffer, &oldTags); |
| 11442 | + |
| 11443 | + yaffs_verify_oh(in, oh, &oldTags, 0); |
| 11444 | + |
| 11445 | + memcpy(old_name, oh->name, sizeof(oh->name)); |
| 11446 | + memset(buffer, 0xFF, sizeof(yaffs_obj_header)); |
| 11447 | + } else |
| 11448 | + memset(buffer, 0xFF, dev->data_bytes_per_chunk); |
| 11449 | + |
| 11450 | + oh->type = in->variant_type; |
| 11451 | + oh->yst_mode = in->yst_mode; |
| 11452 | + oh->shadows_obj = oh->inband_shadowed_obj_id = shadows; |
| 11453 | |
| 11454 | -int yaffs_FlushFile(yaffs_Object *in, int updateTime) |
| 11455 | -{ |
| 11456 | - int retVal; |
| 11457 | - if (in->dirty) { |
| 11458 | - yaffs_FlushFilesChunkCache(in); |
| 11459 | - if (updateTime) { |
| 11460 | #ifdef CONFIG_YAFFS_WINCE |
| 11461 | - yfsd_WinFileTimeNow(in->win_mtime); |
| 11462 | + oh->win_atime[0] = in->win_atime[0]; |
| 11463 | + oh->win_ctime[0] = in->win_ctime[0]; |
| 11464 | + oh->win_mtime[0] = in->win_mtime[0]; |
| 11465 | + oh->win_atime[1] = in->win_atime[1]; |
| 11466 | + oh->win_ctime[1] = in->win_ctime[1]; |
| 11467 | + oh->win_mtime[1] = in->win_mtime[1]; |
| 11468 | #else |
| 11469 | + oh->yst_uid = in->yst_uid; |
| 11470 | + oh->yst_gid = in->yst_gid; |
| 11471 | + oh->yst_atime = in->yst_atime; |
| 11472 | + oh->yst_mtime = in->yst_mtime; |
| 11473 | + oh->yst_ctime = in->yst_ctime; |
| 11474 | + oh->yst_rdev = in->yst_rdev; |
| 11475 | +#endif |
| 11476 | + if (in->parent) |
| 11477 | + oh->parent_obj_id = in->parent->obj_id; |
| 11478 | + else |
| 11479 | + oh->parent_obj_id = 0; |
| 11480 | + |
| 11481 | + if (name && *name) { |
| 11482 | + memset(oh->name, 0, sizeof(oh->name)); |
| 11483 | + yaffs_load_oh_from_name(dev,oh->name,name); |
| 11484 | + } else if (prevChunkId > 0) |
| 11485 | + memcpy(oh->name, old_name, sizeof(oh->name)); |
| 11486 | + else |
| 11487 | + memset(oh->name, 0, sizeof(oh->name)); |
| 11488 | |
| 11489 | - in->yst_mtime = Y_CURRENT_TIME; |
| 11490 | + oh->is_shrink = is_shrink; |
| 11491 | |
| 11492 | -#endif |
| 11493 | + switch (in->variant_type) { |
| 11494 | + case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 11495 | + /* Should not happen */ |
| 11496 | + break; |
| 11497 | + case YAFFS_OBJECT_TYPE_FILE: |
| 11498 | + oh->file_size = |
| 11499 | + (oh->parent_obj_id == YAFFS_OBJECTID_DELETED |
| 11500 | + || oh->parent_obj_id == |
| 11501 | + YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant. |
| 11502 | + file_variant.file_size; |
| 11503 | + break; |
| 11504 | + case YAFFS_OBJECT_TYPE_HARDLINK: |
| 11505 | + oh->equiv_id = |
| 11506 | + in->variant.hardlink_variant.equiv_id; |
| 11507 | + break; |
| 11508 | + case YAFFS_OBJECT_TYPE_SPECIAL: |
| 11509 | + /* Do nothing */ |
| 11510 | + break; |
| 11511 | + case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 11512 | + /* Do nothing */ |
| 11513 | + break; |
| 11514 | + case YAFFS_OBJECT_TYPE_SYMLINK: |
| 11515 | + alias = in->variant.symlink_variant.alias; |
| 11516 | + if(!alias) |
| 11517 | + alias = _Y("no alias"); |
| 11518 | + yaffs_strncpy(oh->alias, |
| 11519 | + alias, |
| 11520 | + YAFFS_MAX_ALIAS_LENGTH); |
| 11521 | + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; |
| 11522 | + break; |
| 11523 | } |
| 11524 | |
| 11525 | - retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >= |
| 11526 | - 0) ? YAFFS_OK : YAFFS_FAIL; |
| 11527 | - } else { |
| 11528 | - retVal = YAFFS_OK; |
| 11529 | - } |
| 11530 | + /* process any xattrib modifications */ |
| 11531 | + if(xmod) |
| 11532 | + yaffs_apply_xattrib_mod(in, (char *)buffer, xmod); |
| 11533 | |
| 11534 | - return retVal; |
| 11535 | |
| 11536 | -} |
| 11537 | + /* Tags */ |
| 11538 | + yaffs_init_tags(&newTags); |
| 11539 | + in->serial++; |
| 11540 | + newTags.chunk_id = 0; |
| 11541 | + newTags.obj_id = in->obj_id; |
| 11542 | + newTags.serial_number = in->serial; |
| 11543 | |
| 11544 | -static int yaffs_DoGenericObjectDeletion(yaffs_Object *in) |
| 11545 | -{ |
| 11546 | + /* Add extra info for file header */ |
| 11547 | |
| 11548 | - /* First off, invalidate the file's data in the cache, without flushing. */ |
| 11549 | - yaffs_InvalidateWholeChunkCache(in); |
| 11550 | + newTags.extra_available = 1; |
| 11551 | + newTags.extra_parent_id = oh->parent_obj_id; |
| 11552 | + newTags.extra_length = oh->file_size; |
| 11553 | + newTags.extra_is_shrink = oh->is_shrink; |
| 11554 | + newTags.extra_equiv_id = oh->equiv_id; |
| 11555 | + newTags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0; |
| 11556 | + newTags.extra_obj_type = in->variant_type; |
| 11557 | |
| 11558 | - if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) { |
| 11559 | - /* Move to the unlinked directory so we have a record that it was deleted. */ |
| 11560 | - yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0); |
| 11561 | + yaffs_verify_oh(in, oh, &newTags, 1); |
| 11562 | |
| 11563 | - } |
| 11564 | + /* Create new chunk in NAND */ |
| 11565 | + newChunkId = |
| 11566 | + yaffs_write_new_chunk(dev, buffer, &newTags, |
| 11567 | + (prevChunkId > 0) ? 1 : 0); |
| 11568 | |
| 11569 | - yaffs_RemoveObjectFromDirectory(in); |
| 11570 | - yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__); |
| 11571 | - in->hdrChunk = 0; |
| 11572 | + if (newChunkId >= 0) { |
| 11573 | |
| 11574 | - yaffs_FreeObject(in); |
| 11575 | - return YAFFS_OK; |
| 11576 | + in->hdr_chunk = newChunkId; |
| 11577 | |
| 11578 | -} |
| 11579 | + if (prevChunkId > 0) { |
| 11580 | + yaffs_chunk_del(dev, prevChunkId, 1, |
| 11581 | + __LINE__); |
| 11582 | + } |
| 11583 | |
| 11584 | -/* yaffs_DeleteFile deletes the whole file data |
| 11585 | - * and the inode associated with the file. |
| 11586 | - * It does not delete the links associated with the file. |
| 11587 | - */ |
| 11588 | -static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in) |
| 11589 | -{ |
| 11590 | + if (!yaffs_obj_cache_dirty(in)) |
| 11591 | + in->dirty = 0; |
| 11592 | |
| 11593 | - int retVal; |
| 11594 | - int immediateDeletion = 0; |
| 11595 | + /* If this was a shrink, then mark the block that the chunk lives on */ |
| 11596 | + if (is_shrink) { |
| 11597 | + bi = yaffs_get_block_info(in->my_dev, |
| 11598 | + newChunkId / in->my_dev->param.chunks_per_block); |
| 11599 | + bi->has_shrink_hdr = 1; |
| 11600 | + } |
| 11601 | |
| 11602 | -#ifdef __KERNEL__ |
| 11603 | - if (!in->myInode) |
| 11604 | - immediateDeletion = 1; |
| 11605 | -#else |
| 11606 | - if (in->inUse <= 0) |
| 11607 | - immediateDeletion = 1; |
| 11608 | -#endif |
| 11609 | + } |
| 11610 | + |
| 11611 | + retVal = newChunkId; |
| 11612 | |
| 11613 | - if (immediateDeletion) { |
| 11614 | - retVal = |
| 11615 | - yaffs_ChangeObjectName(in, in->myDev->deletedDir, |
| 11616 | - _Y("deleted"), 0, 0); |
| 11617 | - T(YAFFS_TRACE_TRACING, |
| 11618 | - (TSTR("yaffs: immediate deletion of file %d" TENDSTR), |
| 11619 | - in->objectId)); |
| 11620 | - in->deleted = 1; |
| 11621 | - in->myDev->nDeletedFiles++; |
| 11622 | - if (1 || in->myDev->isYaffs2) |
| 11623 | - yaffs_ResizeFile(in, 0); |
| 11624 | - yaffs_SoftDeleteFile(in); |
| 11625 | - } else { |
| 11626 | - retVal = |
| 11627 | - yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, |
| 11628 | - _Y("unlinked"), 0, 0); |
| 11629 | } |
| 11630 | |
| 11631 | + if (buffer) |
| 11632 | + yaffs_release_temp_buffer(dev, buffer, __LINE__); |
| 11633 | |
| 11634 | return retVal; |
| 11635 | } |
| 11636 | |
| 11637 | -int yaffs_DeleteFile(yaffs_Object *in) |
| 11638 | -{ |
| 11639 | - int retVal = YAFFS_OK; |
| 11640 | - int deleted = in->deleted; |
| 11641 | - |
| 11642 | - yaffs_ResizeFile(in, 0); |
| 11643 | - |
| 11644 | - if (in->nDataChunks > 0) { |
| 11645 | - /* Use soft deletion if there is data in the file. |
| 11646 | - * That won't be the case if it has been resized to zero. |
| 11647 | - */ |
| 11648 | - if (!in->unlinked) |
| 11649 | - retVal = yaffs_UnlinkFileIfNeeded(in); |
| 11650 | - |
| 11651 | - if (retVal == YAFFS_OK && in->unlinked && !in->deleted) { |
| 11652 | - in->deleted = 1; |
| 11653 | - deleted = 1; |
| 11654 | - in->myDev->nDeletedFiles++; |
| 11655 | - yaffs_SoftDeleteFile(in); |
| 11656 | - } |
| 11657 | - return deleted ? YAFFS_OK : YAFFS_FAIL; |
| 11658 | - } else { |
| 11659 | - /* The file has no data chunks so we toss it immediately */ |
| 11660 | - yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top); |
| 11661 | - in->variant.fileVariant.top = NULL; |
| 11662 | - yaffs_DoGenericObjectDeletion(in); |
| 11663 | - |
| 11664 | - return YAFFS_OK; |
| 11665 | - } |
| 11666 | -} |
| 11667 | +/*------------------------ Short Operations Cache ---------------------------------------- |
| 11668 | + * In many situations where there is no high level buffering (eg WinCE) a lot of |
| 11669 | + * reads might be short sequential reads, and a lot of writes may be short |
| 11670 | + * sequential writes. eg. scanning/writing a jpeg file. |
| 11671 | + * In these cases, a short read/write cache can provide a huge perfomance benefit |
| 11672 | + * with dumb-as-a-rock code. |
| 11673 | + * In Linux, the page cache provides read buffering aand the short op cache provides write |
| 11674 | + * buffering. |
| 11675 | + * |
| 11676 | + * There are a limited number (~10) of cache chunks per device so that we don't |
| 11677 | + * need a very intelligent search. |
| 11678 | + */ |
| 11679 | |
| 11680 | -static int yaffs_DeleteDirectory(yaffs_Object *in) |
| 11681 | +static int yaffs_obj_cache_dirty(yaffs_obj_t *obj) |
| 11682 | { |
| 11683 | - /* First check that the directory is empty. */ |
| 11684 | - if (ylist_empty(&in->variant.directoryVariant.children)) |
| 11685 | - return yaffs_DoGenericObjectDeletion(in); |
| 11686 | + yaffs_dev_t *dev = obj->my_dev; |
| 11687 | + int i; |
| 11688 | + yaffs_cache_t *cache; |
| 11689 | + int nCaches = obj->my_dev->param.n_caches; |
| 11690 | |
| 11691 | - return YAFFS_FAIL; |
| 11692 | + for (i = 0; i < nCaches; i++) { |
| 11693 | + cache = &dev->cache[i]; |
| 11694 | + if (cache->object == obj && |
| 11695 | + cache->dirty) |
| 11696 | + return 1; |
| 11697 | + } |
| 11698 | |
| 11699 | + return 0; |
| 11700 | } |
| 11701 | |
| 11702 | -static int yaffs_DeleteSymLink(yaffs_Object *in) |
| 11703 | -{ |
| 11704 | - YFREE(in->variant.symLinkVariant.alias); |
| 11705 | - |
| 11706 | - return yaffs_DoGenericObjectDeletion(in); |
| 11707 | -} |
| 11708 | |
| 11709 | -static int yaffs_DeleteHardLink(yaffs_Object *in) |
| 11710 | +static void yaffs_flush_file_cache(yaffs_obj_t *obj) |
| 11711 | { |
| 11712 | - /* remove this hardlink from the list assocaited with the equivalent |
| 11713 | - * object |
| 11714 | - */ |
| 11715 | - ylist_del_init(&in->hardLinks); |
| 11716 | - return yaffs_DoGenericObjectDeletion(in); |
| 11717 | -} |
| 11718 | + yaffs_dev_t *dev = obj->my_dev; |
| 11719 | + int lowest = -99; /* Stop compiler whining. */ |
| 11720 | + int i; |
| 11721 | + yaffs_cache_t *cache; |
| 11722 | + int chunkWritten = 0; |
| 11723 | + int nCaches = obj->my_dev->param.n_caches; |
| 11724 | |
| 11725 | -int yaffs_DeleteObject(yaffs_Object *obj) |
| 11726 | -{ |
| 11727 | -int retVal = -1; |
| 11728 | - switch (obj->variantType) { |
| 11729 | - case YAFFS_OBJECT_TYPE_FILE: |
| 11730 | - retVal = yaffs_DeleteFile(obj); |
| 11731 | - break; |
| 11732 | - case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 11733 | - return yaffs_DeleteDirectory(obj); |
| 11734 | - break; |
| 11735 | - case YAFFS_OBJECT_TYPE_SYMLINK: |
| 11736 | - retVal = yaffs_DeleteSymLink(obj); |
| 11737 | - break; |
| 11738 | - case YAFFS_OBJECT_TYPE_HARDLINK: |
| 11739 | - retVal = yaffs_DeleteHardLink(obj); |
| 11740 | - break; |
| 11741 | - case YAFFS_OBJECT_TYPE_SPECIAL: |
| 11742 | - retVal = yaffs_DoGenericObjectDeletion(obj); |
| 11743 | - break; |
| 11744 | - case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 11745 | - retVal = 0; |
| 11746 | - break; /* should not happen. */ |
| 11747 | - } |
| 11748 | + if (nCaches > 0) { |
| 11749 | + do { |
| 11750 | + cache = NULL; |
| 11751 | |
| 11752 | - return retVal; |
| 11753 | -} |
| 11754 | + /* Find the dirty cache for this object with the lowest chunk id. */ |
| 11755 | + for (i = 0; i < nCaches; i++) { |
| 11756 | + if (dev->cache[i].object == obj && |
| 11757 | + dev->cache[i].dirty) { |
| 11758 | + if (!cache |
| 11759 | + || dev->cache[i].chunk_id < |
| 11760 | + lowest) { |
| 11761 | + cache = &dev->cache[i]; |
| 11762 | + lowest = cache->chunk_id; |
| 11763 | + } |
| 11764 | + } |
| 11765 | + } |
| 11766 | |
| 11767 | -static int yaffs_UnlinkWorker(yaffs_Object *obj) |
| 11768 | -{ |
| 11769 | + if (cache && !cache->locked) { |
| 11770 | + /* Write it out and free it up */ |
| 11771 | |
| 11772 | - int immediateDeletion = 0; |
| 11773 | + chunkWritten = |
| 11774 | + yaffs_wr_data_obj(cache->object, |
| 11775 | + cache->chunk_id, |
| 11776 | + cache->data, |
| 11777 | + cache->n_bytes, |
| 11778 | + 1); |
| 11779 | + cache->dirty = 0; |
| 11780 | + cache->object = NULL; |
| 11781 | + } |
| 11782 | |
| 11783 | -#ifdef __KERNEL__ |
| 11784 | - if (!obj->myInode) |
| 11785 | - immediateDeletion = 1; |
| 11786 | -#else |
| 11787 | - if (obj->inUse <= 0) |
| 11788 | - immediateDeletion = 1; |
| 11789 | -#endif |
| 11790 | + } while (cache && chunkWritten > 0); |
| 11791 | |
| 11792 | - if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { |
| 11793 | - return yaffs_DeleteHardLink(obj); |
| 11794 | - } else if (!ylist_empty(&obj->hardLinks)) { |
| 11795 | - /* Curve ball: We're unlinking an object that has a hardlink. |
| 11796 | - * |
| 11797 | - * This problem arises because we are not strictly following |
| 11798 | - * The Linux link/inode model. |
| 11799 | - * |
| 11800 | - * We can't really delete the object. |
| 11801 | - * Instead, we do the following: |
| 11802 | - * - Select a hardlink. |
| 11803 | - * - Unhook it from the hard links |
| 11804 | - * - Unhook it from its parent directory (so that the rename can work) |
| 11805 | - * - Rename the object to the hardlink's name. |
| 11806 | - * - Delete the hardlink |
| 11807 | - */ |
| 11808 | + if (cache) { |
| 11809 | + /* Hoosterman, disk full while writing cache out. */ |
| 11810 | + T(YAFFS_TRACE_ERROR, |
| 11811 | + (TSTR("yaffs tragedy: no space during cache write" TENDSTR))); |
| 11812 | |
| 11813 | - yaffs_Object *hl; |
| 11814 | - int retVal; |
| 11815 | - YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; |
| 11816 | + } |
| 11817 | + } |
| 11818 | |
| 11819 | - hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks); |
| 11820 | +} |
| 11821 | |
| 11822 | - ylist_del_init(&hl->hardLinks); |
| 11823 | - ylist_del_init(&hl->siblings); |
| 11824 | +/*yaffs_flush_whole_cache(dev) |
| 11825 | + * |
| 11826 | + * |
| 11827 | + */ |
| 11828 | |
| 11829 | - yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); |
| 11830 | +void yaffs_flush_whole_cache(yaffs_dev_t *dev) |
| 11831 | +{ |
| 11832 | + yaffs_obj_t *obj; |
| 11833 | + int nCaches = dev->param.n_caches; |
| 11834 | + int i; |
| 11835 | |
| 11836 | - retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0); |
| 11837 | + /* Find a dirty object in the cache and flush it... |
| 11838 | + * until there are no further dirty objects. |
| 11839 | + */ |
| 11840 | + do { |
| 11841 | + obj = NULL; |
| 11842 | + for (i = 0; i < nCaches && !obj; i++) { |
| 11843 | + if (dev->cache[i].object && |
| 11844 | + dev->cache[i].dirty) |
| 11845 | + obj = dev->cache[i].object; |
| 11846 | |
| 11847 | - if (retVal == YAFFS_OK) |
| 11848 | - retVal = yaffs_DoGenericObjectDeletion(hl); |
| 11849 | + } |
| 11850 | + if (obj) |
| 11851 | + yaffs_flush_file_cache(obj); |
| 11852 | |
| 11853 | - return retVal; |
| 11854 | + } while (obj); |
| 11855 | |
| 11856 | - } else if (immediateDeletion) { |
| 11857 | - switch (obj->variantType) { |
| 11858 | - case YAFFS_OBJECT_TYPE_FILE: |
| 11859 | - return yaffs_DeleteFile(obj); |
| 11860 | - break; |
| 11861 | - case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 11862 | - return yaffs_DeleteDirectory(obj); |
| 11863 | - break; |
| 11864 | - case YAFFS_OBJECT_TYPE_SYMLINK: |
| 11865 | - return yaffs_DeleteSymLink(obj); |
| 11866 | - break; |
| 11867 | - case YAFFS_OBJECT_TYPE_SPECIAL: |
| 11868 | - return yaffs_DoGenericObjectDeletion(obj); |
| 11869 | - break; |
| 11870 | - case YAFFS_OBJECT_TYPE_HARDLINK: |
| 11871 | - case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 11872 | - default: |
| 11873 | - return YAFFS_FAIL; |
| 11874 | - } |
| 11875 | - } else |
| 11876 | - return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir, |
| 11877 | - _Y("unlinked"), 0, 0); |
| 11878 | } |
| 11879 | |
| 11880 | |
| 11881 | -static int yaffs_UnlinkObject(yaffs_Object *obj) |
| 11882 | +/* Grab us a cache chunk for use. |
| 11883 | + * First look for an empty one. |
| 11884 | + * Then look for the least recently used non-dirty one. |
| 11885 | + * Then look for the least recently used dirty one...., flush and look again. |
| 11886 | + */ |
| 11887 | +static yaffs_cache_t *yaffs_grab_chunk_worker(yaffs_dev_t *dev) |
| 11888 | { |
| 11889 | + int i; |
| 11890 | |
| 11891 | - if (obj && obj->unlinkAllowed) |
| 11892 | - return yaffs_UnlinkWorker(obj); |
| 11893 | - |
| 11894 | - return YAFFS_FAIL; |
| 11895 | - |
| 11896 | -} |
| 11897 | -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name) |
| 11898 | -{ |
| 11899 | - yaffs_Object *obj; |
| 11900 | + if (dev->param.n_caches > 0) { |
| 11901 | + for (i = 0; i < dev->param.n_caches; i++) { |
| 11902 | + if (!dev->cache[i].object) |
| 11903 | + return &dev->cache[i]; |
| 11904 | + } |
| 11905 | + } |
| 11906 | |
| 11907 | - obj = yaffs_FindObjectByName(dir, name); |
| 11908 | - return yaffs_UnlinkObject(obj); |
| 11909 | + return NULL; |
| 11910 | } |
| 11911 | |
| 11912 | -/*----------------------- Initialisation Scanning ---------------------- */ |
| 11913 | - |
| 11914 | -static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, |
| 11915 | - int backwardScanning) |
| 11916 | +static yaffs_cache_t *yaffs_grab_chunk_cache(yaffs_dev_t *dev) |
| 11917 | { |
| 11918 | - yaffs_Object *obj; |
| 11919 | + yaffs_cache_t *cache; |
| 11920 | + yaffs_obj_t *theObj; |
| 11921 | + int usage; |
| 11922 | + int i; |
| 11923 | + int pushout; |
| 11924 | |
| 11925 | - if (!backwardScanning) { |
| 11926 | - /* Handle YAFFS1 forward scanning case |
| 11927 | - * For YAFFS1 we always do the deletion |
| 11928 | - */ |
| 11929 | + if (dev->param.n_caches > 0) { |
| 11930 | + /* Try find a non-dirty one... */ |
| 11931 | |
| 11932 | - } else { |
| 11933 | - /* Handle YAFFS2 case (backward scanning) |
| 11934 | - * If the shadowed object exists then ignore. |
| 11935 | - */ |
| 11936 | - if (yaffs_FindObjectByNumber(dev, objId)) |
| 11937 | - return; |
| 11938 | - } |
| 11939 | + cache = yaffs_grab_chunk_worker(dev); |
| 11940 | |
| 11941 | - /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc. |
| 11942 | - * We put it in unlinked dir to be cleaned up after the scanning |
| 11943 | - */ |
| 11944 | - obj = |
| 11945 | - yaffs_FindOrCreateObjectByNumber(dev, objId, |
| 11946 | - YAFFS_OBJECT_TYPE_FILE); |
| 11947 | - if (!obj) |
| 11948 | - return; |
| 11949 | - yaffs_AddObjectToDirectory(dev->unlinkedDir, obj); |
| 11950 | - obj->variant.fileVariant.shrinkSize = 0; |
| 11951 | - obj->valid = 1; /* So that we don't read any other info for this file */ |
| 11952 | + if (!cache) { |
| 11953 | + /* They were all dirty, find the last recently used object and flush |
| 11954 | + * its cache, then find again. |
| 11955 | + * NB what's here is not very accurate, we actually flush the object |
| 11956 | + * the last recently used page. |
| 11957 | + */ |
| 11958 | |
| 11959 | -} |
| 11960 | + /* With locking we can't assume we can use entry zero */ |
| 11961 | |
| 11962 | -typedef struct { |
| 11963 | - int seq; |
| 11964 | - int block; |
| 11965 | -} yaffs_BlockIndex; |
| 11966 | + theObj = NULL; |
| 11967 | + usage = -1; |
| 11968 | + cache = NULL; |
| 11969 | + pushout = -1; |
| 11970 | |
| 11971 | + for (i = 0; i < dev->param.n_caches; i++) { |
| 11972 | + if (dev->cache[i].object && |
| 11973 | + !dev->cache[i].locked && |
| 11974 | + (dev->cache[i].last_use < usage || !cache)) { |
| 11975 | + usage = dev->cache[i].last_use; |
| 11976 | + theObj = dev->cache[i].object; |
| 11977 | + cache = &dev->cache[i]; |
| 11978 | + pushout = i; |
| 11979 | + } |
| 11980 | + } |
| 11981 | |
| 11982 | -static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList) |
| 11983 | -{ |
| 11984 | - yaffs_Object *hl; |
| 11985 | - yaffs_Object *in; |
| 11986 | + if (!cache || cache->dirty) { |
| 11987 | + /* Flush and try again */ |
| 11988 | + yaffs_flush_file_cache(theObj); |
| 11989 | + cache = yaffs_grab_chunk_worker(dev); |
| 11990 | + } |
| 11991 | |
| 11992 | - while (hardList) { |
| 11993 | - hl = hardList; |
| 11994 | - hardList = (yaffs_Object *) (hardList->hardLinks.next); |
| 11995 | + } |
| 11996 | + return cache; |
| 11997 | + } else |
| 11998 | + return NULL; |
| 11999 | |
| 12000 | - in = yaffs_FindObjectByNumber(dev, |
| 12001 | - hl->variant.hardLinkVariant. |
| 12002 | - equivalentObjectId); |
| 12003 | +} |
| 12004 | |
| 12005 | - if (in) { |
| 12006 | - /* Add the hardlink pointers */ |
| 12007 | - hl->variant.hardLinkVariant.equivalentObject = in; |
| 12008 | - ylist_add(&hl->hardLinks, &in->hardLinks); |
| 12009 | - } else { |
| 12010 | - /* Todo Need to report/handle this better. |
| 12011 | - * Got a problem... hardlink to a non-existant object |
| 12012 | - */ |
| 12013 | - hl->variant.hardLinkVariant.equivalentObject = NULL; |
| 12014 | - YINIT_LIST_HEAD(&hl->hardLinks); |
| 12015 | +/* Find a cached chunk */ |
| 12016 | +static yaffs_cache_t *yaffs_find_chunk_cache(const yaffs_obj_t *obj, |
| 12017 | + int chunk_id) |
| 12018 | +{ |
| 12019 | + yaffs_dev_t *dev = obj->my_dev; |
| 12020 | + int i; |
| 12021 | + if (dev->param.n_caches > 0) { |
| 12022 | + for (i = 0; i < dev->param.n_caches; i++) { |
| 12023 | + if (dev->cache[i].object == obj && |
| 12024 | + dev->cache[i].chunk_id == chunk_id) { |
| 12025 | + dev->cache_hits++; |
| 12026 | |
| 12027 | + return &dev->cache[i]; |
| 12028 | + } |
| 12029 | } |
| 12030 | } |
| 12031 | + return NULL; |
| 12032 | } |
| 12033 | |
| 12034 | +/* Mark the chunk for the least recently used algorithym */ |
| 12035 | +static void yaffs_use_cache(yaffs_dev_t *dev, yaffs_cache_t *cache, |
| 12036 | + int isAWrite) |
| 12037 | +{ |
| 12038 | + |
| 12039 | + if (dev->param.n_caches > 0) { |
| 12040 | + if (dev->cache_last_use < 0 || dev->cache_last_use > 100000000) { |
| 12041 | + /* Reset the cache usages */ |
| 12042 | + int i; |
| 12043 | + for (i = 1; i < dev->param.n_caches; i++) |
| 12044 | + dev->cache[i].last_use = 0; |
| 12045 | |
| 12046 | + dev->cache_last_use = 0; |
| 12047 | + } |
| 12048 | |
| 12049 | + dev->cache_last_use++; |
| 12050 | |
| 12051 | + cache->last_use = dev->cache_last_use; |
| 12052 | |
| 12053 | -static int ybicmp(const void *a, const void *b) |
| 12054 | -{ |
| 12055 | - register int aseq = ((yaffs_BlockIndex *)a)->seq; |
| 12056 | - register int bseq = ((yaffs_BlockIndex *)b)->seq; |
| 12057 | - register int ablock = ((yaffs_BlockIndex *)a)->block; |
| 12058 | - register int bblock = ((yaffs_BlockIndex *)b)->block; |
| 12059 | - if (aseq == bseq) |
| 12060 | - return ablock - bblock; |
| 12061 | - else |
| 12062 | - return aseq - bseq; |
| 12063 | + if (isAWrite) |
| 12064 | + cache->dirty = 1; |
| 12065 | + } |
| 12066 | } |
| 12067 | |
| 12068 | +/* Invalidate a single cache page. |
| 12069 | + * Do this when a whole page gets written, |
| 12070 | + * ie the short cache for this page is no longer valid. |
| 12071 | + */ |
| 12072 | +static void yaffs_invalidate_chunk_cache(yaffs_obj_t *object, int chunk_id) |
| 12073 | +{ |
| 12074 | + if (object->my_dev->param.n_caches > 0) { |
| 12075 | + yaffs_cache_t *cache = yaffs_find_chunk_cache(object, chunk_id); |
| 12076 | |
| 12077 | -struct yaffs_ShadowFixerStruct { |
| 12078 | - int objectId; |
| 12079 | - int shadowedId; |
| 12080 | - struct yaffs_ShadowFixerStruct *next; |
| 12081 | -}; |
| 12082 | - |
| 12083 | + if (cache) |
| 12084 | + cache->object = NULL; |
| 12085 | + } |
| 12086 | +} |
| 12087 | |
| 12088 | -static void yaffs_StripDeletedObjects(yaffs_Device *dev) |
| 12089 | +/* Invalidate all the cache pages associated with this object |
| 12090 | + * Do this whenever ther file is deleted or resized. |
| 12091 | + */ |
| 12092 | +static void yaffs_invalidate_whole_cache(yaffs_obj_t *in) |
| 12093 | { |
| 12094 | - /* |
| 12095 | - * Sort out state of unlinked and deleted objects after scanning. |
| 12096 | - */ |
| 12097 | - struct ylist_head *i; |
| 12098 | - struct ylist_head *n; |
| 12099 | - yaffs_Object *l; |
| 12100 | + int i; |
| 12101 | + yaffs_dev_t *dev = in->my_dev; |
| 12102 | |
| 12103 | - /* Soft delete all the unlinked files */ |
| 12104 | - ylist_for_each_safe(i, n, |
| 12105 | - &dev->unlinkedDir->variant.directoryVariant.children) { |
| 12106 | - if (i) { |
| 12107 | - l = ylist_entry(i, yaffs_Object, siblings); |
| 12108 | - yaffs_DeleteObject(l); |
| 12109 | + if (dev->param.n_caches > 0) { |
| 12110 | + /* Invalidate it. */ |
| 12111 | + for (i = 0; i < dev->param.n_caches; i++) { |
| 12112 | + if (dev->cache[i].object == in) |
| 12113 | + dev->cache[i].object = NULL; |
| 12114 | } |
| 12115 | } |
| 12116 | +} |
| 12117 | |
| 12118 | - ylist_for_each_safe(i, n, |
| 12119 | - &dev->deletedDir->variant.directoryVariant.children) { |
| 12120 | - if (i) { |
| 12121 | - l = ylist_entry(i, yaffs_Object, siblings); |
| 12122 | - yaffs_DeleteObject(l); |
| 12123 | - } |
| 12124 | - } |
| 12125 | |
| 12126 | -} |
| 12127 | +/*--------------------- File read/write ------------------------ |
| 12128 | + * Read and write have very similar structures. |
| 12129 | + * In general the read/write has three parts to it |
| 12130 | + * An incomplete chunk to start with (if the read/write is not chunk-aligned) |
| 12131 | + * Some complete chunks |
| 12132 | + * An incomplete chunk to end off with |
| 12133 | + * |
| 12134 | + * Curve-balls: the first chunk might also be the last chunk. |
| 12135 | + */ |
| 12136 | |
| 12137 | -static int yaffs_Scan(yaffs_Device *dev) |
| 12138 | +int yaffs_file_rd(yaffs_obj_t *in, __u8 *buffer, loff_t offset, |
| 12139 | + int n_bytes) |
| 12140 | { |
| 12141 | - yaffs_ExtendedTags tags; |
| 12142 | - int blk; |
| 12143 | - int blockIterator; |
| 12144 | - int startIterator; |
| 12145 | - int endIterator; |
| 12146 | - int result; |
| 12147 | |
| 12148 | int chunk; |
| 12149 | - int c; |
| 12150 | - int deleted; |
| 12151 | - yaffs_BlockState state; |
| 12152 | - yaffs_Object *hardList = NULL; |
| 12153 | - yaffs_BlockInfo *bi; |
| 12154 | - __u32 sequenceNumber; |
| 12155 | - yaffs_ObjectHeader *oh; |
| 12156 | - yaffs_Object *in; |
| 12157 | - yaffs_Object *parent; |
| 12158 | + __u32 start; |
| 12159 | + int nToCopy; |
| 12160 | + int n = n_bytes; |
| 12161 | + int nDone = 0; |
| 12162 | + yaffs_cache_t *cache; |
| 12163 | |
| 12164 | - int alloc_failed = 0; |
| 12165 | + yaffs_dev_t *dev; |
| 12166 | |
| 12167 | - struct yaffs_ShadowFixerStruct *shadowFixerList = NULL; |
| 12168 | + dev = in->my_dev; |
| 12169 | |
| 12170 | + while (n > 0) { |
| 12171 | + /* chunk = offset / dev->data_bytes_per_chunk + 1; */ |
| 12172 | + /* start = offset % dev->data_bytes_per_chunk; */ |
| 12173 | + yaffs_addr_to_chunk(dev, offset, &chunk, &start); |
| 12174 | + chunk++; |
| 12175 | |
| 12176 | - __u8 *chunkData; |
| 12177 | + /* OK now check for the curveball where the start and end are in |
| 12178 | + * the same chunk. |
| 12179 | + */ |
| 12180 | + if ((start + n) < dev->data_bytes_per_chunk) |
| 12181 | + nToCopy = n; |
| 12182 | + else |
| 12183 | + nToCopy = dev->data_bytes_per_chunk - start; |
| 12184 | |
| 12185 | + cache = yaffs_find_chunk_cache(in, chunk); |
| 12186 | |
| 12187 | + /* If the chunk is already in the cache or it is less than a whole chunk |
| 12188 | + * or we're using inband tags then use the cache (if there is caching) |
| 12189 | + * else bypass the cache. |
| 12190 | + */ |
| 12191 | + if (cache || nToCopy != dev->data_bytes_per_chunk || dev->param.inband_tags) { |
| 12192 | + if (dev->param.n_caches > 0) { |
| 12193 | |
| 12194 | - T(YAFFS_TRACE_SCAN, |
| 12195 | - (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), |
| 12196 | - dev->internalStartBlock, dev->internalEndBlock)); |
| 12197 | + /* If we can't find the data in the cache, then load it up. */ |
| 12198 | |
| 12199 | - chunkData = yaffs_GetTempBuffer(dev, __LINE__); |
| 12200 | + if (!cache) { |
| 12201 | + cache = yaffs_grab_chunk_cache(in->my_dev); |
| 12202 | + cache->object = in; |
| 12203 | + cache->chunk_id = chunk; |
| 12204 | + cache->dirty = 0; |
| 12205 | + cache->locked = 0; |
| 12206 | + yaffs_rd_data_obj(in, chunk, |
| 12207 | + cache-> |
| 12208 | + data); |
| 12209 | + cache->n_bytes = 0; |
| 12210 | + } |
| 12211 | |
| 12212 | - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; |
| 12213 | + yaffs_use_cache(dev, cache, 0); |
| 12214 | |
| 12215 | - /* Scan all the blocks to determine their state */ |
| 12216 | - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { |
| 12217 | - bi = yaffs_GetBlockInfo(dev, blk); |
| 12218 | - yaffs_ClearChunkBits(dev, blk); |
| 12219 | - bi->pagesInUse = 0; |
| 12220 | - bi->softDeletions = 0; |
| 12221 | + cache->locked = 1; |
| 12222 | |
| 12223 | - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); |
| 12224 | |
| 12225 | - bi->blockState = state; |
| 12226 | - bi->sequenceNumber = sequenceNumber; |
| 12227 | + memcpy(buffer, &cache->data[start], nToCopy); |
| 12228 | |
| 12229 | - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK) |
| 12230 | - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD; |
| 12231 | + cache->locked = 0; |
| 12232 | + } else { |
| 12233 | + /* Read into the local buffer then copy..*/ |
| 12234 | |
| 12235 | - T(YAFFS_TRACE_SCAN_DEBUG, |
| 12236 | - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, |
| 12237 | - state, sequenceNumber)); |
| 12238 | + __u8 *localBuffer = |
| 12239 | + yaffs_get_temp_buffer(dev, __LINE__); |
| 12240 | + yaffs_rd_data_obj(in, chunk, |
| 12241 | + localBuffer); |
| 12242 | |
| 12243 | - if (state == YAFFS_BLOCK_STATE_DEAD) { |
| 12244 | - T(YAFFS_TRACE_BAD_BLOCKS, |
| 12245 | - (TSTR("block %d is bad" TENDSTR), blk)); |
| 12246 | - } else if (state == YAFFS_BLOCK_STATE_EMPTY) { |
| 12247 | - T(YAFFS_TRACE_SCAN_DEBUG, |
| 12248 | - (TSTR("Block empty " TENDSTR))); |
| 12249 | - dev->nErasedBlocks++; |
| 12250 | - dev->nFreeChunks += dev->nChunksPerBlock; |
| 12251 | - } |
| 12252 | - } |
| 12253 | + memcpy(buffer, &localBuffer[start], nToCopy); |
| 12254 | |
| 12255 | - startIterator = dev->internalStartBlock; |
| 12256 | - endIterator = dev->internalEndBlock; |
| 12257 | |
| 12258 | - /* For each block.... */ |
| 12259 | - for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; |
| 12260 | - blockIterator++) { |
| 12261 | + yaffs_release_temp_buffer(dev, localBuffer, |
| 12262 | + __LINE__); |
| 12263 | + } |
| 12264 | |
| 12265 | - YYIELD(); |
| 12266 | + } else { |
| 12267 | |
| 12268 | - YYIELD(); |
| 12269 | + /* A full chunk. Read directly into the supplied buffer. */ |
| 12270 | + yaffs_rd_data_obj(in, chunk, buffer); |
| 12271 | |
| 12272 | - blk = blockIterator; |
| 12273 | + } |
| 12274 | |
| 12275 | - bi = yaffs_GetBlockInfo(dev, blk); |
| 12276 | - state = bi->blockState; |
| 12277 | + n -= nToCopy; |
| 12278 | + offset += nToCopy; |
| 12279 | + buffer += nToCopy; |
| 12280 | + nDone += nToCopy; |
| 12281 | |
| 12282 | - deleted = 0; |
| 12283 | + } |
| 12284 | |
| 12285 | - /* For each chunk in each block that needs scanning....*/ |
| 12286 | - for (c = 0; !alloc_failed && c < dev->nChunksPerBlock && |
| 12287 | - state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { |
| 12288 | - /* Read the tags and decide what to do */ |
| 12289 | - chunk = blk * dev->nChunksPerBlock + c; |
| 12290 | + return nDone; |
| 12291 | +} |
| 12292 | |
| 12293 | - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, |
| 12294 | - &tags); |
| 12295 | +int yaffs_do_file_wr(yaffs_obj_t *in, const __u8 *buffer, loff_t offset, |
| 12296 | + int n_bytes, int write_trhrough) |
| 12297 | +{ |
| 12298 | |
| 12299 | - /* Let's have a good look at this chunk... */ |
| 12300 | + int chunk; |
| 12301 | + __u32 start; |
| 12302 | + int nToCopy; |
| 12303 | + int n = n_bytes; |
| 12304 | + int nDone = 0; |
| 12305 | + int nToWriteBack; |
| 12306 | + int startOfWrite = offset; |
| 12307 | + int chunkWritten = 0; |
| 12308 | + __u32 n_bytesRead; |
| 12309 | + __u32 chunkStart; |
| 12310 | |
| 12311 | - if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) { |
| 12312 | - /* YAFFS1 only... |
| 12313 | - * A deleted chunk |
| 12314 | - */ |
| 12315 | - deleted++; |
| 12316 | - dev->nFreeChunks++; |
| 12317 | - /*T((" %d %d deleted\n",blk,c)); */ |
| 12318 | - } else if (!tags.chunkUsed) { |
| 12319 | - /* An unassigned chunk in the block |
| 12320 | - * This means that either the block is empty or |
| 12321 | - * this is the one being allocated from |
| 12322 | - */ |
| 12323 | + yaffs_dev_t *dev; |
| 12324 | |
| 12325 | - if (c == 0) { |
| 12326 | - /* We're looking at the first chunk in the block so the block is unused */ |
| 12327 | - state = YAFFS_BLOCK_STATE_EMPTY; |
| 12328 | - dev->nErasedBlocks++; |
| 12329 | - } else { |
| 12330 | - /* this is the block being allocated from */ |
| 12331 | - T(YAFFS_TRACE_SCAN, |
| 12332 | - (TSTR |
| 12333 | - (" Allocating from %d %d" TENDSTR), |
| 12334 | - blk, c)); |
| 12335 | - state = YAFFS_BLOCK_STATE_ALLOCATING; |
| 12336 | - dev->allocationBlock = blk; |
| 12337 | - dev->allocationPage = c; |
| 12338 | - dev->allocationBlockFinder = blk; |
| 12339 | - /* Set it to here to encourage the allocator to go forth from here. */ |
| 12340 | + dev = in->my_dev; |
| 12341 | |
| 12342 | - } |
| 12343 | + while (n > 0 && chunkWritten >= 0) { |
| 12344 | + yaffs_addr_to_chunk(dev, offset, &chunk, &start); |
| 12345 | |
| 12346 | - dev->nFreeChunks += (dev->nChunksPerBlock - c); |
| 12347 | - } else if (tags.chunkId > 0) { |
| 12348 | - /* chunkId > 0 so it is a data chunk... */ |
| 12349 | - unsigned int endpos; |
| 12350 | - |
| 12351 | - yaffs_SetChunkBit(dev, blk, c); |
| 12352 | - bi->pagesInUse++; |
| 12353 | - |
| 12354 | - in = yaffs_FindOrCreateObjectByNumber(dev, |
| 12355 | - tags. |
| 12356 | - objectId, |
| 12357 | - YAFFS_OBJECT_TYPE_FILE); |
| 12358 | - /* PutChunkIntoFile checks for a clash (two data chunks with |
| 12359 | - * the same chunkId). |
| 12360 | - */ |
| 12361 | + if (chunk * dev->data_bytes_per_chunk + start != offset || |
| 12362 | + start >= dev->data_bytes_per_chunk) { |
| 12363 | + T(YAFFS_TRACE_ERROR, ( |
| 12364 | + TSTR("AddrToChunk of offset %d gives chunk %d start %d" |
| 12365 | + TENDSTR), |
| 12366 | + (int)offset, chunk, start)); |
| 12367 | + } |
| 12368 | + chunk++; /* File pos to chunk in file offset */ |
| 12369 | |
| 12370 | - if (!in) |
| 12371 | - alloc_failed = 1; |
| 12372 | + /* OK now check for the curveball where the start and end are in |
| 12373 | + * the same chunk. |
| 12374 | + */ |
| 12375 | |
| 12376 | - if (in) { |
| 12377 | - if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1)) |
| 12378 | - alloc_failed = 1; |
| 12379 | - } |
| 12380 | + if ((start + n) < dev->data_bytes_per_chunk) { |
| 12381 | + nToCopy = n; |
| 12382 | |
| 12383 | - endpos = |
| 12384 | - (tags.chunkId - 1) * dev->nDataBytesPerChunk + |
| 12385 | - tags.byteCount; |
| 12386 | - if (in && |
| 12387 | - in->variantType == YAFFS_OBJECT_TYPE_FILE |
| 12388 | - && in->variant.fileVariant.scannedFileSize < |
| 12389 | - endpos) { |
| 12390 | - in->variant.fileVariant. |
| 12391 | - scannedFileSize = endpos; |
| 12392 | - if (!dev->useHeaderFileSize) { |
| 12393 | - in->variant.fileVariant. |
| 12394 | - fileSize = |
| 12395 | - in->variant.fileVariant. |
| 12396 | - scannedFileSize; |
| 12397 | - } |
| 12398 | + /* Now folks, to calculate how many bytes to write back.... |
| 12399 | + * If we're overwriting and not writing to then end of file then |
| 12400 | + * we need to write back as much as was there before. |
| 12401 | + */ |
| 12402 | |
| 12403 | - } |
| 12404 | - /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */ |
| 12405 | - } else { |
| 12406 | - /* chunkId == 0, so it is an ObjectHeader. |
| 12407 | - * Thus, we read in the object header and make the object |
| 12408 | - */ |
| 12409 | - yaffs_SetChunkBit(dev, blk, c); |
| 12410 | - bi->pagesInUse++; |
| 12411 | + chunkStart = ((chunk - 1) * dev->data_bytes_per_chunk); |
| 12412 | |
| 12413 | - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, |
| 12414 | - chunkData, |
| 12415 | - NULL); |
| 12416 | - |
| 12417 | - oh = (yaffs_ObjectHeader *) chunkData; |
| 12418 | - |
| 12419 | - in = yaffs_FindObjectByNumber(dev, |
| 12420 | - tags.objectId); |
| 12421 | - if (in && in->variantType != oh->type) { |
| 12422 | - /* This should not happen, but somehow |
| 12423 | - * Wev'e ended up with an objectId that has been reused but not yet |
| 12424 | - * deleted, and worse still it has changed type. Delete the old object. |
| 12425 | - */ |
| 12426 | + if (chunkStart > in->variant.file_variant.file_size) |
| 12427 | + n_bytesRead = 0; /* Past end of file */ |
| 12428 | + else |
| 12429 | + n_bytesRead = in->variant.file_variant.file_size - chunkStart; |
| 12430 | |
| 12431 | - yaffs_DeleteObject(in); |
| 12432 | + if (n_bytesRead > dev->data_bytes_per_chunk) |
| 12433 | + n_bytesRead = dev->data_bytes_per_chunk; |
| 12434 | |
| 12435 | - in = 0; |
| 12436 | - } |
| 12437 | + nToWriteBack = |
| 12438 | + (n_bytesRead > |
| 12439 | + (start + n)) ? n_bytesRead : (start + n); |
| 12440 | |
| 12441 | - in = yaffs_FindOrCreateObjectByNumber(dev, |
| 12442 | - tags. |
| 12443 | - objectId, |
| 12444 | - oh->type); |
| 12445 | - |
| 12446 | - if (!in) |
| 12447 | - alloc_failed = 1; |
| 12448 | - |
| 12449 | - if (in && oh->shadowsObject > 0) { |
| 12450 | - |
| 12451 | - struct yaffs_ShadowFixerStruct *fixer; |
| 12452 | - fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct)); |
| 12453 | - if (fixer) { |
| 12454 | - fixer->next = shadowFixerList; |
| 12455 | - shadowFixerList = fixer; |
| 12456 | - fixer->objectId = tags.objectId; |
| 12457 | - fixer->shadowedId = oh->shadowsObject; |
| 12458 | - } |
| 12459 | + if (nToWriteBack < 0 || nToWriteBack > dev->data_bytes_per_chunk) |
| 12460 | + YBUG(); |
| 12461 | + |
| 12462 | + } else { |
| 12463 | + nToCopy = dev->data_bytes_per_chunk - start; |
| 12464 | + nToWriteBack = dev->data_bytes_per_chunk; |
| 12465 | + } |
| 12466 | + |
| 12467 | + if (nToCopy != dev->data_bytes_per_chunk || dev->param.inband_tags) { |
| 12468 | + /* An incomplete start or end chunk (or maybe both start and end chunk), |
| 12469 | + * or we're using inband tags, so we want to use the cache buffers. |
| 12470 | + */ |
| 12471 | + if (dev->param.n_caches > 0) { |
| 12472 | + yaffs_cache_t *cache; |
| 12473 | + /* If we can't find the data in the cache, then load the cache */ |
| 12474 | + cache = yaffs_find_chunk_cache(in, chunk); |
| 12475 | |
| 12476 | + if (!cache |
| 12477 | + && yaffs_check_alloc_available(dev, 1)) { |
| 12478 | + cache = yaffs_grab_chunk_cache(dev); |
| 12479 | + cache->object = in; |
| 12480 | + cache->chunk_id = chunk; |
| 12481 | + cache->dirty = 0; |
| 12482 | + cache->locked = 0; |
| 12483 | + yaffs_rd_data_obj(in, chunk, |
| 12484 | + cache->data); |
| 12485 | + } else if (cache && |
| 12486 | + !cache->dirty && |
| 12487 | + !yaffs_check_alloc_available(dev, 1)) { |
| 12488 | + /* Drop the cache if it was a read cache item and |
| 12489 | + * no space check has been made for it. |
| 12490 | + */ |
| 12491 | + cache = NULL; |
| 12492 | } |
| 12493 | |
| 12494 | - if (in && in->valid) { |
| 12495 | - /* We have already filled this one. We have a duplicate and need to resolve it. */ |
| 12496 | + if (cache) { |
| 12497 | + yaffs_use_cache(dev, cache, 1); |
| 12498 | + cache->locked = 1; |
| 12499 | |
| 12500 | - unsigned existingSerial = in->serial; |
| 12501 | - unsigned newSerial = tags.serialNumber; |
| 12502 | |
| 12503 | - if (((existingSerial + 1) & 3) == newSerial) { |
| 12504 | - /* Use new one - destroy the exisiting one */ |
| 12505 | - yaffs_DeleteChunk(dev, |
| 12506 | - in->hdrChunk, |
| 12507 | - 1, __LINE__); |
| 12508 | - in->valid = 0; |
| 12509 | - } else { |
| 12510 | - /* Use existing - destroy this one. */ |
| 12511 | - yaffs_DeleteChunk(dev, chunk, 1, |
| 12512 | - __LINE__); |
| 12513 | + memcpy(&cache->data[start], buffer, |
| 12514 | + nToCopy); |
| 12515 | + |
| 12516 | + |
| 12517 | + cache->locked = 0; |
| 12518 | + cache->n_bytes = nToWriteBack; |
| 12519 | + |
| 12520 | + if (write_trhrough) { |
| 12521 | + chunkWritten = |
| 12522 | + yaffs_wr_data_obj |
| 12523 | + (cache->object, |
| 12524 | + cache->chunk_id, |
| 12525 | + cache->data, cache->n_bytes, |
| 12526 | + 1); |
| 12527 | + cache->dirty = 0; |
| 12528 | } |
| 12529 | + |
| 12530 | + } else { |
| 12531 | + chunkWritten = -1; /* fail the write */ |
| 12532 | } |
| 12533 | + } else { |
| 12534 | + /* An incomplete start or end chunk (or maybe both start and end chunk) |
| 12535 | + * Read into the local buffer then copy, then copy over and write back. |
| 12536 | + */ |
| 12537 | |
| 12538 | - if (in && !in->valid && |
| 12539 | - (tags.objectId == YAFFS_OBJECTID_ROOT || |
| 12540 | - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) { |
| 12541 | - /* We only load some info, don't fiddle with directory structure */ |
| 12542 | - in->valid = 1; |
| 12543 | - in->variantType = oh->type; |
| 12544 | + __u8 *localBuffer = |
| 12545 | + yaffs_get_temp_buffer(dev, __LINE__); |
| 12546 | |
| 12547 | - in->yst_mode = oh->yst_mode; |
| 12548 | -#ifdef CONFIG_YAFFS_WINCE |
| 12549 | - in->win_atime[0] = oh->win_atime[0]; |
| 12550 | - in->win_ctime[0] = oh->win_ctime[0]; |
| 12551 | - in->win_mtime[0] = oh->win_mtime[0]; |
| 12552 | - in->win_atime[1] = oh->win_atime[1]; |
| 12553 | - in->win_ctime[1] = oh->win_ctime[1]; |
| 12554 | - in->win_mtime[1] = oh->win_mtime[1]; |
| 12555 | -#else |
| 12556 | - in->yst_uid = oh->yst_uid; |
| 12557 | - in->yst_gid = oh->yst_gid; |
| 12558 | - in->yst_atime = oh->yst_atime; |
| 12559 | - in->yst_mtime = oh->yst_mtime; |
| 12560 | - in->yst_ctime = oh->yst_ctime; |
| 12561 | - in->yst_rdev = oh->yst_rdev; |
| 12562 | -#endif |
| 12563 | - in->hdrChunk = chunk; |
| 12564 | - in->serial = tags.serialNumber; |
| 12565 | + yaffs_rd_data_obj(in, chunk, |
| 12566 | + localBuffer); |
| 12567 | |
| 12568 | - } else if (in && !in->valid) { |
| 12569 | - /* we need to load this info */ |
| 12570 | |
| 12571 | - in->valid = 1; |
| 12572 | - in->variantType = oh->type; |
| 12573 | |
| 12574 | - in->yst_mode = oh->yst_mode; |
| 12575 | -#ifdef CONFIG_YAFFS_WINCE |
| 12576 | - in->win_atime[0] = oh->win_atime[0]; |
| 12577 | - in->win_ctime[0] = oh->win_ctime[0]; |
| 12578 | - in->win_mtime[0] = oh->win_mtime[0]; |
| 12579 | - in->win_atime[1] = oh->win_atime[1]; |
| 12580 | - in->win_ctime[1] = oh->win_ctime[1]; |
| 12581 | - in->win_mtime[1] = oh->win_mtime[1]; |
| 12582 | -#else |
| 12583 | - in->yst_uid = oh->yst_uid; |
| 12584 | - in->yst_gid = oh->yst_gid; |
| 12585 | - in->yst_atime = oh->yst_atime; |
| 12586 | - in->yst_mtime = oh->yst_mtime; |
| 12587 | - in->yst_ctime = oh->yst_ctime; |
| 12588 | - in->yst_rdev = oh->yst_rdev; |
| 12589 | -#endif |
| 12590 | - in->hdrChunk = chunk; |
| 12591 | - in->serial = tags.serialNumber; |
| 12592 | + memcpy(&localBuffer[start], buffer, nToCopy); |
| 12593 | |
| 12594 | - yaffs_SetObjectName(in, oh->name); |
| 12595 | - in->dirty = 0; |
| 12596 | + chunkWritten = |
| 12597 | + yaffs_wr_data_obj(in, chunk, |
| 12598 | + localBuffer, |
| 12599 | + nToWriteBack, |
| 12600 | + 0); |
| 12601 | |
| 12602 | - /* directory stuff... |
| 12603 | - * hook up to parent |
| 12604 | - */ |
| 12605 | + yaffs_release_temp_buffer(dev, localBuffer, |
| 12606 | + __LINE__); |
| 12607 | |
| 12608 | - parent = |
| 12609 | - yaffs_FindOrCreateObjectByNumber |
| 12610 | - (dev, oh->parentObjectId, |
| 12611 | - YAFFS_OBJECT_TYPE_DIRECTORY); |
| 12612 | - if (!parent) |
| 12613 | - alloc_failed = 1; |
| 12614 | - if (parent && parent->variantType == |
| 12615 | - YAFFS_OBJECT_TYPE_UNKNOWN) { |
| 12616 | - /* Set up as a directory */ |
| 12617 | - parent->variantType = |
| 12618 | - YAFFS_OBJECT_TYPE_DIRECTORY; |
| 12619 | - YINIT_LIST_HEAD(&parent->variant. |
| 12620 | - directoryVariant. |
| 12621 | - children); |
| 12622 | - } else if (!parent || parent->variantType != |
| 12623 | - YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 12624 | - /* Hoosterman, another problem.... |
| 12625 | - * We're trying to use a non-directory as a directory |
| 12626 | - */ |
| 12627 | + } |
| 12628 | |
| 12629 | - T(YAFFS_TRACE_ERROR, |
| 12630 | - (TSTR |
| 12631 | - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." |
| 12632 | - TENDSTR))); |
| 12633 | - parent = dev->lostNFoundDir; |
| 12634 | - } |
| 12635 | + } else { |
| 12636 | + /* A full chunk. Write directly from the supplied buffer. */ |
| 12637 | |
| 12638 | - yaffs_AddObjectToDirectory(parent, in); |
| 12639 | |
| 12640 | - if (0 && (parent == dev->deletedDir || |
| 12641 | - parent == dev->unlinkedDir)) { |
| 12642 | - in->deleted = 1; /* If it is unlinked at start up then it wants deleting */ |
| 12643 | - dev->nDeletedFiles++; |
| 12644 | - } |
| 12645 | - /* Note re hardlinks. |
| 12646 | - * Since we might scan a hardlink before its equivalent object is scanned |
| 12647 | - * we put them all in a list. |
| 12648 | - * After scanning is complete, we should have all the objects, so we run through this |
| 12649 | - * list and fix up all the chains. |
| 12650 | - */ |
| 12651 | |
| 12652 | - switch (in->variantType) { |
| 12653 | - case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 12654 | - /* Todo got a problem */ |
| 12655 | - break; |
| 12656 | - case YAFFS_OBJECT_TYPE_FILE: |
| 12657 | - if (dev->useHeaderFileSize) |
| 12658 | - |
| 12659 | - in->variant.fileVariant. |
| 12660 | - fileSize = |
| 12661 | - oh->fileSize; |
| 12662 | - |
| 12663 | - break; |
| 12664 | - case YAFFS_OBJECT_TYPE_HARDLINK: |
| 12665 | - in->variant.hardLinkVariant. |
| 12666 | - equivalentObjectId = |
| 12667 | - oh->equivalentObjectId; |
| 12668 | - in->hardLinks.next = |
| 12669 | - (struct ylist_head *) |
| 12670 | - hardList; |
| 12671 | - hardList = in; |
| 12672 | - break; |
| 12673 | - case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 12674 | - /* Do nothing */ |
| 12675 | - break; |
| 12676 | - case YAFFS_OBJECT_TYPE_SPECIAL: |
| 12677 | - /* Do nothing */ |
| 12678 | - break; |
| 12679 | - case YAFFS_OBJECT_TYPE_SYMLINK: |
| 12680 | - in->variant.symLinkVariant.alias = |
| 12681 | - yaffs_CloneString(oh->alias); |
| 12682 | - if (!in->variant.symLinkVariant.alias) |
| 12683 | - alloc_failed = 1; |
| 12684 | - break; |
| 12685 | - } |
| 12686 | + chunkWritten = |
| 12687 | + yaffs_wr_data_obj(in, chunk, buffer, |
| 12688 | + dev->data_bytes_per_chunk, |
| 12689 | + 0); |
| 12690 | |
| 12691 | -/* |
| 12692 | - if (parent == dev->deletedDir) { |
| 12693 | - yaffs_DestroyObject(in); |
| 12694 | - bi->hasShrinkHeader = 1; |
| 12695 | - } |
| 12696 | -*/ |
| 12697 | - } |
| 12698 | - } |
| 12699 | + /* Since we've overwritten the cached data, we better invalidate it. */ |
| 12700 | + yaffs_invalidate_chunk_cache(in, chunk); |
| 12701 | } |
| 12702 | |
| 12703 | - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { |
| 12704 | - /* If we got this far while scanning, then the block is fully allocated.*/ |
| 12705 | - state = YAFFS_BLOCK_STATE_FULL; |
| 12706 | + if (chunkWritten >= 0) { |
| 12707 | + n -= nToCopy; |
| 12708 | + offset += nToCopy; |
| 12709 | + buffer += nToCopy; |
| 12710 | + nDone += nToCopy; |
| 12711 | } |
| 12712 | |
| 12713 | - bi->blockState = state; |
| 12714 | + } |
| 12715 | |
| 12716 | - /* Now let's see if it was dirty */ |
| 12717 | - if (bi->pagesInUse == 0 && |
| 12718 | - !bi->hasShrinkHeader && |
| 12719 | - bi->blockState == YAFFS_BLOCK_STATE_FULL) { |
| 12720 | - yaffs_BlockBecameDirty(dev, blk); |
| 12721 | - } |
| 12722 | + /* Update file object */ |
| 12723 | |
| 12724 | - } |
| 12725 | + if ((startOfWrite + nDone) > in->variant.file_variant.file_size) |
| 12726 | + in->variant.file_variant.file_size = (startOfWrite + nDone); |
| 12727 | |
| 12728 | + in->dirty = 1; |
| 12729 | |
| 12730 | - /* Ok, we've done all the scanning. |
| 12731 | - * Fix up the hard link chains. |
| 12732 | - * We should now have scanned all the objects, now it's time to add these |
| 12733 | - * hardlinks. |
| 12734 | - */ |
| 12735 | + return nDone; |
| 12736 | +} |
| 12737 | |
| 12738 | - yaffs_HardlinkFixup(dev, hardList); |
| 12739 | +int yaffs_wr_file(yaffs_obj_t *in, const __u8 *buffer, loff_t offset, |
| 12740 | + int n_bytes, int write_trhrough) |
| 12741 | +{ |
| 12742 | + yaffs2_handle_hole(in,offset); |
| 12743 | + return yaffs_do_file_wr(in,buffer,offset,n_bytes,write_trhrough); |
| 12744 | +} |
| 12745 | |
| 12746 | - /* Fix up any shadowed objects */ |
| 12747 | - { |
| 12748 | - struct yaffs_ShadowFixerStruct *fixer; |
| 12749 | - yaffs_Object *obj; |
| 12750 | - |
| 12751 | - while (shadowFixerList) { |
| 12752 | - fixer = shadowFixerList; |
| 12753 | - shadowFixerList = fixer->next; |
| 12754 | - /* Complete the rename transaction by deleting the shadowed object |
| 12755 | - * then setting the object header to unshadowed. |
| 12756 | - */ |
| 12757 | - obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId); |
| 12758 | - if (obj) |
| 12759 | - yaffs_DeleteObject(obj); |
| 12760 | |
| 12761 | - obj = yaffs_FindObjectByNumber(dev, fixer->objectId); |
| 12762 | |
| 12763 | - if (obj) |
| 12764 | - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); |
| 12765 | +/* ---------------------- File resizing stuff ------------------ */ |
| 12766 | |
| 12767 | - YFREE(fixer); |
| 12768 | - } |
| 12769 | - } |
| 12770 | +static void yaffs_prune_chunks(yaffs_obj_t *in, int new_size) |
| 12771 | +{ |
| 12772 | |
| 12773 | - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); |
| 12774 | + yaffs_dev_t *dev = in->my_dev; |
| 12775 | + int oldFileSize = in->variant.file_variant.file_size; |
| 12776 | |
| 12777 | - if (alloc_failed) |
| 12778 | - return YAFFS_FAIL; |
| 12779 | + int lastDel = 1 + (oldFileSize - 1) / dev->data_bytes_per_chunk; |
| 12780 | + |
| 12781 | + int startDel = 1 + (new_size + dev->data_bytes_per_chunk - 1) / |
| 12782 | + dev->data_bytes_per_chunk; |
| 12783 | + int i; |
| 12784 | + int chunk_id; |
| 12785 | |
| 12786 | - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR))); |
| 12787 | + /* Delete backwards so that we don't end up with holes if |
| 12788 | + * power is lost part-way through the operation. |
| 12789 | + */ |
| 12790 | + for (i = lastDel; i >= startDel; i--) { |
| 12791 | + /* NB this could be optimised somewhat, |
| 12792 | + * eg. could retrieve the tags and write them without |
| 12793 | + * using yaffs_chunk_del |
| 12794 | + */ |
| 12795 | |
| 12796 | + chunk_id = yaffs_find_del_file_chunk(in, i, NULL); |
| 12797 | + if (chunk_id > 0) { |
| 12798 | + if (chunk_id < |
| 12799 | + (dev->internal_start_block * dev->param.chunks_per_block) |
| 12800 | + || chunk_id >= |
| 12801 | + ((dev->internal_end_block + |
| 12802 | + 1) * dev->param.chunks_per_block)) { |
| 12803 | + T(YAFFS_TRACE_ALWAYS, |
| 12804 | + (TSTR("Found daft chunk_id %d for %d" TENDSTR), |
| 12805 | + chunk_id, i)); |
| 12806 | + } else { |
| 12807 | + in->n_data_chunks--; |
| 12808 | + yaffs_chunk_del(dev, chunk_id, 1, __LINE__); |
| 12809 | + } |
| 12810 | + } |
| 12811 | + } |
| 12812 | |
| 12813 | - return YAFFS_OK; |
| 12814 | } |
| 12815 | |
| 12816 | -static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) |
| 12817 | -{ |
| 12818 | - __u8 *chunkData; |
| 12819 | - yaffs_ObjectHeader *oh; |
| 12820 | - yaffs_Device *dev; |
| 12821 | - yaffs_ExtendedTags tags; |
| 12822 | - int result; |
| 12823 | - int alloc_failed = 0; |
| 12824 | |
| 12825 | - if (!in) |
| 12826 | - return; |
| 12827 | +void yaffs_resize_file_down( yaffs_obj_t *obj, loff_t new_size) |
| 12828 | +{ |
| 12829 | + int newFullChunks; |
| 12830 | + __u32 new_sizeOfPartialChunk; |
| 12831 | + yaffs_dev_t *dev = obj->my_dev; |
| 12832 | |
| 12833 | - dev = in->myDev; |
| 12834 | + yaffs_addr_to_chunk(dev, new_size, &newFullChunks, &new_sizeOfPartialChunk); |
| 12835 | |
| 12836 | -#if 0 |
| 12837 | - T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR), |
| 12838 | - in->objectId, |
| 12839 | - in->lazyLoaded ? "not yet" : "already")); |
| 12840 | -#endif |
| 12841 | + yaffs_prune_chunks(obj, new_size); |
| 12842 | |
| 12843 | - if (in->lazyLoaded && in->hdrChunk > 0) { |
| 12844 | - in->lazyLoaded = 0; |
| 12845 | - chunkData = yaffs_GetTempBuffer(dev, __LINE__); |
| 12846 | + if (new_sizeOfPartialChunk != 0) { |
| 12847 | + int lastChunk = 1 + newFullChunks; |
| 12848 | + __u8 *localBuffer = yaffs_get_temp_buffer(dev, __LINE__); |
| 12849 | |
| 12850 | - result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags); |
| 12851 | - oh = (yaffs_ObjectHeader *) chunkData; |
| 12852 | + /* Got to read and rewrite the last chunk with its new size and zero pad */ |
| 12853 | + yaffs_rd_data_obj(obj, lastChunk, localBuffer); |
| 12854 | + memset(localBuffer + new_sizeOfPartialChunk, 0, |
| 12855 | + dev->data_bytes_per_chunk - new_sizeOfPartialChunk); |
| 12856 | |
| 12857 | - in->yst_mode = oh->yst_mode; |
| 12858 | -#ifdef CONFIG_YAFFS_WINCE |
| 12859 | - in->win_atime[0] = oh->win_atime[0]; |
| 12860 | - in->win_ctime[0] = oh->win_ctime[0]; |
| 12861 | - in->win_mtime[0] = oh->win_mtime[0]; |
| 12862 | - in->win_atime[1] = oh->win_atime[1]; |
| 12863 | - in->win_ctime[1] = oh->win_ctime[1]; |
| 12864 | - in->win_mtime[1] = oh->win_mtime[1]; |
| 12865 | -#else |
| 12866 | - in->yst_uid = oh->yst_uid; |
| 12867 | - in->yst_gid = oh->yst_gid; |
| 12868 | - in->yst_atime = oh->yst_atime; |
| 12869 | - in->yst_mtime = oh->yst_mtime; |
| 12870 | - in->yst_ctime = oh->yst_ctime; |
| 12871 | - in->yst_rdev = oh->yst_rdev; |
| 12872 | + yaffs_wr_data_obj(obj, lastChunk, localBuffer, |
| 12873 | + new_sizeOfPartialChunk, 1); |
| 12874 | |
| 12875 | -#endif |
| 12876 | - yaffs_SetObjectName(in, oh->name); |
| 12877 | + yaffs_release_temp_buffer(dev, localBuffer, __LINE__); |
| 12878 | + } |
| 12879 | |
| 12880 | - if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { |
| 12881 | - in->variant.symLinkVariant.alias = |
| 12882 | - yaffs_CloneString(oh->alias); |
| 12883 | - if (!in->variant.symLinkVariant.alias) |
| 12884 | - alloc_failed = 1; /* Not returned to caller */ |
| 12885 | - } |
| 12886 | + obj->variant.file_variant.file_size = new_size; |
| 12887 | |
| 12888 | - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); |
| 12889 | - } |
| 12890 | + yaffs_prune_tree(dev, &obj->variant.file_variant); |
| 12891 | } |
| 12892 | |
| 12893 | -static int yaffs_ScanBackwards(yaffs_Device *dev) |
| 12894 | -{ |
| 12895 | - yaffs_ExtendedTags tags; |
| 12896 | - int blk; |
| 12897 | - int blockIterator; |
| 12898 | - int startIterator; |
| 12899 | - int endIterator; |
| 12900 | - int nBlocksToScan = 0; |
| 12901 | - |
| 12902 | - int chunk; |
| 12903 | - int result; |
| 12904 | - int c; |
| 12905 | - int deleted; |
| 12906 | - yaffs_BlockState state; |
| 12907 | - yaffs_Object *hardList = NULL; |
| 12908 | - yaffs_BlockInfo *bi; |
| 12909 | - __u32 sequenceNumber; |
| 12910 | - yaffs_ObjectHeader *oh; |
| 12911 | - yaffs_Object *in; |
| 12912 | - yaffs_Object *parent; |
| 12913 | - int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; |
| 12914 | - int itsUnlinked; |
| 12915 | - __u8 *chunkData; |
| 12916 | |
| 12917 | - int fileSize; |
| 12918 | - int isShrink; |
| 12919 | - int foundChunksInBlock; |
| 12920 | - int equivalentObjectId; |
| 12921 | - int alloc_failed = 0; |
| 12922 | +int yaffs_resize_file(yaffs_obj_t *in, loff_t new_size) |
| 12923 | +{ |
| 12924 | + yaffs_dev_t *dev = in->my_dev; |
| 12925 | + int oldFileSize = in->variant.file_variant.file_size; |
| 12926 | |
| 12927 | + yaffs_flush_file_cache(in); |
| 12928 | + yaffs_invalidate_whole_cache(in); |
| 12929 | |
| 12930 | - yaffs_BlockIndex *blockIndex = NULL; |
| 12931 | - int altBlockIndex = 0; |
| 12932 | + yaffs_check_gc(dev,0); |
| 12933 | |
| 12934 | - if (!dev->isYaffs2) { |
| 12935 | - T(YAFFS_TRACE_SCAN, |
| 12936 | - (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR))); |
| 12937 | + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) |
| 12938 | return YAFFS_FAIL; |
| 12939 | - } |
| 12940 | |
| 12941 | - T(YAFFS_TRACE_SCAN, |
| 12942 | - (TSTR |
| 12943 | - ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..." |
| 12944 | - TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); |
| 12945 | + if (new_size == oldFileSize) |
| 12946 | + return YAFFS_OK; |
| 12947 | + |
| 12948 | + if(new_size > oldFileSize){ |
| 12949 | + yaffs2_handle_hole(in,new_size); |
| 12950 | + in->variant.file_variant.file_size = new_size; |
| 12951 | + } else { |
| 12952 | + /* new_size < oldFileSize */ |
| 12953 | + yaffs_resize_file_down(in, new_size); |
| 12954 | + } |
| 12955 | |
| 12956 | + /* Write a new object header to reflect the resize. |
| 12957 | + * show we've shrunk the file, if need be |
| 12958 | + * Do this only if the file is not in the deleted directories |
| 12959 | + * and is not shadowed. |
| 12960 | + */ |
| 12961 | + if (in->parent && |
| 12962 | + !in->is_shadowed && |
| 12963 | + in->parent->obj_id != YAFFS_OBJECTID_UNLINKED && |
| 12964 | + in->parent->obj_id != YAFFS_OBJECTID_DELETED) |
| 12965 | + yaffs_update_oh(in, NULL, 0, 0, 0, NULL); |
| 12966 | |
| 12967 | - dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; |
| 12968 | |
| 12969 | - blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); |
| 12970 | + return YAFFS_OK; |
| 12971 | +} |
| 12972 | |
| 12973 | - if (!blockIndex) { |
| 12974 | - blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex)); |
| 12975 | - altBlockIndex = 1; |
| 12976 | - } |
| 12977 | +loff_t yaffs_get_file_size(yaffs_obj_t *obj) |
| 12978 | +{ |
| 12979 | + YCHAR *alias = NULL; |
| 12980 | + obj = yaffs_get_equivalent_obj(obj); |
| 12981 | |
| 12982 | - if (!blockIndex) { |
| 12983 | - T(YAFFS_TRACE_SCAN, |
| 12984 | - (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR))); |
| 12985 | - return YAFFS_FAIL; |
| 12986 | + switch (obj->variant_type) { |
| 12987 | + case YAFFS_OBJECT_TYPE_FILE: |
| 12988 | + return obj->variant.file_variant.file_size; |
| 12989 | + case YAFFS_OBJECT_TYPE_SYMLINK: |
| 12990 | + alias = obj->variant.symlink_variant.alias; |
| 12991 | + if(!alias) |
| 12992 | + return 0; |
| 12993 | + return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH); |
| 12994 | + default: |
| 12995 | + return 0; |
| 12996 | } |
| 12997 | +} |
| 12998 | |
| 12999 | - dev->blocksInCheckpoint = 0; |
| 13000 | - |
| 13001 | - chunkData = yaffs_GetTempBuffer(dev, __LINE__); |
| 13002 | - |
| 13003 | - /* Scan all the blocks to determine their state */ |
| 13004 | - for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { |
| 13005 | - bi = yaffs_GetBlockInfo(dev, blk); |
| 13006 | - yaffs_ClearChunkBits(dev, blk); |
| 13007 | - bi->pagesInUse = 0; |
| 13008 | - bi->softDeletions = 0; |
| 13009 | - |
| 13010 | - yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); |
| 13011 | |
| 13012 | - bi->blockState = state; |
| 13013 | - bi->sequenceNumber = sequenceNumber; |
| 13014 | |
| 13015 | - if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) |
| 13016 | - bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT; |
| 13017 | - if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK) |
| 13018 | - bi->blockState = state = YAFFS_BLOCK_STATE_DEAD; |
| 13019 | +int yaffs_flush_file(yaffs_obj_t *in, int update_time, int data_sync) |
| 13020 | +{ |
| 13021 | + int retVal; |
| 13022 | + if (in->dirty) { |
| 13023 | + yaffs_flush_file_cache(in); |
| 13024 | + if(data_sync) /* Only sync data */ |
| 13025 | + retVal=YAFFS_OK; |
| 13026 | + else { |
| 13027 | + if (update_time) { |
| 13028 | +#ifdef CONFIG_YAFFS_WINCE |
| 13029 | + yfsd_win_file_time_now(in->win_mtime); |
| 13030 | +#else |
| 13031 | |
| 13032 | - T(YAFFS_TRACE_SCAN_DEBUG, |
| 13033 | - (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, |
| 13034 | - state, sequenceNumber)); |
| 13035 | + in->yst_mtime = Y_CURRENT_TIME; |
| 13036 | |
| 13037 | +#endif |
| 13038 | + } |
| 13039 | |
| 13040 | - if (state == YAFFS_BLOCK_STATE_CHECKPOINT) { |
| 13041 | - dev->blocksInCheckpoint++; |
| 13042 | + retVal = (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= |
| 13043 | + 0) ? YAFFS_OK : YAFFS_FAIL; |
| 13044 | + } |
| 13045 | + } else { |
| 13046 | + retVal = YAFFS_OK; |
| 13047 | + } |
| 13048 | |
| 13049 | - } else if (state == YAFFS_BLOCK_STATE_DEAD) { |
| 13050 | - T(YAFFS_TRACE_BAD_BLOCKS, |
| 13051 | - (TSTR("block %d is bad" TENDSTR), blk)); |
| 13052 | - } else if (state == YAFFS_BLOCK_STATE_EMPTY) { |
| 13053 | - T(YAFFS_TRACE_SCAN_DEBUG, |
| 13054 | - (TSTR("Block empty " TENDSTR))); |
| 13055 | - dev->nErasedBlocks++; |
| 13056 | - dev->nFreeChunks += dev->nChunksPerBlock; |
| 13057 | - } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { |
| 13058 | + return retVal; |
| 13059 | |
| 13060 | - /* Determine the highest sequence number */ |
| 13061 | - if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && |
| 13062 | - sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { |
| 13063 | +} |
| 13064 | |
| 13065 | - blockIndex[nBlocksToScan].seq = sequenceNumber; |
| 13066 | - blockIndex[nBlocksToScan].block = blk; |
| 13067 | +static int yaffs_generic_obj_del(yaffs_obj_t *in) |
| 13068 | +{ |
| 13069 | |
| 13070 | - nBlocksToScan++; |
| 13071 | + /* First off, invalidate the file's data in the cache, without flushing. */ |
| 13072 | + yaffs_invalidate_whole_cache(in); |
| 13073 | |
| 13074 | - if (sequenceNumber >= dev->sequenceNumber) |
| 13075 | - dev->sequenceNumber = sequenceNumber; |
| 13076 | - } else { |
| 13077 | - /* TODO: Nasty sequence number! */ |
| 13078 | - T(YAFFS_TRACE_SCAN, |
| 13079 | - (TSTR |
| 13080 | - ("Block scanning block %d has bad sequence number %d" |
| 13081 | - TENDSTR), blk, sequenceNumber)); |
| 13082 | + if (in->my_dev->param.is_yaffs2 && (in->parent != in->my_dev->del_dir)) { |
| 13083 | + /* Move to the unlinked directory so we have a record that it was deleted. */ |
| 13084 | + yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0, 0); |
| 13085 | |
| 13086 | - } |
| 13087 | - } |
| 13088 | } |
| 13089 | |
| 13090 | - T(YAFFS_TRACE_SCAN, |
| 13091 | - (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan)); |
| 13092 | + yaffs_remove_obj_from_dir(in); |
| 13093 | + yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__); |
| 13094 | + in->hdr_chunk = 0; |
| 13095 | |
| 13096 | + yaffs_free_obj(in); |
| 13097 | + return YAFFS_OK; |
| 13098 | |
| 13099 | +} |
| 13100 | |
| 13101 | - YYIELD(); |
| 13102 | +/* yaffs_del_file deletes the whole file data |
| 13103 | + * and the inode associated with the file. |
| 13104 | + * It does not delete the links associated with the file. |
| 13105 | + */ |
| 13106 | +static int yaffs_unlink_file_if_needed(yaffs_obj_t *in) |
| 13107 | +{ |
| 13108 | |
| 13109 | - /* Sort the blocks */ |
| 13110 | -#ifndef CONFIG_YAFFS_USE_OWN_SORT |
| 13111 | - { |
| 13112 | - /* Use qsort now. */ |
| 13113 | - yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); |
| 13114 | - } |
| 13115 | -#else |
| 13116 | - { |
| 13117 | - /* Dungy old bubble sort... */ |
| 13118 | + int retVal; |
| 13119 | + int immediateDeletion = 0; |
| 13120 | + yaffs_dev_t *dev = in->my_dev; |
| 13121 | |
| 13122 | - yaffs_BlockIndex temp; |
| 13123 | - int i; |
| 13124 | - int j; |
| 13125 | + if (!in->my_inode) |
| 13126 | + immediateDeletion = 1; |
| 13127 | |
| 13128 | - for (i = 0; i < nBlocksToScan; i++) |
| 13129 | - for (j = i + 1; j < nBlocksToScan; j++) |
| 13130 | - if (blockIndex[i].seq > blockIndex[j].seq) { |
| 13131 | - temp = blockIndex[j]; |
| 13132 | - blockIndex[j] = blockIndex[i]; |
| 13133 | - blockIndex[i] = temp; |
| 13134 | - } |
| 13135 | + if (immediateDeletion) { |
| 13136 | + retVal = |
| 13137 | + yaffs_change_obj_name(in, in->my_dev->del_dir, |
| 13138 | + _Y("deleted"), 0, 0); |
| 13139 | + T(YAFFS_TRACE_TRACING, |
| 13140 | + (TSTR("yaffs: immediate deletion of file %d" TENDSTR), |
| 13141 | + in->obj_id)); |
| 13142 | + in->deleted = 1; |
| 13143 | + in->my_dev->n_deleted_files++; |
| 13144 | + if (dev->param.disable_soft_del || dev->param.is_yaffs2) |
| 13145 | + yaffs_resize_file(in, 0); |
| 13146 | + yaffs_soft_del_file(in); |
| 13147 | + } else { |
| 13148 | + retVal = |
| 13149 | + yaffs_change_obj_name(in, in->my_dev->unlinked_dir, |
| 13150 | + _Y("unlinked"), 0, 0); |
| 13151 | } |
| 13152 | -#endif |
| 13153 | |
| 13154 | - YYIELD(); |
| 13155 | |
| 13156 | - T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR))); |
| 13157 | + return retVal; |
| 13158 | +} |
| 13159 | |
| 13160 | - /* Now scan the blocks looking at the data. */ |
| 13161 | - startIterator = 0; |
| 13162 | - endIterator = nBlocksToScan - 1; |
| 13163 | - T(YAFFS_TRACE_SCAN_DEBUG, |
| 13164 | - (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); |
| 13165 | +int yaffs_del_file(yaffs_obj_t *in) |
| 13166 | +{ |
| 13167 | + int retVal = YAFFS_OK; |
| 13168 | + int deleted; /* Need to cache value on stack if in is freed */ |
| 13169 | + yaffs_dev_t *dev = in->my_dev; |
| 13170 | |
| 13171 | - /* For each block.... backwards */ |
| 13172 | - for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; |
| 13173 | - blockIterator--) { |
| 13174 | - /* Cooperative multitasking! This loop can run for so |
| 13175 | - long that watchdog timers expire. */ |
| 13176 | - YYIELD(); |
| 13177 | + if (dev->param.disable_soft_del || dev->param.is_yaffs2) |
| 13178 | + yaffs_resize_file(in, 0); |
| 13179 | |
| 13180 | - /* get the block to scan in the correct order */ |
| 13181 | - blk = blockIndex[blockIterator].block; |
| 13182 | + if (in->n_data_chunks > 0) { |
| 13183 | + /* Use soft deletion if there is data in the file. |
| 13184 | + * That won't be the case if it has been resized to zero. |
| 13185 | + */ |
| 13186 | + if (!in->unlinked) |
| 13187 | + retVal = yaffs_unlink_file_if_needed(in); |
| 13188 | |
| 13189 | - bi = yaffs_GetBlockInfo(dev, blk); |
| 13190 | + deleted = in->deleted; |
| 13191 | |
| 13192 | + if (retVal == YAFFS_OK && in->unlinked && !in->deleted) { |
| 13193 | + in->deleted = 1; |
| 13194 | + deleted = 1; |
| 13195 | + in->my_dev->n_deleted_files++; |
| 13196 | + yaffs_soft_del_file(in); |
| 13197 | + } |
| 13198 | + return deleted ? YAFFS_OK : YAFFS_FAIL; |
| 13199 | + } else { |
| 13200 | + /* The file has no data chunks so we toss it immediately */ |
| 13201 | + yaffs_free_tnode(in->my_dev, in->variant.file_variant.top); |
| 13202 | + in->variant.file_variant.top = NULL; |
| 13203 | + yaffs_generic_obj_del(in); |
| 13204 | |
| 13205 | - state = bi->blockState; |
| 13206 | + return YAFFS_OK; |
| 13207 | + } |
| 13208 | +} |
| 13209 | |
| 13210 | - deleted = 0; |
| 13211 | +static int yaffs_is_non_empty_dir(yaffs_obj_t *obj) |
| 13212 | +{ |
| 13213 | + return (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) && |
| 13214 | + !(ylist_empty(&obj->variant.dir_variant.children)); |
| 13215 | +} |
| 13216 | |
| 13217 | - /* For each chunk in each block that needs scanning.... */ |
| 13218 | - foundChunksInBlock = 0; |
| 13219 | - for (c = dev->nChunksPerBlock - 1; |
| 13220 | - !alloc_failed && c >= 0 && |
| 13221 | - (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || |
| 13222 | - state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { |
| 13223 | - /* Scan backwards... |
| 13224 | - * Read the tags and decide what to do |
| 13225 | - */ |
| 13226 | +static int yaffs_del_dir(yaffs_obj_t *obj) |
| 13227 | +{ |
| 13228 | + /* First check that the directory is empty. */ |
| 13229 | + if (yaffs_is_non_empty_dir(obj)) |
| 13230 | + return YAFFS_FAIL; |
| 13231 | |
| 13232 | - chunk = blk * dev->nChunksPerBlock + c; |
| 13233 | + return yaffs_generic_obj_del(obj); |
| 13234 | +} |
| 13235 | |
| 13236 | - result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, |
| 13237 | - &tags); |
| 13238 | +static int yaffs_del_symlink(yaffs_obj_t *in) |
| 13239 | +{ |
| 13240 | + if(in->variant.symlink_variant.alias) |
| 13241 | + YFREE(in->variant.symlink_variant.alias); |
| 13242 | + in->variant.symlink_variant.alias=NULL; |
| 13243 | |
| 13244 | - /* Let's have a good look at this chunk... */ |
| 13245 | + return yaffs_generic_obj_del(in); |
| 13246 | +} |
| 13247 | |
| 13248 | - if (!tags.chunkUsed) { |
| 13249 | - /* An unassigned chunk in the block. |
| 13250 | - * If there are used chunks after this one, then |
| 13251 | - * it is a chunk that was skipped due to failing the erased |
| 13252 | - * check. Just skip it so that it can be deleted. |
| 13253 | - * But, more typically, We get here when this is an unallocated |
| 13254 | - * chunk and his means that either the block is empty or |
| 13255 | - * this is the one being allocated from |
| 13256 | - */ |
| 13257 | +static int yaffs_del_link(yaffs_obj_t *in) |
| 13258 | +{ |
| 13259 | + /* remove this hardlink from the list assocaited with the equivalent |
| 13260 | + * object |
| 13261 | + */ |
| 13262 | + ylist_del_init(&in->hard_links); |
| 13263 | + return yaffs_generic_obj_del(in); |
| 13264 | +} |
| 13265 | |
| 13266 | - if (foundChunksInBlock) { |
| 13267 | - /* This is a chunk that was skipped due to failing the erased check */ |
| 13268 | - } else if (c == 0) { |
| 13269 | - /* We're looking at the first chunk in the block so the block is unused */ |
| 13270 | - state = YAFFS_BLOCK_STATE_EMPTY; |
| 13271 | - dev->nErasedBlocks++; |
| 13272 | - } else { |
| 13273 | - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || |
| 13274 | - state == YAFFS_BLOCK_STATE_ALLOCATING) { |
| 13275 | - if (dev->sequenceNumber == bi->sequenceNumber) { |
| 13276 | - /* this is the block being allocated from */ |
| 13277 | - |
| 13278 | - T(YAFFS_TRACE_SCAN, |
| 13279 | - (TSTR |
| 13280 | - (" Allocating from %d %d" |
| 13281 | - TENDSTR), blk, c)); |
| 13282 | - |
| 13283 | - state = YAFFS_BLOCK_STATE_ALLOCATING; |
| 13284 | - dev->allocationBlock = blk; |
| 13285 | - dev->allocationPage = c; |
| 13286 | - dev->allocationBlockFinder = blk; |
| 13287 | - } else { |
| 13288 | - /* This is a partially written block that is not |
| 13289 | - * the current allocation block. This block must have |
| 13290 | - * had a write failure, so set up for retirement. |
| 13291 | - */ |
| 13292 | - |
| 13293 | - /* bi->needsRetiring = 1; ??? TODO */ |
| 13294 | - bi->gcPrioritise = 1; |
| 13295 | - |
| 13296 | - T(YAFFS_TRACE_ALWAYS, |
| 13297 | - (TSTR("Partially written block %d detected" TENDSTR), |
| 13298 | - blk)); |
| 13299 | - } |
| 13300 | - } |
| 13301 | - } |
| 13302 | +int yaffs_del_obj(yaffs_obj_t *obj) |
| 13303 | +{ |
| 13304 | +int retVal = -1; |
| 13305 | + switch (obj->variant_type) { |
| 13306 | + case YAFFS_OBJECT_TYPE_FILE: |
| 13307 | + retVal = yaffs_del_file(obj); |
| 13308 | + break; |
| 13309 | + case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 13310 | + if(!ylist_empty(&obj->variant.dir_variant.dirty)){ |
| 13311 | + T(YAFFS_TRACE_BACKGROUND, (TSTR("Remove object %d from dirty directories" TENDSTR),obj->obj_id)); |
| 13312 | + ylist_del_init(&obj->variant.dir_variant.dirty); |
| 13313 | + } |
| 13314 | + return yaffs_del_dir(obj); |
| 13315 | + break; |
| 13316 | + case YAFFS_OBJECT_TYPE_SYMLINK: |
| 13317 | + retVal = yaffs_del_symlink(obj); |
| 13318 | + break; |
| 13319 | + case YAFFS_OBJECT_TYPE_HARDLINK: |
| 13320 | + retVal = yaffs_del_link(obj); |
| 13321 | + break; |
| 13322 | + case YAFFS_OBJECT_TYPE_SPECIAL: |
| 13323 | + retVal = yaffs_generic_obj_del(obj); |
| 13324 | + break; |
| 13325 | + case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 13326 | + retVal = 0; |
| 13327 | + break; /* should not happen. */ |
| 13328 | + } |
| 13329 | |
| 13330 | - dev->nFreeChunks++; |
| 13331 | + return retVal; |
| 13332 | +} |
| 13333 | |
| 13334 | - } else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) { |
| 13335 | - T(YAFFS_TRACE_SCAN, |
| 13336 | - (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR), |
| 13337 | - blk, c)); |
| 13338 | - |
| 13339 | - dev->nFreeChunks++; |
| 13340 | - |
| 13341 | - } else if (tags.chunkId > 0) { |
| 13342 | - /* chunkId > 0 so it is a data chunk... */ |
| 13343 | - unsigned int endpos; |
| 13344 | - __u32 chunkBase = |
| 13345 | - (tags.chunkId - 1) * dev->nDataBytesPerChunk; |
| 13346 | - |
| 13347 | - foundChunksInBlock = 1; |
| 13348 | - |
| 13349 | - |
| 13350 | - yaffs_SetChunkBit(dev, blk, c); |
| 13351 | - bi->pagesInUse++; |
| 13352 | - |
| 13353 | - in = yaffs_FindOrCreateObjectByNumber(dev, |
| 13354 | - tags. |
| 13355 | - objectId, |
| 13356 | - YAFFS_OBJECT_TYPE_FILE); |
| 13357 | - if (!in) { |
| 13358 | - /* Out of memory */ |
| 13359 | - alloc_failed = 1; |
| 13360 | - } |
| 13361 | +static int yaffs_unlink_worker(yaffs_obj_t *obj) |
| 13362 | +{ |
| 13363 | |
| 13364 | - if (in && |
| 13365 | - in->variantType == YAFFS_OBJECT_TYPE_FILE |
| 13366 | - && chunkBase < |
| 13367 | - in->variant.fileVariant.shrinkSize) { |
| 13368 | - /* This has not been invalidated by a resize */ |
| 13369 | - if (!yaffs_PutChunkIntoFile(in, tags.chunkId, |
| 13370 | - chunk, -1)) { |
| 13371 | - alloc_failed = 1; |
| 13372 | - } |
| 13373 | + int immediateDeletion = 0; |
| 13374 | |
| 13375 | - /* File size is calculated by looking at the data chunks if we have not |
| 13376 | - * seen an object header yet. Stop this practice once we find an object header. |
| 13377 | - */ |
| 13378 | - endpos = |
| 13379 | - (tags.chunkId - |
| 13380 | - 1) * dev->nDataBytesPerChunk + |
| 13381 | - tags.byteCount; |
| 13382 | - |
| 13383 | - if (!in->valid && /* have not got an object header yet */ |
| 13384 | - in->variant.fileVariant. |
| 13385 | - scannedFileSize < endpos) { |
| 13386 | - in->variant.fileVariant. |
| 13387 | - scannedFileSize = endpos; |
| 13388 | - in->variant.fileVariant. |
| 13389 | - fileSize = |
| 13390 | - in->variant.fileVariant. |
| 13391 | - scannedFileSize; |
| 13392 | - } |
| 13393 | + if (!obj->my_inode) |
| 13394 | + immediateDeletion = 1; |
| 13395 | |
| 13396 | - } else if (in) { |
| 13397 | - /* This chunk has been invalidated by a resize, so delete */ |
| 13398 | - yaffs_DeleteChunk(dev, chunk, 1, __LINE__); |
| 13399 | + if(obj) |
| 13400 | + yaffs_update_parent(obj->parent); |
| 13401 | |
| 13402 | - } |
| 13403 | - } else { |
| 13404 | - /* chunkId == 0, so it is an ObjectHeader. |
| 13405 | - * Thus, we read in the object header and make the object |
| 13406 | - */ |
| 13407 | - foundChunksInBlock = 1; |
| 13408 | + if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { |
| 13409 | + return yaffs_del_link(obj); |
| 13410 | + } else if (!ylist_empty(&obj->hard_links)) { |
| 13411 | + /* Curve ball: We're unlinking an object that has a hardlink. |
| 13412 | + * |
| 13413 | + * This problem arises because we are not strictly following |
| 13414 | + * The Linux link/inode model. |
| 13415 | + * |
| 13416 | + * We can't really delete the object. |
| 13417 | + * Instead, we do the following: |
| 13418 | + * - Select a hardlink. |
| 13419 | + * - Unhook it from the hard links |
| 13420 | + * - Move it from its parent directory (so that the rename can work) |
| 13421 | + * - Rename the object to the hardlink's name. |
| 13422 | + * - Delete the hardlink |
| 13423 | + */ |
| 13424 | |
| 13425 | - yaffs_SetChunkBit(dev, blk, c); |
| 13426 | - bi->pagesInUse++; |
| 13427 | + yaffs_obj_t *hl; |
| 13428 | + yaffs_obj_t *parent; |
| 13429 | + int retVal; |
| 13430 | + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; |
| 13431 | |
| 13432 | - oh = NULL; |
| 13433 | - in = NULL; |
| 13434 | + hl = ylist_entry(obj->hard_links.next, yaffs_obj_t, hard_links); |
| 13435 | |
| 13436 | - if (tags.extraHeaderInfoAvailable) { |
| 13437 | - in = yaffs_FindOrCreateObjectByNumber |
| 13438 | - (dev, tags.objectId, |
| 13439 | - tags.extraObjectType); |
| 13440 | - if (!in) |
| 13441 | - alloc_failed = 1; |
| 13442 | - } |
| 13443 | + yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1); |
| 13444 | + parent = hl->parent; |
| 13445 | |
| 13446 | - if (!in || |
| 13447 | -#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD |
| 13448 | - !in->valid || |
| 13449 | -#endif |
| 13450 | - tags.extraShadows || |
| 13451 | - (!in->valid && |
| 13452 | - (tags.objectId == YAFFS_OBJECTID_ROOT || |
| 13453 | - tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) { |
| 13454 | - |
| 13455 | - /* If we don't have valid info then we need to read the chunk |
| 13456 | - * TODO In future we can probably defer reading the chunk and |
| 13457 | - * living with invalid data until needed. |
| 13458 | - */ |
| 13459 | + ylist_del_init(&hl->hard_links); |
| 13460 | |
| 13461 | - result = yaffs_ReadChunkWithTagsFromNAND(dev, |
| 13462 | - chunk, |
| 13463 | - chunkData, |
| 13464 | - NULL); |
| 13465 | - |
| 13466 | - oh = (yaffs_ObjectHeader *) chunkData; |
| 13467 | - |
| 13468 | - if (dev->inbandTags) { |
| 13469 | - /* Fix up the header if they got corrupted by inband tags */ |
| 13470 | - oh->shadowsObject = oh->inbandShadowsObject; |
| 13471 | - oh->isShrink = oh->inbandIsShrink; |
| 13472 | - } |
| 13473 | + yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl); |
| 13474 | |
| 13475 | - if (!in) { |
| 13476 | - in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type); |
| 13477 | - if (!in) |
| 13478 | - alloc_failed = 1; |
| 13479 | - } |
| 13480 | + retVal = yaffs_change_obj_name(obj,parent, name, 0, 0); |
| 13481 | |
| 13482 | - } |
| 13483 | + if (retVal == YAFFS_OK) |
| 13484 | + retVal = yaffs_generic_obj_del(hl); |
| 13485 | |
| 13486 | - if (!in) { |
| 13487 | - /* TODO Hoosterman we have a problem! */ |
| 13488 | - T(YAFFS_TRACE_ERROR, |
| 13489 | - (TSTR |
| 13490 | - ("yaffs tragedy: Could not make object for object %d at chunk %d during scan" |
| 13491 | - TENDSTR), tags.objectId, chunk)); |
| 13492 | - continue; |
| 13493 | - } |
| 13494 | + return retVal; |
| 13495 | |
| 13496 | - if (in->valid) { |
| 13497 | - /* We have already filled this one. |
| 13498 | - * We have a duplicate that will be discarded, but |
| 13499 | - * we first have to suck out resize info if it is a file. |
| 13500 | - */ |
| 13501 | + } else if (immediateDeletion) { |
| 13502 | + switch (obj->variant_type) { |
| 13503 | + case YAFFS_OBJECT_TYPE_FILE: |
| 13504 | + return yaffs_del_file(obj); |
| 13505 | + break; |
| 13506 | + case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 13507 | + ylist_del_init(&obj->variant.dir_variant.dirty); |
| 13508 | + return yaffs_del_dir(obj); |
| 13509 | + break; |
| 13510 | + case YAFFS_OBJECT_TYPE_SYMLINK: |
| 13511 | + return yaffs_del_symlink(obj); |
| 13512 | + break; |
| 13513 | + case YAFFS_OBJECT_TYPE_SPECIAL: |
| 13514 | + return yaffs_generic_obj_del(obj); |
| 13515 | + break; |
| 13516 | + case YAFFS_OBJECT_TYPE_HARDLINK: |
| 13517 | + case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 13518 | + default: |
| 13519 | + return YAFFS_FAIL; |
| 13520 | + } |
| 13521 | + } else if(yaffs_is_non_empty_dir(obj)) |
| 13522 | + return YAFFS_FAIL; |
| 13523 | + else |
| 13524 | + return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir, |
| 13525 | + _Y("unlinked"), 0, 0); |
| 13526 | +} |
| 13527 | |
| 13528 | - if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && |
| 13529 | - ((oh && |
| 13530 | - oh->type == YAFFS_OBJECT_TYPE_FILE) || |
| 13531 | - (tags.extraHeaderInfoAvailable && |
| 13532 | - tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) { |
| 13533 | - __u32 thisSize = |
| 13534 | - (oh) ? oh->fileSize : tags. |
| 13535 | - extraFileLength; |
| 13536 | - __u32 parentObjectId = |
| 13537 | - (oh) ? oh-> |
| 13538 | - parentObjectId : tags. |
| 13539 | - extraParentObjectId; |
| 13540 | - |
| 13541 | - |
| 13542 | - isShrink = |
| 13543 | - (oh) ? oh->isShrink : tags. |
| 13544 | - extraIsShrinkHeader; |
| 13545 | |
| 13546 | - /* If it is deleted (unlinked at start also means deleted) |
| 13547 | - * we treat the file size as being zeroed at this point. |
| 13548 | - */ |
| 13549 | - if (parentObjectId == |
| 13550 | - YAFFS_OBJECTID_DELETED |
| 13551 | - || parentObjectId == |
| 13552 | - YAFFS_OBJECTID_UNLINKED) { |
| 13553 | - thisSize = 0; |
| 13554 | - isShrink = 1; |
| 13555 | - } |
| 13556 | +static int yaffs_unlink_obj(yaffs_obj_t *obj) |
| 13557 | +{ |
| 13558 | |
| 13559 | - if (isShrink && |
| 13560 | - in->variant.fileVariant. |
| 13561 | - shrinkSize > thisSize) { |
| 13562 | - in->variant.fileVariant. |
| 13563 | - shrinkSize = |
| 13564 | - thisSize; |
| 13565 | - } |
| 13566 | + if (obj && obj->unlink_allowed) |
| 13567 | + return yaffs_unlink_worker(obj); |
| 13568 | |
| 13569 | - if (isShrink) |
| 13570 | - bi->hasShrinkHeader = 1; |
| 13571 | + return YAFFS_FAIL; |
| 13572 | |
| 13573 | - } |
| 13574 | - /* Use existing - destroy this one. */ |
| 13575 | - yaffs_DeleteChunk(dev, chunk, 1, __LINE__); |
| 13576 | +} |
| 13577 | +int yaffs_unlinker(yaffs_obj_t *dir, const YCHAR *name) |
| 13578 | +{ |
| 13579 | + yaffs_obj_t *obj; |
| 13580 | |
| 13581 | - } |
| 13582 | + obj = yaffs_find_by_name(dir, name); |
| 13583 | + return yaffs_unlink_obj(obj); |
| 13584 | +} |
| 13585 | |
| 13586 | - if (!in->valid && in->variantType != |
| 13587 | - (oh ? oh->type : tags.extraObjectType)) |
| 13588 | - T(YAFFS_TRACE_ERROR, ( |
| 13589 | - TSTR("yaffs tragedy: Bad object type, " |
| 13590 | - TCONT("%d != %d, for object %d at chunk ") |
| 13591 | - TCONT("%d during scan") |
| 13592 | - TENDSTR), oh ? |
| 13593 | - oh->type : tags.extraObjectType, |
| 13594 | - in->variantType, tags.objectId, |
| 13595 | - chunk)); |
| 13596 | - |
| 13597 | - if (!in->valid && |
| 13598 | - (tags.objectId == YAFFS_OBJECTID_ROOT || |
| 13599 | - tags.objectId == |
| 13600 | - YAFFS_OBJECTID_LOSTNFOUND)) { |
| 13601 | - /* We only load some info, don't fiddle with directory structure */ |
| 13602 | - in->valid = 1; |
| 13603 | +/*----------------------- Initialisation Scanning ---------------------- */ |
| 13604 | |
| 13605 | - if (oh) { |
| 13606 | - in->variantType = oh->type; |
| 13607 | +void yaffs_handle_shadowed_obj(yaffs_dev_t *dev, int obj_id, |
| 13608 | + int backward_scanning) |
| 13609 | +{ |
| 13610 | + yaffs_obj_t *obj; |
| 13611 | |
| 13612 | - in->yst_mode = oh->yst_mode; |
| 13613 | -#ifdef CONFIG_YAFFS_WINCE |
| 13614 | - in->win_atime[0] = oh->win_atime[0]; |
| 13615 | - in->win_ctime[0] = oh->win_ctime[0]; |
| 13616 | - in->win_mtime[0] = oh->win_mtime[0]; |
| 13617 | - in->win_atime[1] = oh->win_atime[1]; |
| 13618 | - in->win_ctime[1] = oh->win_ctime[1]; |
| 13619 | - in->win_mtime[1] = oh->win_mtime[1]; |
| 13620 | -#else |
| 13621 | - in->yst_uid = oh->yst_uid; |
| 13622 | - in->yst_gid = oh->yst_gid; |
| 13623 | - in->yst_atime = oh->yst_atime; |
| 13624 | - in->yst_mtime = oh->yst_mtime; |
| 13625 | - in->yst_ctime = oh->yst_ctime; |
| 13626 | - in->yst_rdev = oh->yst_rdev; |
| 13627 | + if (!backward_scanning) { |
| 13628 | + /* Handle YAFFS1 forward scanning case |
| 13629 | + * For YAFFS1 we always do the deletion |
| 13630 | + */ |
| 13631 | |
| 13632 | -#endif |
| 13633 | - } else { |
| 13634 | - in->variantType = tags.extraObjectType; |
| 13635 | - in->lazyLoaded = 1; |
| 13636 | - } |
| 13637 | + } else { |
| 13638 | + /* Handle YAFFS2 case (backward scanning) |
| 13639 | + * If the shadowed object exists then ignore. |
| 13640 | + */ |
| 13641 | + obj = yaffs_find_by_number(dev, obj_id); |
| 13642 | + if(obj) |
| 13643 | + return; |
| 13644 | + } |
| 13645 | |
| 13646 | - in->hdrChunk = chunk; |
| 13647 | + /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc. |
| 13648 | + * We put it in unlinked dir to be cleaned up after the scanning |
| 13649 | + */ |
| 13650 | + obj = |
| 13651 | + yaffs_find_or_create_by_number(dev, obj_id, |
| 13652 | + YAFFS_OBJECT_TYPE_FILE); |
| 13653 | + if (!obj) |
| 13654 | + return; |
| 13655 | + obj->is_shadowed = 1; |
| 13656 | + yaffs_add_obj_to_dir(dev->unlinked_dir, obj); |
| 13657 | + obj->variant.file_variant.shrink_size = 0; |
| 13658 | + obj->valid = 1; /* So that we don't read any other info for this file */ |
| 13659 | |
| 13660 | - } else if (!in->valid) { |
| 13661 | - /* we need to load this info */ |
| 13662 | +} |
| 13663 | |
| 13664 | - in->valid = 1; |
| 13665 | - in->hdrChunk = chunk; |
| 13666 | |
| 13667 | - if (oh) { |
| 13668 | - in->variantType = oh->type; |
| 13669 | +void yaffs_link_fixup(yaffs_dev_t *dev, yaffs_obj_t *hard_list) |
| 13670 | +{ |
| 13671 | + yaffs_obj_t *hl; |
| 13672 | + yaffs_obj_t *in; |
| 13673 | |
| 13674 | - in->yst_mode = oh->yst_mode; |
| 13675 | -#ifdef CONFIG_YAFFS_WINCE |
| 13676 | - in->win_atime[0] = oh->win_atime[0]; |
| 13677 | - in->win_ctime[0] = oh->win_ctime[0]; |
| 13678 | - in->win_mtime[0] = oh->win_mtime[0]; |
| 13679 | - in->win_atime[1] = oh->win_atime[1]; |
| 13680 | - in->win_ctime[1] = oh->win_ctime[1]; |
| 13681 | - in->win_mtime[1] = oh->win_mtime[1]; |
| 13682 | -#else |
| 13683 | - in->yst_uid = oh->yst_uid; |
| 13684 | - in->yst_gid = oh->yst_gid; |
| 13685 | - in->yst_atime = oh->yst_atime; |
| 13686 | - in->yst_mtime = oh->yst_mtime; |
| 13687 | - in->yst_ctime = oh->yst_ctime; |
| 13688 | - in->yst_rdev = oh->yst_rdev; |
| 13689 | -#endif |
| 13690 | + while (hard_list) { |
| 13691 | + hl = hard_list; |
| 13692 | + hard_list = (yaffs_obj_t *) (hard_list->hard_links.next); |
| 13693 | + |
| 13694 | + in = yaffs_find_by_number(dev, |
| 13695 | + hl->variant.hardlink_variant. |
| 13696 | + equiv_id); |
| 13697 | |
| 13698 | - if (oh->shadowsObject > 0) |
| 13699 | - yaffs_HandleShadowedObject(dev, |
| 13700 | - oh-> |
| 13701 | - shadowsObject, |
| 13702 | - 1); |
| 13703 | - |
| 13704 | - |
| 13705 | - yaffs_SetObjectName(in, oh->name); |
| 13706 | - parent = |
| 13707 | - yaffs_FindOrCreateObjectByNumber |
| 13708 | - (dev, oh->parentObjectId, |
| 13709 | - YAFFS_OBJECT_TYPE_DIRECTORY); |
| 13710 | - |
| 13711 | - fileSize = oh->fileSize; |
| 13712 | - isShrink = oh->isShrink; |
| 13713 | - equivalentObjectId = oh->equivalentObjectId; |
| 13714 | + if (in) { |
| 13715 | + /* Add the hardlink pointers */ |
| 13716 | + hl->variant.hardlink_variant.equiv_obj = in; |
| 13717 | + ylist_add(&hl->hard_links, &in->hard_links); |
| 13718 | + } else { |
| 13719 | + /* Todo Need to report/handle this better. |
| 13720 | + * Got a problem... hardlink to a non-existant object |
| 13721 | + */ |
| 13722 | + hl->variant.hardlink_variant.equiv_obj = NULL; |
| 13723 | + YINIT_LIST_HEAD(&hl->hard_links); |
| 13724 | |
| 13725 | - } else { |
| 13726 | - in->variantType = tags.extraObjectType; |
| 13727 | - parent = |
| 13728 | - yaffs_FindOrCreateObjectByNumber |
| 13729 | - (dev, tags.extraParentObjectId, |
| 13730 | - YAFFS_OBJECT_TYPE_DIRECTORY); |
| 13731 | - fileSize = tags.extraFileLength; |
| 13732 | - isShrink = tags.extraIsShrinkHeader; |
| 13733 | - equivalentObjectId = tags.extraEquivalentObjectId; |
| 13734 | - in->lazyLoaded = 1; |
| 13735 | + } |
| 13736 | + } |
| 13737 | +} |
| 13738 | |
| 13739 | - } |
| 13740 | - in->dirty = 0; |
| 13741 | |
| 13742 | - if (!parent) |
| 13743 | - alloc_failed = 1; |
| 13744 | +static void yaffs_strip_deleted_objs(yaffs_dev_t *dev) |
| 13745 | +{ |
| 13746 | + /* |
| 13747 | + * Sort out state of unlinked and deleted objects after scanning. |
| 13748 | + */ |
| 13749 | + struct ylist_head *i; |
| 13750 | + struct ylist_head *n; |
| 13751 | + yaffs_obj_t *l; |
| 13752 | |
| 13753 | - /* directory stuff... |
| 13754 | - * hook up to parent |
| 13755 | - */ |
| 13756 | + if (dev->read_only) |
| 13757 | + return; |
| 13758 | |
| 13759 | - if (parent && parent->variantType == |
| 13760 | - YAFFS_OBJECT_TYPE_UNKNOWN) { |
| 13761 | - /* Set up as a directory */ |
| 13762 | - parent->variantType = |
| 13763 | - YAFFS_OBJECT_TYPE_DIRECTORY; |
| 13764 | - YINIT_LIST_HEAD(&parent->variant. |
| 13765 | - directoryVariant. |
| 13766 | - children); |
| 13767 | - } else if (!parent || parent->variantType != |
| 13768 | - YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 13769 | - /* Hoosterman, another problem.... |
| 13770 | - * We're trying to use a non-directory as a directory |
| 13771 | - */ |
| 13772 | + /* Soft delete all the unlinked files */ |
| 13773 | + ylist_for_each_safe(i, n, |
| 13774 | + &dev->unlinked_dir->variant.dir_variant.children) { |
| 13775 | + if (i) { |
| 13776 | + l = ylist_entry(i, yaffs_obj_t, siblings); |
| 13777 | + yaffs_del_obj(l); |
| 13778 | + } |
| 13779 | + } |
| 13780 | |
| 13781 | - T(YAFFS_TRACE_ERROR, |
| 13782 | - (TSTR |
| 13783 | - ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." |
| 13784 | - TENDSTR))); |
| 13785 | - parent = dev->lostNFoundDir; |
| 13786 | - } |
| 13787 | + ylist_for_each_safe(i, n, |
| 13788 | + &dev->del_dir->variant.dir_variant.children) { |
| 13789 | + if (i) { |
| 13790 | + l = ylist_entry(i, yaffs_obj_t, siblings); |
| 13791 | + yaffs_del_obj(l); |
| 13792 | + } |
| 13793 | + } |
| 13794 | |
| 13795 | - yaffs_AddObjectToDirectory(parent, in); |
| 13796 | +} |
| 13797 | |
| 13798 | - itsUnlinked = (parent == dev->deletedDir) || |
| 13799 | - (parent == dev->unlinkedDir); |
| 13800 | +/* |
| 13801 | + * This code iterates through all the objects making sure that they are rooted. |
| 13802 | + * Any unrooted objects are re-rooted in lost+found. |
| 13803 | + * An object needs to be in one of: |
| 13804 | + * - Directly under deleted, unlinked |
| 13805 | + * - Directly or indirectly under root. |
| 13806 | + * |
| 13807 | + * Note: |
| 13808 | + * This code assumes that we don't ever change the current relationships between |
| 13809 | + * directories: |
| 13810 | + * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL |
| 13811 | + * lostNfound->parent == root_dir |
| 13812 | + * |
| 13813 | + * This fixes the problem where directories might have inadvertently been deleted |
| 13814 | + * leaving the object "hanging" without being rooted in the directory tree. |
| 13815 | + */ |
| 13816 | + |
| 13817 | +static int yaffs_has_null_parent(yaffs_dev_t *dev, yaffs_obj_t *obj) |
| 13818 | +{ |
| 13819 | + return (obj == dev->del_dir || |
| 13820 | + obj == dev->unlinked_dir|| |
| 13821 | + obj == dev->root_dir); |
| 13822 | +} |
| 13823 | |
| 13824 | - if (isShrink) { |
| 13825 | - /* Mark the block as having a shrinkHeader */ |
| 13826 | - bi->hasShrinkHeader = 1; |
| 13827 | - } |
| 13828 | +static void yaffs_fix_hanging_objs(yaffs_dev_t *dev) |
| 13829 | +{ |
| 13830 | + yaffs_obj_t *obj; |
| 13831 | + yaffs_obj_t *parent; |
| 13832 | + int i; |
| 13833 | + struct ylist_head *lh; |
| 13834 | + struct ylist_head *n; |
| 13835 | + int depthLimit; |
| 13836 | + int hanging; |
| 13837 | |
| 13838 | - /* Note re hardlinks. |
| 13839 | - * Since we might scan a hardlink before its equivalent object is scanned |
| 13840 | - * we put them all in a list. |
| 13841 | - * After scanning is complete, we should have all the objects, so we run |
| 13842 | - * through this list and fix up all the chains. |
| 13843 | - */ |
| 13844 | + if (dev->read_only) |
| 13845 | + return; |
| 13846 | |
| 13847 | - switch (in->variantType) { |
| 13848 | - case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 13849 | - /* Todo got a problem */ |
| 13850 | - break; |
| 13851 | - case YAFFS_OBJECT_TYPE_FILE: |
| 13852 | - |
| 13853 | - if (in->variant.fileVariant. |
| 13854 | - scannedFileSize < fileSize) { |
| 13855 | - /* This covers the case where the file size is greater |
| 13856 | - * than where the data is |
| 13857 | - * This will happen if the file is resized to be larger |
| 13858 | - * than its current data extents. |
| 13859 | - */ |
| 13860 | - in->variant.fileVariant.fileSize = fileSize; |
| 13861 | - in->variant.fileVariant.scannedFileSize = |
| 13862 | - in->variant.fileVariant.fileSize; |
| 13863 | - } |
| 13864 | + /* Iterate through the objects in each hash entry, |
| 13865 | + * looking at each object. |
| 13866 | + * Make sure it is rooted. |
| 13867 | + */ |
| 13868 | |
| 13869 | - if (isShrink && |
| 13870 | - in->variant.fileVariant.shrinkSize > fileSize) { |
| 13871 | - in->variant.fileVariant.shrinkSize = fileSize; |
| 13872 | - } |
| 13873 | + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { |
| 13874 | + ylist_for_each_safe(lh, n, &dev->obj_bucket[i].list) { |
| 13875 | + if (lh) { |
| 13876 | + obj = ylist_entry(lh, yaffs_obj_t, hash_link); |
| 13877 | + parent= obj->parent; |
| 13878 | + |
| 13879 | + if(yaffs_has_null_parent(dev,obj)){ |
| 13880 | + /* These directories are not hanging */ |
| 13881 | + hanging = 0; |
| 13882 | + } |
| 13883 | + else if(!parent || parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) |
| 13884 | + hanging = 1; |
| 13885 | + else if(yaffs_has_null_parent(dev,parent)) |
| 13886 | + hanging = 0; |
| 13887 | + else { |
| 13888 | + /* |
| 13889 | + * Need to follow the parent chain to see if it is hanging. |
| 13890 | + */ |
| 13891 | + hanging = 0; |
| 13892 | + depthLimit=100; |
| 13893 | |
| 13894 | - break; |
| 13895 | - case YAFFS_OBJECT_TYPE_HARDLINK: |
| 13896 | - if (!itsUnlinked) { |
| 13897 | - in->variant.hardLinkVariant.equivalentObjectId = |
| 13898 | - equivalentObjectId; |
| 13899 | - in->hardLinks.next = |
| 13900 | - (struct ylist_head *) hardList; |
| 13901 | - hardList = in; |
| 13902 | - } |
| 13903 | - break; |
| 13904 | - case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 13905 | - /* Do nothing */ |
| 13906 | - break; |
| 13907 | - case YAFFS_OBJECT_TYPE_SPECIAL: |
| 13908 | - /* Do nothing */ |
| 13909 | - break; |
| 13910 | - case YAFFS_OBJECT_TYPE_SYMLINK: |
| 13911 | - if (oh) { |
| 13912 | - in->variant.symLinkVariant.alias = |
| 13913 | - yaffs_CloneString(oh->alias); |
| 13914 | - if (!in->variant.symLinkVariant.alias) |
| 13915 | - alloc_failed = 1; |
| 13916 | - } |
| 13917 | - break; |
| 13918 | + while(parent != dev->root_dir && |
| 13919 | + parent->parent && |
| 13920 | + parent->parent->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY && |
| 13921 | + depthLimit > 0){ |
| 13922 | + parent = parent->parent; |
| 13923 | + depthLimit--; |
| 13924 | } |
| 13925 | - |
| 13926 | + if(parent != dev->root_dir) |
| 13927 | + hanging = 1; |
| 13928 | + } |
| 13929 | + if(hanging){ |
| 13930 | + T(YAFFS_TRACE_SCAN, |
| 13931 | + (TSTR("Hanging object %d moved to lost and found" TENDSTR), |
| 13932 | + obj->obj_id)); |
| 13933 | + yaffs_add_obj_to_dir(dev->lost_n_found,obj); |
| 13934 | } |
| 13935 | - |
| 13936 | } |
| 13937 | + } |
| 13938 | + } |
| 13939 | +} |
| 13940 | |
| 13941 | - } /* End of scanning for each chunk */ |
| 13942 | |
| 13943 | - if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { |
| 13944 | - /* If we got this far while scanning, then the block is fully allocated. */ |
| 13945 | - state = YAFFS_BLOCK_STATE_FULL; |
| 13946 | - } |
| 13947 | +/* |
| 13948 | + * Delete directory contents for cleaning up lost and found. |
| 13949 | + */ |
| 13950 | +static void yaffs_del_dir_contents(yaffs_obj_t *dir) |
| 13951 | +{ |
| 13952 | + yaffs_obj_t *obj; |
| 13953 | + struct ylist_head *lh; |
| 13954 | + struct ylist_head *n; |
| 13955 | |
| 13956 | - bi->blockState = state; |
| 13957 | + if(dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) |
| 13958 | + YBUG(); |
| 13959 | + |
| 13960 | + ylist_for_each_safe(lh, n, &dir->variant.dir_variant.children) { |
| 13961 | + if (lh) { |
| 13962 | + obj = ylist_entry(lh, yaffs_obj_t, siblings); |
| 13963 | + if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) |
| 13964 | + yaffs_del_dir_contents(obj); |
| 13965 | + |
| 13966 | + T(YAFFS_TRACE_SCAN, |
| 13967 | + (TSTR("Deleting lost_found object %d" TENDSTR), |
| 13968 | + obj->obj_id)); |
| 13969 | |
| 13970 | - /* Now let's see if it was dirty */ |
| 13971 | - if (bi->pagesInUse == 0 && |
| 13972 | - !bi->hasShrinkHeader && |
| 13973 | - bi->blockState == YAFFS_BLOCK_STATE_FULL) { |
| 13974 | - yaffs_BlockBecameDirty(dev, blk); |
| 13975 | + /* Need to use UnlinkObject since Delete would not handle |
| 13976 | + * hardlinked objects correctly. |
| 13977 | + */ |
| 13978 | + yaffs_unlink_obj(obj); |
| 13979 | } |
| 13980 | - |
| 13981 | } |
| 13982 | + |
| 13983 | +} |
| 13984 | |
| 13985 | - if (altBlockIndex) |
| 13986 | - YFREE_ALT(blockIndex); |
| 13987 | - else |
| 13988 | - YFREE(blockIndex); |
| 13989 | +static void yaffs_empty_l_n_f(yaffs_dev_t *dev) |
| 13990 | +{ |
| 13991 | + yaffs_del_dir_contents(dev->lost_n_found); |
| 13992 | +} |
| 13993 | |
| 13994 | - /* Ok, we've done all the scanning. |
| 13995 | - * Fix up the hard link chains. |
| 13996 | - * We should now have scanned all the objects, now it's time to add these |
| 13997 | - * hardlinks. |
| 13998 | - */ |
| 13999 | - yaffs_HardlinkFixup(dev, hardList); |
| 14000 | +static void yaffs_check_obj_details_loaded(yaffs_obj_t *in) |
| 14001 | +{ |
| 14002 | + __u8 *chunkData; |
| 14003 | + yaffs_obj_header *oh; |
| 14004 | + yaffs_dev_t *dev; |
| 14005 | + yaffs_ext_tags tags; |
| 14006 | + int result; |
| 14007 | + int alloc_failed = 0; |
| 14008 | |
| 14009 | + if (!in) |
| 14010 | + return; |
| 14011 | |
| 14012 | - yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); |
| 14013 | + dev = in->my_dev; |
| 14014 | |
| 14015 | - if (alloc_failed) |
| 14016 | - return YAFFS_FAIL; |
| 14017 | +#if 0 |
| 14018 | + T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR), |
| 14019 | + in->obj_id, |
| 14020 | + in->lazy_loaded ? "not yet" : "already")); |
| 14021 | +#endif |
| 14022 | |
| 14023 | - T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR))); |
| 14024 | + if (in->lazy_loaded && in->hdr_chunk > 0) { |
| 14025 | + in->lazy_loaded = 0; |
| 14026 | + chunkData = yaffs_get_temp_buffer(dev, __LINE__); |
| 14027 | |
| 14028 | - return YAFFS_OK; |
| 14029 | -} |
| 14030 | + result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, chunkData, &tags); |
| 14031 | + oh = (yaffs_obj_header *) chunkData; |
| 14032 | |
| 14033 | -/*------------------------------ Directory Functions ----------------------------- */ |
| 14034 | + in->yst_mode = oh->yst_mode; |
| 14035 | +#ifdef CONFIG_YAFFS_WINCE |
| 14036 | + in->win_atime[0] = oh->win_atime[0]; |
| 14037 | + in->win_ctime[0] = oh->win_ctime[0]; |
| 14038 | + in->win_mtime[0] = oh->win_mtime[0]; |
| 14039 | + in->win_atime[1] = oh->win_atime[1]; |
| 14040 | + in->win_ctime[1] = oh->win_ctime[1]; |
| 14041 | + in->win_mtime[1] = oh->win_mtime[1]; |
| 14042 | +#else |
| 14043 | + in->yst_uid = oh->yst_uid; |
| 14044 | + in->yst_gid = oh->yst_gid; |
| 14045 | + in->yst_atime = oh->yst_atime; |
| 14046 | + in->yst_mtime = oh->yst_mtime; |
| 14047 | + in->yst_ctime = oh->yst_ctime; |
| 14048 | + in->yst_rdev = oh->yst_rdev; |
| 14049 | |
| 14050 | -static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj) |
| 14051 | -{ |
| 14052 | - struct ylist_head *lh; |
| 14053 | - yaffs_Object *listObj; |
| 14054 | +#endif |
| 14055 | + yaffs_set_obj_name_from_oh(in, oh); |
| 14056 | |
| 14057 | - int count = 0; |
| 14058 | + if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { |
| 14059 | + in->variant.symlink_variant.alias = |
| 14060 | + yaffs_clone_str(oh->alias); |
| 14061 | + if (!in->variant.symlink_variant.alias) |
| 14062 | + alloc_failed = 1; /* Not returned to caller */ |
| 14063 | + } |
| 14064 | |
| 14065 | - if (!obj) { |
| 14066 | - T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR))); |
| 14067 | - YBUG(); |
| 14068 | - return; |
| 14069 | + yaffs_release_temp_buffer(dev, chunkData, __LINE__); |
| 14070 | } |
| 14071 | +} |
| 14072 | |
| 14073 | - if (yaffs_SkipVerification(obj->myDev)) |
| 14074 | - return; |
| 14075 | +/*------------------------------ Directory Functions ----------------------------- */ |
| 14076 | |
| 14077 | - if (!obj->parent) { |
| 14078 | - T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR))); |
| 14079 | - YBUG(); |
| 14080 | +/* |
| 14081 | + *yaffs_update_parent() handles fixing a directories mtime and ctime when a new |
| 14082 | + * link (ie. name) is created or deleted in the directory. |
| 14083 | + * |
| 14084 | + * ie. |
| 14085 | + * create dir/a : update dir's mtime/ctime |
| 14086 | + * rm dir/a: update dir's mtime/ctime |
| 14087 | + * modify dir/a: don't update dir's mtimme/ctime |
| 14088 | + * |
| 14089 | + * This can be handled immediately or defered. Defering helps reduce the number |
| 14090 | + * of updates when many files in a directory are changed within a brief period. |
| 14091 | + * |
| 14092 | + * If the directory updating is defered then yaffs_update_dirty_dirs must be |
| 14093 | + * called periodically. |
| 14094 | + */ |
| 14095 | + |
| 14096 | +static void yaffs_update_parent(yaffs_obj_t *obj) |
| 14097 | +{ |
| 14098 | + yaffs_dev_t *dev; |
| 14099 | + if(!obj) |
| 14100 | return; |
| 14101 | - } |
| 14102 | - |
| 14103 | - if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 14104 | - T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR))); |
| 14105 | - YBUG(); |
| 14106 | - } |
| 14107 | - |
| 14108 | - /* Iterate through the objects in each hash entry */ |
| 14109 | +#ifndef CONFIG_YAFFS_WINCE |
| 14110 | |
| 14111 | - ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) { |
| 14112 | - if (lh) { |
| 14113 | - listObj = ylist_entry(lh, yaffs_Object, siblings); |
| 14114 | - yaffs_VerifyObject(listObj); |
| 14115 | - if (obj == listObj) |
| 14116 | - count++; |
| 14117 | + dev = obj->my_dev; |
| 14118 | + obj->dirty = 1; |
| 14119 | + obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME; |
| 14120 | + if(dev->param.defered_dir_update){ |
| 14121 | + struct ylist_head *link = &obj->variant.dir_variant.dirty; |
| 14122 | + |
| 14123 | + if(ylist_empty(link)){ |
| 14124 | + ylist_add(link,&dev->dirty_dirs); |
| 14125 | + T(YAFFS_TRACE_BACKGROUND, (TSTR("Added object %d to dirty directories" TENDSTR),obj->obj_id)); |
| 14126 | } |
| 14127 | - } |
| 14128 | |
| 14129 | - if (count != 1) { |
| 14130 | - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count)); |
| 14131 | - YBUG(); |
| 14132 | - } |
| 14133 | + } else |
| 14134 | + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); |
| 14135 | +#endif |
| 14136 | } |
| 14137 | |
| 14138 | -static void yaffs_VerifyDirectory(yaffs_Object *directory) |
| 14139 | +void yaffs_update_dirty_dirs(yaffs_dev_t *dev) |
| 14140 | { |
| 14141 | - struct ylist_head *lh; |
| 14142 | - yaffs_Object *listObj; |
| 14143 | - |
| 14144 | - if (!directory) { |
| 14145 | - YBUG(); |
| 14146 | - return; |
| 14147 | - } |
| 14148 | + struct ylist_head *link; |
| 14149 | + yaffs_obj_t *obj; |
| 14150 | + yaffs_dir_s *dS; |
| 14151 | + yaffs_obj_variant *oV; |
| 14152 | |
| 14153 | - if (yaffs_SkipFullVerification(directory->myDev)) |
| 14154 | - return; |
| 14155 | + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update dirty directories" TENDSTR))); |
| 14156 | |
| 14157 | - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 14158 | - T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType)); |
| 14159 | - YBUG(); |
| 14160 | - } |
| 14161 | + while(!ylist_empty(&dev->dirty_dirs)){ |
| 14162 | + link = dev->dirty_dirs.next; |
| 14163 | + ylist_del_init(link); |
| 14164 | + |
| 14165 | + dS=ylist_entry(link,yaffs_dir_s,dirty); |
| 14166 | + oV = ylist_entry(dS,yaffs_obj_variant,dir_variant); |
| 14167 | + obj = ylist_entry(oV,yaffs_obj_t,variant); |
| 14168 | |
| 14169 | - /* Iterate through the objects in each hash entry */ |
| 14170 | + T(YAFFS_TRACE_BACKGROUND, (TSTR("Update directory %d" TENDSTR), obj->obj_id)); |
| 14171 | |
| 14172 | - ylist_for_each(lh, &directory->variant.directoryVariant.children) { |
| 14173 | - if (lh) { |
| 14174 | - listObj = ylist_entry(lh, yaffs_Object, siblings); |
| 14175 | - if (listObj->parent != directory) { |
| 14176 | - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent)); |
| 14177 | - YBUG(); |
| 14178 | - } |
| 14179 | - yaffs_VerifyObjectInDirectory(listObj); |
| 14180 | - } |
| 14181 | + if(obj->dirty) |
| 14182 | + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); |
| 14183 | } |
| 14184 | } |
| 14185 | |
| 14186 | - |
| 14187 | -static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj) |
| 14188 | +static void yaffs_remove_obj_from_dir(yaffs_obj_t *obj) |
| 14189 | { |
| 14190 | - yaffs_Device *dev = obj->myDev; |
| 14191 | - yaffs_Object *parent; |
| 14192 | + yaffs_dev_t *dev = obj->my_dev; |
| 14193 | + yaffs_obj_t *parent; |
| 14194 | |
| 14195 | - yaffs_VerifyObjectInDirectory(obj); |
| 14196 | + yaffs_verify_obj_in_dir(obj); |
| 14197 | parent = obj->parent; |
| 14198 | |
| 14199 | - yaffs_VerifyDirectory(parent); |
| 14200 | + yaffs_verify_dir(parent); |
| 14201 | |
| 14202 | - if (dev && dev->removeObjectCallback) |
| 14203 | - dev->removeObjectCallback(obj); |
| 14204 | + if (dev && dev->param.remove_obj_fn) |
| 14205 | + dev->param.remove_obj_fn(obj); |
| 14206 | |
| 14207 | |
| 14208 | ylist_del_init(&obj->siblings); |
| 14209 | obj->parent = NULL; |
| 14210 | - |
| 14211 | - yaffs_VerifyDirectory(parent); |
| 14212 | + |
| 14213 | + yaffs_verify_dir(parent); |
| 14214 | } |
| 14215 | |
| 14216 | - |
| 14217 | -static void yaffs_AddObjectToDirectory(yaffs_Object *directory, |
| 14218 | - yaffs_Object *obj) |
| 14219 | +void yaffs_add_obj_to_dir(yaffs_obj_t *directory, |
| 14220 | + yaffs_obj_t *obj) |
| 14221 | { |
| 14222 | if (!directory) { |
| 14223 | T(YAFFS_TRACE_ALWAYS, |
| 14224 | @@ -6699,7 +4495,7 @@ static void yaffs_AddObjectToDirectory(y |
| 14225 | YBUG(); |
| 14226 | return; |
| 14227 | } |
| 14228 | - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 14229 | + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 14230 | T(YAFFS_TRACE_ALWAYS, |
| 14231 | (TSTR |
| 14232 | ("tragedy: Trying to add an object to a non-directory" |
| 14233 | @@ -6713,27 +4509,27 @@ static void yaffs_AddObjectToDirectory(y |
| 14234 | } |
| 14235 | |
| 14236 | |
| 14237 | - yaffs_VerifyDirectory(directory); |
| 14238 | + yaffs_verify_dir(directory); |
| 14239 | |
| 14240 | - yaffs_RemoveObjectFromDirectory(obj); |
| 14241 | + yaffs_remove_obj_from_dir(obj); |
| 14242 | |
| 14243 | |
| 14244 | /* Now add it */ |
| 14245 | - ylist_add(&obj->siblings, &directory->variant.directoryVariant.children); |
| 14246 | + ylist_add(&obj->siblings, &directory->variant.dir_variant.children); |
| 14247 | obj->parent = directory; |
| 14248 | |
| 14249 | - if (directory == obj->myDev->unlinkedDir |
| 14250 | - || directory == obj->myDev->deletedDir) { |
| 14251 | + if (directory == obj->my_dev->unlinked_dir |
| 14252 | + || directory == obj->my_dev->del_dir) { |
| 14253 | obj->unlinked = 1; |
| 14254 | - obj->myDev->nUnlinkedFiles++; |
| 14255 | - obj->renameAllowed = 0; |
| 14256 | + obj->my_dev->n_unlinked_files++; |
| 14257 | + obj->rename_allowed = 0; |
| 14258 | } |
| 14259 | |
| 14260 | - yaffs_VerifyDirectory(directory); |
| 14261 | - yaffs_VerifyObjectInDirectory(obj); |
| 14262 | + yaffs_verify_dir(directory); |
| 14263 | + yaffs_verify_obj_in_dir(obj); |
| 14264 | } |
| 14265 | |
| 14266 | -yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory, |
| 14267 | +yaffs_obj_t *yaffs_find_by_name(yaffs_obj_t *directory, |
| 14268 | const YCHAR *name) |
| 14269 | { |
| 14270 | int sum; |
| 14271 | @@ -6741,7 +4537,7 @@ yaffs_Object *yaffs_FindObjectByName(yaf |
| 14272 | struct ylist_head *i; |
| 14273 | YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; |
| 14274 | |
| 14275 | - yaffs_Object *l; |
| 14276 | + yaffs_obj_t *l; |
| 14277 | |
| 14278 | if (!name) |
| 14279 | return NULL; |
| 14280 | @@ -6749,39 +4545,39 @@ yaffs_Object *yaffs_FindObjectByName(yaf |
| 14281 | if (!directory) { |
| 14282 | T(YAFFS_TRACE_ALWAYS, |
| 14283 | (TSTR |
| 14284 | - ("tragedy: yaffs_FindObjectByName: null pointer directory" |
| 14285 | + ("tragedy: yaffs_find_by_name: null pointer directory" |
| 14286 | TENDSTR))); |
| 14287 | YBUG(); |
| 14288 | return NULL; |
| 14289 | } |
| 14290 | - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 14291 | + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 14292 | T(YAFFS_TRACE_ALWAYS, |
| 14293 | (TSTR |
| 14294 | - ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); |
| 14295 | + ("tragedy: yaffs_find_by_name: non-directory" TENDSTR))); |
| 14296 | YBUG(); |
| 14297 | } |
| 14298 | |
| 14299 | - sum = yaffs_CalcNameSum(name); |
| 14300 | + sum = yaffs_calc_name_sum(name); |
| 14301 | |
| 14302 | - ylist_for_each(i, &directory->variant.directoryVariant.children) { |
| 14303 | + ylist_for_each(i, &directory->variant.dir_variant.children) { |
| 14304 | if (i) { |
| 14305 | - l = ylist_entry(i, yaffs_Object, siblings); |
| 14306 | + l = ylist_entry(i, yaffs_obj_t, siblings); |
| 14307 | |
| 14308 | if (l->parent != directory) |
| 14309 | YBUG(); |
| 14310 | |
| 14311 | - yaffs_CheckObjectDetailsLoaded(l); |
| 14312 | + yaffs_check_obj_details_loaded(l); |
| 14313 | |
| 14314 | /* Special case for lost-n-found */ |
| 14315 | - if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) { |
| 14316 | + if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { |
| 14317 | if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) |
| 14318 | return l; |
| 14319 | - } else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0) { |
| 14320 | + } else if (yaffs_sum_cmp(l->sum, sum) || l->hdr_chunk <= 0) { |
| 14321 | /* LostnFound chunk called Objxxx |
| 14322 | * Do a real check |
| 14323 | */ |
| 14324 | - yaffs_GetObjectName(l, buffer, |
| 14325 | - YAFFS_MAX_NAME_LENGTH); |
| 14326 | + yaffs_get_obj_name(l, buffer, |
| 14327 | + YAFFS_MAX_NAME_LENGTH + 1); |
| 14328 | if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0) |
| 14329 | return l; |
| 14330 | } |
| 14331 | @@ -6793,31 +4589,31 @@ yaffs_Object *yaffs_FindObjectByName(yaf |
| 14332 | |
| 14333 | |
| 14334 | #if 0 |
| 14335 | -int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir, |
| 14336 | - int (*fn) (yaffs_Object *)) |
| 14337 | +int yaffs_ApplyToDirectoryChildren(yaffs_obj_t *the_dir, |
| 14338 | + int (*fn) (yaffs_obj_t *)) |
| 14339 | { |
| 14340 | struct ylist_head *i; |
| 14341 | - yaffs_Object *l; |
| 14342 | + yaffs_obj_t *l; |
| 14343 | |
| 14344 | - if (!theDir) { |
| 14345 | + if (!the_dir) { |
| 14346 | T(YAFFS_TRACE_ALWAYS, |
| 14347 | (TSTR |
| 14348 | - ("tragedy: yaffs_FindObjectByName: null pointer directory" |
| 14349 | + ("tragedy: yaffs_find_by_name: null pointer directory" |
| 14350 | TENDSTR))); |
| 14351 | YBUG(); |
| 14352 | return YAFFS_FAIL; |
| 14353 | } |
| 14354 | - if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 14355 | + if (the_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 14356 | T(YAFFS_TRACE_ALWAYS, |
| 14357 | (TSTR |
| 14358 | - ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); |
| 14359 | + ("tragedy: yaffs_find_by_name: non-directory" TENDSTR))); |
| 14360 | YBUG(); |
| 14361 | return YAFFS_FAIL; |
| 14362 | } |
| 14363 | |
| 14364 | - ylist_for_each(i, &theDir->variant.directoryVariant.children) { |
| 14365 | + ylist_for_each(i, &the_dir->variant.dir_variant.children) { |
| 14366 | if (i) { |
| 14367 | - l = ylist_entry(i, yaffs_Object, siblings); |
| 14368 | + l = ylist_entry(i, yaffs_obj_t, siblings); |
| 14369 | if (l && !fn(l)) |
| 14370 | return YAFFS_FAIL; |
| 14371 | } |
| 14372 | @@ -6832,82 +4628,175 @@ int yaffs_ApplyToDirectoryChildren(yaffs |
| 14373 | * actual object. |
| 14374 | */ |
| 14375 | |
| 14376 | -yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj) |
| 14377 | +yaffs_obj_t *yaffs_get_equivalent_obj(yaffs_obj_t *obj) |
| 14378 | { |
| 14379 | - if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { |
| 14380 | + if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { |
| 14381 | /* We want the object id of the equivalent object, not this one */ |
| 14382 | - obj = obj->variant.hardLinkVariant.equivalentObject; |
| 14383 | - yaffs_CheckObjectDetailsLoaded(obj); |
| 14384 | + obj = obj->variant.hardlink_variant.equiv_obj; |
| 14385 | + yaffs_check_obj_details_loaded(obj); |
| 14386 | } |
| 14387 | return obj; |
| 14388 | } |
| 14389 | |
| 14390 | -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize) |
| 14391 | -{ |
| 14392 | - memset(name, 0, buffSize * sizeof(YCHAR)); |
| 14393 | - |
| 14394 | - yaffs_CheckObjectDetailsLoaded(obj); |
| 14395 | +/* |
| 14396 | + * A note or two on object names. |
| 14397 | + * * If the object name is missing, we then make one up in the form objnnn |
| 14398 | + * |
| 14399 | + * * ASCII names are stored in the object header's name field from byte zero |
| 14400 | + * * Unicode names are historically stored starting from byte zero. |
| 14401 | + * |
| 14402 | + * Then there are automatic Unicode names... |
| 14403 | + * The purpose of these is to save names in a way that can be read as |
| 14404 | + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII |
| 14405 | + * system to share files. |
| 14406 | + * |
| 14407 | + * These automatic unicode are stored slightly differently... |
| 14408 | + * - If the name can fit in the ASCII character space then they are saved as |
| 14409 | + * ascii names as per above. |
| 14410 | + * - If the name needs Unicode then the name is saved in Unicode |
| 14411 | + * starting at oh->name[1]. |
| 14412 | |
| 14413 | - if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { |
| 14414 | - yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); |
| 14415 | - } else if (obj->hdrChunk <= 0) { |
| 14416 | + */ |
| 14417 | +static void yaffs_fix_null_name(yaffs_obj_t * obj,YCHAR * name, int buffer_size) |
| 14418 | +{ |
| 14419 | + /* Create an object name if we could not find one. */ |
| 14420 | + if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){ |
| 14421 | YCHAR locName[20]; |
| 14422 | YCHAR numString[20]; |
| 14423 | YCHAR *x = &numString[19]; |
| 14424 | - unsigned v = obj->objectId; |
| 14425 | + unsigned v = obj->obj_id; |
| 14426 | numString[19] = 0; |
| 14427 | - while (v > 0) { |
| 14428 | + while(v>0){ |
| 14429 | x--; |
| 14430 | *x = '0' + (v % 10); |
| 14431 | v /= 10; |
| 14432 | } |
| 14433 | /* make up a name */ |
| 14434 | yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX); |
| 14435 | - yaffs_strcat(locName, x); |
| 14436 | - yaffs_strncpy(name, locName, buffSize - 1); |
| 14437 | + yaffs_strcat(locName,x); |
| 14438 | + yaffs_strncpy(name, locName, buffer_size - 1); |
| 14439 | + } |
| 14440 | +} |
| 14441 | + |
| 14442 | +static void yaffs_load_name_from_oh(yaffs_dev_t *dev,YCHAR *name, const YCHAR *ohName, int bufferSize) |
| 14443 | +{ |
| 14444 | +#ifdef CONFIG_YAFFS_AUTO_UNICODE |
| 14445 | + if(dev->param.auto_unicode){ |
| 14446 | + if(*ohName){ |
| 14447 | + /* It is an ASCII name, so do an ASCII to unicode conversion */ |
| 14448 | + const char *asciiOhName = (const char *)ohName; |
| 14449 | + int n = bufferSize - 1; |
| 14450 | + while(n > 0 && *asciiOhName){ |
| 14451 | + *name = *asciiOhName; |
| 14452 | + name++; |
| 14453 | + asciiOhName++; |
| 14454 | + n--; |
| 14455 | + } |
| 14456 | + } else |
| 14457 | + yaffs_strncpy(name,ohName+1, bufferSize -1); |
| 14458 | + } else |
| 14459 | +#endif |
| 14460 | + yaffs_strncpy(name, ohName, bufferSize - 1); |
| 14461 | +} |
| 14462 | + |
| 14463 | + |
| 14464 | +static void yaffs_load_oh_from_name(yaffs_dev_t *dev, YCHAR *ohName, const YCHAR *name) |
| 14465 | +{ |
| 14466 | +#ifdef CONFIG_YAFFS_AUTO_UNICODE |
| 14467 | + |
| 14468 | + int isAscii; |
| 14469 | + YCHAR *w; |
| 14470 | + |
| 14471 | + if(dev->param.auto_unicode){ |
| 14472 | + |
| 14473 | + isAscii = 1; |
| 14474 | + w = name; |
| 14475 | + |
| 14476 | + /* Figure out if the name will fit in ascii character set */ |
| 14477 | + while(isAscii && *w){ |
| 14478 | + if((*w) & 0xff00) |
| 14479 | + isAscii = 0; |
| 14480 | + w++; |
| 14481 | + } |
| 14482 | |
| 14483 | + if(isAscii){ |
| 14484 | + /* It is an ASCII name, so do a unicode to ascii conversion */ |
| 14485 | + char *asciiOhName = (char *)ohName; |
| 14486 | + int n = YAFFS_MAX_NAME_LENGTH - 1; |
| 14487 | + while(n > 0 && *name){ |
| 14488 | + *asciiOhName= *name; |
| 14489 | + name++; |
| 14490 | + asciiOhName++; |
| 14491 | + n--; |
| 14492 | + } |
| 14493 | + } else{ |
| 14494 | + /* It is a unicode name, so save starting at the second YCHAR */ |
| 14495 | + *ohName = 0; |
| 14496 | + yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2); |
| 14497 | + } |
| 14498 | } |
| 14499 | + else |
| 14500 | +#endif |
| 14501 | + yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1); |
| 14502 | + |
| 14503 | +} |
| 14504 | + |
| 14505 | +int yaffs_get_obj_name(yaffs_obj_t * obj, YCHAR * name, int buffer_size) |
| 14506 | +{ |
| 14507 | + memset(name, 0, buffer_size * sizeof(YCHAR)); |
| 14508 | + |
| 14509 | + yaffs_check_obj_details_loaded(obj); |
| 14510 | + |
| 14511 | + if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { |
| 14512 | + yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1); |
| 14513 | + } |
| 14514 | #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM |
| 14515 | - else if (obj->shortName[0]) |
| 14516 | - yaffs_strcpy(name, obj->shortName); |
| 14517 | + else if (obj->short_name[0]) { |
| 14518 | + yaffs_strcpy(name, obj->short_name); |
| 14519 | + } |
| 14520 | #endif |
| 14521 | - else { |
| 14522 | + else if(obj->hdr_chunk > 0) { |
| 14523 | int result; |
| 14524 | - __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__); |
| 14525 | + __u8 *buffer = yaffs_get_temp_buffer(obj->my_dev, __LINE__); |
| 14526 | |
| 14527 | - yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer; |
| 14528 | + yaffs_obj_header *oh = (yaffs_obj_header *) buffer; |
| 14529 | |
| 14530 | - memset(buffer, 0, obj->myDev->nDataBytesPerChunk); |
| 14531 | + memset(buffer, 0, obj->my_dev->data_bytes_per_chunk); |
| 14532 | |
| 14533 | - if (obj->hdrChunk > 0) { |
| 14534 | - result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev, |
| 14535 | - obj->hdrChunk, buffer, |
| 14536 | + if (obj->hdr_chunk > 0) { |
| 14537 | + result = yaffs_rd_chunk_tags_nand(obj->my_dev, |
| 14538 | + obj->hdr_chunk, buffer, |
| 14539 | NULL); |
| 14540 | } |
| 14541 | - yaffs_strncpy(name, oh->name, buffSize - 1); |
| 14542 | + yaffs_load_name_from_oh(obj->my_dev,name,oh->name,buffer_size); |
| 14543 | |
| 14544 | - yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__); |
| 14545 | + yaffs_release_temp_buffer(obj->my_dev, buffer, __LINE__); |
| 14546 | } |
| 14547 | |
| 14548 | - return yaffs_strlen(name); |
| 14549 | + yaffs_fix_null_name(obj,name,buffer_size); |
| 14550 | + |
| 14551 | + return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH); |
| 14552 | } |
| 14553 | |
| 14554 | -int yaffs_GetObjectFileLength(yaffs_Object *obj) |
| 14555 | + |
| 14556 | +int yaffs_get_obj_length(yaffs_obj_t *obj) |
| 14557 | { |
| 14558 | /* Dereference any hard linking */ |
| 14559 | - obj = yaffs_GetEquivalentObject(obj); |
| 14560 | + obj = yaffs_get_equivalent_obj(obj); |
| 14561 | |
| 14562 | - if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) |
| 14563 | - return obj->variant.fileVariant.fileSize; |
| 14564 | - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) |
| 14565 | - return yaffs_strlen(obj->variant.symLinkVariant.alias); |
| 14566 | - else { |
| 14567 | + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) |
| 14568 | + return obj->variant.file_variant.file_size; |
| 14569 | + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK){ |
| 14570 | + if(!obj->variant.symlink_variant.alias) |
| 14571 | + return 0; |
| 14572 | + return yaffs_strnlen(obj->variant.symlink_variant.alias,YAFFS_MAX_ALIAS_LENGTH); |
| 14573 | + } else { |
| 14574 | /* Only a directory should drop through to here */ |
| 14575 | - return obj->myDev->nDataBytesPerChunk; |
| 14576 | + return obj->my_dev->data_bytes_per_chunk; |
| 14577 | } |
| 14578 | } |
| 14579 | |
| 14580 | -int yaffs_GetObjectLinkCount(yaffs_Object *obj) |
| 14581 | +int yaffs_get_obj_link_count(yaffs_obj_t *obj) |
| 14582 | { |
| 14583 | int count = 0; |
| 14584 | struct ylist_head *i; |
| 14585 | @@ -6915,24 +4804,24 @@ int yaffs_GetObjectLinkCount(yaffs_Objec |
| 14586 | if (!obj->unlinked) |
| 14587 | count++; /* the object itself */ |
| 14588 | |
| 14589 | - ylist_for_each(i, &obj->hardLinks) |
| 14590 | + ylist_for_each(i, &obj->hard_links) |
| 14591 | count++; /* add the hard links; */ |
| 14592 | |
| 14593 | return count; |
| 14594 | } |
| 14595 | |
| 14596 | -int yaffs_GetObjectInode(yaffs_Object *obj) |
| 14597 | +int yaffs_get_obj_inode(yaffs_obj_t *obj) |
| 14598 | { |
| 14599 | - obj = yaffs_GetEquivalentObject(obj); |
| 14600 | + obj = yaffs_get_equivalent_obj(obj); |
| 14601 | |
| 14602 | - return obj->objectId; |
| 14603 | + return obj->obj_id; |
| 14604 | } |
| 14605 | |
| 14606 | -unsigned yaffs_GetObjectType(yaffs_Object *obj) |
| 14607 | +unsigned yaffs_get_obj_type(yaffs_obj_t *obj) |
| 14608 | { |
| 14609 | - obj = yaffs_GetEquivalentObject(obj); |
| 14610 | + obj = yaffs_get_equivalent_obj(obj); |
| 14611 | |
| 14612 | - switch (obj->variantType) { |
| 14613 | + switch (obj->variant_type) { |
| 14614 | case YAFFS_OBJECT_TYPE_FILE: |
| 14615 | return DT_REG; |
| 14616 | break; |
| 14617 | @@ -6960,18 +4849,18 @@ unsigned yaffs_GetObjectType(yaffs_Objec |
| 14618 | } |
| 14619 | } |
| 14620 | |
| 14621 | -YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj) |
| 14622 | +YCHAR *yaffs_get_symlink_alias(yaffs_obj_t *obj) |
| 14623 | { |
| 14624 | - obj = yaffs_GetEquivalentObject(obj); |
| 14625 | - if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) |
| 14626 | - return yaffs_CloneString(obj->variant.symLinkVariant.alias); |
| 14627 | + obj = yaffs_get_equivalent_obj(obj); |
| 14628 | + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) |
| 14629 | + return yaffs_clone_str(obj->variant.symlink_variant.alias); |
| 14630 | else |
| 14631 | - return yaffs_CloneString(_Y("")); |
| 14632 | + return yaffs_clone_str(_Y("")); |
| 14633 | } |
| 14634 | |
| 14635 | #ifndef CONFIG_YAFFS_WINCE |
| 14636 | |
| 14637 | -int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr) |
| 14638 | +int yaffs_set_attribs(yaffs_obj_t *obj, struct iattr *attr) |
| 14639 | { |
| 14640 | unsigned int valid = attr->ia_valid; |
| 14641 | |
| 14642 | @@ -6990,14 +4879,14 @@ int yaffs_SetAttributes(yaffs_Object *ob |
| 14643 | obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); |
| 14644 | |
| 14645 | if (valid & ATTR_SIZE) |
| 14646 | - yaffs_ResizeFile(obj, attr->ia_size); |
| 14647 | + yaffs_resize_file(obj, attr->ia_size); |
| 14648 | |
| 14649 | - yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); |
| 14650 | + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); |
| 14651 | |
| 14652 | return YAFFS_OK; |
| 14653 | |
| 14654 | } |
| 14655 | -int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr) |
| 14656 | +int yaffs_get_attribs(yaffs_obj_t *obj, struct iattr *attr) |
| 14657 | { |
| 14658 | unsigned int valid = 0; |
| 14659 | |
| 14660 | @@ -7015,7 +4904,7 @@ int yaffs_GetAttributes(yaffs_Object *ob |
| 14661 | Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; |
| 14662 | valid |= ATTR_MTIME; |
| 14663 | |
| 14664 | - attr->ia_size = yaffs_GetFileSize(obj); |
| 14665 | + attr->ia_size = yaffs_get_file_size(obj); |
| 14666 | valid |= ATTR_SIZE; |
| 14667 | |
| 14668 | attr->ia_valid = valid; |
| 14669 | @@ -7025,20 +4914,137 @@ int yaffs_GetAttributes(yaffs_Object *ob |
| 14670 | |
| 14671 | #endif |
| 14672 | |
| 14673 | + |
| 14674 | +static int yaffs_do_xattrib_mod(yaffs_obj_t *obj, int set, const YCHAR *name, const void *value, int size, int flags) |
| 14675 | +{ |
| 14676 | + yaffs_xattr_mod xmod; |
| 14677 | + |
| 14678 | + int result; |
| 14679 | + |
| 14680 | + xmod.set = set; |
| 14681 | + xmod.name = name; |
| 14682 | + xmod.data = value; |
| 14683 | + xmod.size = size; |
| 14684 | + xmod.flags = flags; |
| 14685 | + xmod.result = -ENOSPC; |
| 14686 | + |
| 14687 | + result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod); |
| 14688 | + |
| 14689 | + if(result > 0) |
| 14690 | + return xmod.result; |
| 14691 | + else |
| 14692 | + return -ENOSPC; |
| 14693 | +} |
| 14694 | + |
| 14695 | +static int yaffs_apply_xattrib_mod(yaffs_obj_t *obj, char *buffer, yaffs_xattr_mod *xmod) |
| 14696 | +{ |
| 14697 | + int retval = 0; |
| 14698 | + int x_offs = sizeof(yaffs_obj_header); |
| 14699 | + yaffs_dev_t *dev = obj->my_dev; |
| 14700 | + int x_size = dev->data_bytes_per_chunk - sizeof(yaffs_obj_header); |
| 14701 | + |
| 14702 | + char * x_buffer = buffer + x_offs; |
| 14703 | + |
| 14704 | + if(xmod->set) |
| 14705 | + retval = nval_set(x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags); |
| 14706 | + else |
| 14707 | + retval = nval_del(x_buffer, x_size, xmod->name); |
| 14708 | + |
| 14709 | + obj->has_xattr = nval_hasvalues(x_buffer, x_size); |
| 14710 | + obj->xattr_known = 1; |
| 14711 | + |
| 14712 | + xmod->result = retval; |
| 14713 | + |
| 14714 | + return retval; |
| 14715 | +} |
| 14716 | + |
| 14717 | +static int yaffs_do_xattrib_fetch(yaffs_obj_t *obj, const YCHAR *name, void *value, int size) |
| 14718 | +{ |
| 14719 | + char *buffer = NULL; |
| 14720 | + int result; |
| 14721 | + yaffs_ext_tags tags; |
| 14722 | + yaffs_dev_t *dev = obj->my_dev; |
| 14723 | + int x_offs = sizeof(yaffs_obj_header); |
| 14724 | + int x_size = dev->data_bytes_per_chunk - sizeof(yaffs_obj_header); |
| 14725 | + |
| 14726 | + char * x_buffer; |
| 14727 | + |
| 14728 | + int retval = 0; |
| 14729 | + |
| 14730 | + if(obj->hdr_chunk < 1) |
| 14731 | + return -ENODATA; |
| 14732 | + |
| 14733 | + /* If we know that the object has no xattribs then don't do all the |
| 14734 | + * reading and parsing. |
| 14735 | + */ |
| 14736 | + if(obj->xattr_known && !obj->has_xattr){ |
| 14737 | + if(name) |
| 14738 | + return -ENODATA; |
| 14739 | + else |
| 14740 | + return 0; |
| 14741 | + } |
| 14742 | + |
| 14743 | + buffer = (char *) yaffs_get_temp_buffer(dev, __LINE__); |
| 14744 | + if(!buffer) |
| 14745 | + return -ENOMEM; |
| 14746 | + |
| 14747 | + result = yaffs_rd_chunk_tags_nand(dev,obj->hdr_chunk, (__u8 *)buffer, &tags); |
| 14748 | + |
| 14749 | + if(result != YAFFS_OK) |
| 14750 | + retval = -ENOENT; |
| 14751 | + else{ |
| 14752 | + x_buffer = buffer + x_offs; |
| 14753 | + |
| 14754 | + if (!obj->xattr_known){ |
| 14755 | + obj->has_xattr = nval_hasvalues(x_buffer, x_size); |
| 14756 | + obj->xattr_known = 1; |
| 14757 | + } |
| 14758 | + |
| 14759 | + if(name) |
| 14760 | + retval = nval_get(x_buffer, x_size, name, value, size); |
| 14761 | + else |
| 14762 | + retval = nval_list(x_buffer, x_size, value,size); |
| 14763 | + } |
| 14764 | + yaffs_release_temp_buffer(dev,(__u8 *)buffer,__LINE__); |
| 14765 | + return retval; |
| 14766 | +} |
| 14767 | + |
| 14768 | +int yaffs_set_xattrib(yaffs_obj_t *obj, const YCHAR *name, const void * value, int size, int flags) |
| 14769 | +{ |
| 14770 | + return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags); |
| 14771 | +} |
| 14772 | + |
| 14773 | +int yaffs_remove_xattrib(yaffs_obj_t *obj, const YCHAR *name) |
| 14774 | +{ |
| 14775 | + return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0); |
| 14776 | +} |
| 14777 | + |
| 14778 | +int yaffs_get_xattrib(yaffs_obj_t *obj, const YCHAR *name, void *value, int size) |
| 14779 | +{ |
| 14780 | + return yaffs_do_xattrib_fetch(obj, name, value, size); |
| 14781 | +} |
| 14782 | + |
| 14783 | +int yaffs_list_xattrib(yaffs_obj_t *obj, char *buffer, int size) |
| 14784 | +{ |
| 14785 | + return yaffs_do_xattrib_fetch(obj, NULL, buffer,size); |
| 14786 | +} |
| 14787 | + |
| 14788 | + |
| 14789 | + |
| 14790 | #if 0 |
| 14791 | -int yaffs_DumpObject(yaffs_Object *obj) |
| 14792 | +int yaffs_dump_obj(yaffs_obj_t *obj) |
| 14793 | { |
| 14794 | YCHAR name[257]; |
| 14795 | |
| 14796 | - yaffs_GetObjectName(obj, name, 256); |
| 14797 | + yaffs_get_obj_name(obj, name, YAFFS_MAX_NAME_LENGTH + 1); |
| 14798 | |
| 14799 | T(YAFFS_TRACE_ALWAYS, |
| 14800 | (TSTR |
| 14801 | ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d" |
| 14802 | " chunk %d type %d size %d\n" |
| 14803 | - TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name, |
| 14804 | - obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk, |
| 14805 | - yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj))); |
| 14806 | + TENDSTR), obj->obj_id, yaffs_get_obj_inode(obj), name, |
| 14807 | + obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdr_chunk, |
| 14808 | + yaffs_get_obj_type(obj), yaffs_get_obj_length(obj))); |
| 14809 | |
| 14810 | return YAFFS_OK; |
| 14811 | } |
| 14812 | @@ -7046,72 +5052,74 @@ int yaffs_DumpObject(yaffs_Object *obj) |
| 14813 | |
| 14814 | /*---------------------------- Initialisation code -------------------------------------- */ |
| 14815 | |
| 14816 | -static int yaffs_CheckDevFunctions(const yaffs_Device *dev) |
| 14817 | +static int yaffs_cehck_dev_fns(const yaffs_dev_t *dev) |
| 14818 | { |
| 14819 | |
| 14820 | /* Common functions, gotta have */ |
| 14821 | - if (!dev->eraseBlockInNAND || !dev->initialiseNAND) |
| 14822 | + if (!dev->param.erase_fn || !dev->param.initialise_flash_fn) |
| 14823 | return 0; |
| 14824 | |
| 14825 | #ifdef CONFIG_YAFFS_YAFFS2 |
| 14826 | |
| 14827 | /* Can use the "with tags" style interface for yaffs1 or yaffs2 */ |
| 14828 | - if (dev->writeChunkWithTagsToNAND && |
| 14829 | - dev->readChunkWithTagsFromNAND && |
| 14830 | - !dev->writeChunkToNAND && |
| 14831 | - !dev->readChunkFromNAND && |
| 14832 | - dev->markNANDBlockBad && dev->queryNANDBlock) |
| 14833 | + if (dev->param.write_chunk_tags_fn && |
| 14834 | + dev->param.read_chunk_tags_fn && |
| 14835 | + !dev->param.write_chunk_fn && |
| 14836 | + !dev->param.read_chunk_fn && |
| 14837 | + dev->param.bad_block_fn && |
| 14838 | + dev->param.query_block_fn) |
| 14839 | return 1; |
| 14840 | #endif |
| 14841 | |
| 14842 | /* Can use the "spare" style interface for yaffs1 */ |
| 14843 | - if (!dev->isYaffs2 && |
| 14844 | - !dev->writeChunkWithTagsToNAND && |
| 14845 | - !dev->readChunkWithTagsFromNAND && |
| 14846 | - dev->writeChunkToNAND && |
| 14847 | - dev->readChunkFromNAND && |
| 14848 | - !dev->markNANDBlockBad && !dev->queryNANDBlock) |
| 14849 | + if (!dev->param.is_yaffs2 && |
| 14850 | + !dev->param.write_chunk_tags_fn && |
| 14851 | + !dev->param.read_chunk_tags_fn && |
| 14852 | + dev->param.write_chunk_fn && |
| 14853 | + dev->param.read_chunk_fn && |
| 14854 | + !dev->param.bad_block_fn && |
| 14855 | + !dev->param.query_block_fn) |
| 14856 | return 1; |
| 14857 | |
| 14858 | - return 0; /* bad */ |
| 14859 | + return 0; /* bad */ |
| 14860 | } |
| 14861 | |
| 14862 | |
| 14863 | -static int yaffs_CreateInitialDirectories(yaffs_Device *dev) |
| 14864 | +static int yaffs_create_initial_dir(yaffs_dev_t *dev) |
| 14865 | { |
| 14866 | /* Initialise the unlinked, deleted, root and lost and found directories */ |
| 14867 | |
| 14868 | - dev->lostNFoundDir = dev->rootDir = NULL; |
| 14869 | - dev->unlinkedDir = dev->deletedDir = NULL; |
| 14870 | + dev->lost_n_found = dev->root_dir = NULL; |
| 14871 | + dev->unlinked_dir = dev->del_dir = NULL; |
| 14872 | |
| 14873 | - dev->unlinkedDir = |
| 14874 | - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); |
| 14875 | + dev->unlinked_dir = |
| 14876 | + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); |
| 14877 | |
| 14878 | - dev->deletedDir = |
| 14879 | - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); |
| 14880 | + dev->del_dir = |
| 14881 | + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); |
| 14882 | |
| 14883 | - dev->rootDir = |
| 14884 | - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT, |
| 14885 | + dev->root_dir = |
| 14886 | + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT, |
| 14887 | YAFFS_ROOT_MODE | S_IFDIR); |
| 14888 | - dev->lostNFoundDir = |
| 14889 | - yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND, |
| 14890 | + dev->lost_n_found = |
| 14891 | + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND, |
| 14892 | YAFFS_LOSTNFOUND_MODE | S_IFDIR); |
| 14893 | |
| 14894 | - if (dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir) { |
| 14895 | - yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); |
| 14896 | + if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir && dev->del_dir) { |
| 14897 | + yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found); |
| 14898 | return YAFFS_OK; |
| 14899 | } |
| 14900 | |
| 14901 | return YAFFS_FAIL; |
| 14902 | } |
| 14903 | |
| 14904 | -int yaffs_GutsInitialise(yaffs_Device *dev) |
| 14905 | +int yaffs_guts_initialise(yaffs_dev_t *dev) |
| 14906 | { |
| 14907 | int init_failed = 0; |
| 14908 | unsigned x; |
| 14909 | int bits; |
| 14910 | |
| 14911 | - T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR))); |
| 14912 | + T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_guts_initialise()" TENDSTR))); |
| 14913 | |
| 14914 | /* Check stuff that must be set */ |
| 14915 | |
| 14916 | @@ -7120,52 +5128,52 @@ int yaffs_GutsInitialise(yaffs_Device *d |
| 14917 | return YAFFS_FAIL; |
| 14918 | } |
| 14919 | |
| 14920 | - dev->internalStartBlock = dev->startBlock; |
| 14921 | - dev->internalEndBlock = dev->endBlock; |
| 14922 | - dev->blockOffset = 0; |
| 14923 | - dev->chunkOffset = 0; |
| 14924 | - dev->nFreeChunks = 0; |
| 14925 | - |
| 14926 | - dev->gcBlock = -1; |
| 14927 | - |
| 14928 | - if (dev->startBlock == 0) { |
| 14929 | - dev->internalStartBlock = dev->startBlock + 1; |
| 14930 | - dev->internalEndBlock = dev->endBlock + 1; |
| 14931 | - dev->blockOffset = 1; |
| 14932 | - dev->chunkOffset = dev->nChunksPerBlock; |
| 14933 | + dev->internal_start_block = dev->param.start_block; |
| 14934 | + dev->internal_end_block = dev->param.end_block; |
| 14935 | + dev->block_offset = 0; |
| 14936 | + dev->chunk_offset = 0; |
| 14937 | + dev->n_free_chunks = 0; |
| 14938 | + |
| 14939 | + dev->gc_block = 0; |
| 14940 | + |
| 14941 | + if (dev->param.start_block == 0) { |
| 14942 | + dev->internal_start_block = dev->param.start_block + 1; |
| 14943 | + dev->internal_end_block = dev->param.end_block + 1; |
| 14944 | + dev->block_offset = 1; |
| 14945 | + dev->chunk_offset = dev->param.chunks_per_block; |
| 14946 | } |
| 14947 | |
| 14948 | /* Check geometry parameters. */ |
| 14949 | |
| 14950 | - if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) || |
| 14951 | - (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) || |
| 14952 | - (dev->inbandTags && !dev->isYaffs2) || |
| 14953 | - dev->nChunksPerBlock < 2 || |
| 14954 | - dev->nReservedBlocks < 2 || |
| 14955 | - dev->internalStartBlock <= 0 || |
| 14956 | - dev->internalEndBlock <= 0 || |
| 14957 | - dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) { /* otherwise it is too small */ |
| 14958 | + if ((!dev->param.inband_tags && dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 1024) || |
| 14959 | + (!dev->param.is_yaffs2 && dev->param.total_bytes_per_chunk < 512) || |
| 14960 | + (dev->param.inband_tags && !dev->param.is_yaffs2) || |
| 14961 | + dev->param.chunks_per_block < 2 || |
| 14962 | + dev->param.n_reserved_blocks < 2 || |
| 14963 | + dev->internal_start_block <= 0 || |
| 14964 | + dev->internal_end_block <= 0 || |
| 14965 | + dev->internal_end_block <= (dev->internal_start_block + dev->param.n_reserved_blocks + 2)) { /* otherwise it is too small */ |
| 14966 | T(YAFFS_TRACE_ALWAYS, |
| 14967 | (TSTR |
| 14968 | - ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d " |
| 14969 | - TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags)); |
| 14970 | + ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d " |
| 14971 | + TENDSTR), dev->param.total_bytes_per_chunk, dev->param.is_yaffs2 ? "2" : "", dev->param.inband_tags)); |
| 14972 | return YAFFS_FAIL; |
| 14973 | } |
| 14974 | |
| 14975 | - if (yaffs_InitialiseNAND(dev) != YAFFS_OK) { |
| 14976 | + if (yaffs_init_nand(dev) != YAFFS_OK) { |
| 14977 | T(YAFFS_TRACE_ALWAYS, |
| 14978 | (TSTR("yaffs: InitialiseNAND failed" TENDSTR))); |
| 14979 | return YAFFS_FAIL; |
| 14980 | } |
| 14981 | |
| 14982 | /* Sort out space for inband tags, if required */ |
| 14983 | - if (dev->inbandTags) |
| 14984 | - dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart); |
| 14985 | + if (dev->param.inband_tags) |
| 14986 | + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk - sizeof(yaffs_PackedTags2TagsPart); |
| 14987 | else |
| 14988 | - dev->nDataBytesPerChunk = dev->totalBytesPerChunk; |
| 14989 | + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk; |
| 14990 | |
| 14991 | /* Got the right mix of functions? */ |
| 14992 | - if (!yaffs_CheckDevFunctions(dev)) { |
| 14993 | + if (!yaffs_cehck_dev_fns(dev)) { |
| 14994 | /* Function missing */ |
| 14995 | T(YAFFS_TRACE_ALWAYS, |
| 14996 | (TSTR |
| 14997 | @@ -7175,13 +5183,13 @@ int yaffs_GutsInitialise(yaffs_Device *d |
| 14998 | } |
| 14999 | |
| 15000 | /* This is really a compilation check. */ |
| 15001 | - if (!yaffs_CheckStructures()) { |
| 15002 | + if (!yaffs_check_structures()) { |
| 15003 | T(YAFFS_TRACE_ALWAYS, |
| 15004 | - (TSTR("yaffs_CheckStructures failed\n" TENDSTR))); |
| 15005 | + (TSTR("yaffs_check_structures failed\n" TENDSTR))); |
| 15006 | return YAFFS_FAIL; |
| 15007 | } |
| 15008 | |
| 15009 | - if (dev->isMounted) { |
| 15010 | + if (dev->is_mounted) { |
| 15011 | T(YAFFS_TRACE_ALWAYS, |
| 15012 | (TSTR("yaffs: device already mounted\n" TENDSTR))); |
| 15013 | return YAFFS_FAIL; |
| 15014 | @@ -7189,59 +5197,62 @@ int yaffs_GutsInitialise(yaffs_Device *d |
| 15015 | |
| 15016 | /* Finished with most checks. One or two more checks happen later on too. */ |
| 15017 | |
| 15018 | - dev->isMounted = 1; |
| 15019 | + dev->is_mounted = 1; |
| 15020 | |
| 15021 | /* OK now calculate a few things for the device */ |
| 15022 | |
| 15023 | /* |
| 15024 | * Calculate all the chunk size manipulation numbers: |
| 15025 | */ |
| 15026 | - x = dev->nDataBytesPerChunk; |
| 15027 | - /* We always use dev->chunkShift and dev->chunkDiv */ |
| 15028 | - dev->chunkShift = Shifts(x); |
| 15029 | - x >>= dev->chunkShift; |
| 15030 | - dev->chunkDiv = x; |
| 15031 | - /* We only use chunk mask if chunkDiv is 1 */ |
| 15032 | - dev->chunkMask = (1<<dev->chunkShift) - 1; |
| 15033 | + x = dev->data_bytes_per_chunk; |
| 15034 | + /* We always use dev->chunk_shift and dev->chunk_div */ |
| 15035 | + dev->chunk_shift = Shifts(x); |
| 15036 | + x >>= dev->chunk_shift; |
| 15037 | + dev->chunk_div = x; |
| 15038 | + /* We only use chunk mask if chunk_div is 1 */ |
| 15039 | + dev->chunk_mask = (1<<dev->chunk_shift) - 1; |
| 15040 | |
| 15041 | /* |
| 15042 | - * Calculate chunkGroupBits. |
| 15043 | - * We need to find the next power of 2 > than internalEndBlock |
| 15044 | + * Calculate chunk_grp_bits. |
| 15045 | + * We need to find the next power of 2 > than internal_end_block |
| 15046 | */ |
| 15047 | |
| 15048 | - x = dev->nChunksPerBlock * (dev->internalEndBlock + 1); |
| 15049 | + x = dev->param.chunks_per_block * (dev->internal_end_block + 1); |
| 15050 | |
| 15051 | bits = ShiftsGE(x); |
| 15052 | |
| 15053 | /* Set up tnode width if wide tnodes are enabled. */ |
| 15054 | - if (!dev->wideTnodesDisabled) { |
| 15055 | + if (!dev->param.wide_tnodes_disabled) { |
| 15056 | /* bits must be even so that we end up with 32-bit words */ |
| 15057 | if (bits & 1) |
| 15058 | bits++; |
| 15059 | if (bits < 16) |
| 15060 | - dev->tnodeWidth = 16; |
| 15061 | + dev->tnode_width = 16; |
| 15062 | else |
| 15063 | - dev->tnodeWidth = bits; |
| 15064 | + dev->tnode_width = bits; |
| 15065 | } else |
| 15066 | - dev->tnodeWidth = 16; |
| 15067 | + dev->tnode_width = 16; |
| 15068 | |
| 15069 | - dev->tnodeMask = (1<<dev->tnodeWidth)-1; |
| 15070 | + dev->tnode_mask = (1<<dev->tnode_width)-1; |
| 15071 | |
| 15072 | /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), |
| 15073 | * so if the bitwidth of the |
| 15074 | * chunk range we're using is greater than 16 we need |
| 15075 | - * to figure out chunk shift and chunkGroupSize |
| 15076 | + * to figure out chunk shift and chunk_grp_size |
| 15077 | */ |
| 15078 | |
| 15079 | - if (bits <= dev->tnodeWidth) |
| 15080 | - dev->chunkGroupBits = 0; |
| 15081 | + if (bits <= dev->tnode_width) |
| 15082 | + dev->chunk_grp_bits = 0; |
| 15083 | else |
| 15084 | - dev->chunkGroupBits = bits - dev->tnodeWidth; |
| 15085 | + dev->chunk_grp_bits = bits - dev->tnode_width; |
| 15086 | |
| 15087 | + dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0)/8; |
| 15088 | + if(dev->tnode_size < sizeof(yaffs_tnode_t)) |
| 15089 | + dev->tnode_size = sizeof(yaffs_tnode_t); |
| 15090 | |
| 15091 | - dev->chunkGroupSize = 1 << dev->chunkGroupBits; |
| 15092 | + dev->chunk_grp_size = 1 << dev->chunk_grp_bits; |
| 15093 | |
| 15094 | - if (dev->nChunksPerBlock < dev->chunkGroupSize) { |
| 15095 | + if (dev->param.chunks_per_block < dev->chunk_grp_size) { |
| 15096 | /* We have a problem because the soft delete won't work if |
| 15097 | * the chunk group size > chunks per block. |
| 15098 | * This can be remedied by using larger "virtual blocks". |
| 15099 | @@ -7255,85 +5266,89 @@ int yaffs_GutsInitialise(yaffs_Device *d |
| 15100 | /* OK, we've finished verifying the device, lets continue with initialisation */ |
| 15101 | |
| 15102 | /* More device initialisation */ |
| 15103 | - dev->garbageCollections = 0; |
| 15104 | - dev->passiveGarbageCollections = 0; |
| 15105 | - dev->currentDirtyChecker = 0; |
| 15106 | - dev->bufferedBlock = -1; |
| 15107 | - dev->doingBufferedBlockRewrite = 0; |
| 15108 | - dev->nDeletedFiles = 0; |
| 15109 | - dev->nBackgroundDeletions = 0; |
| 15110 | - dev->nUnlinkedFiles = 0; |
| 15111 | - dev->eccFixed = 0; |
| 15112 | - dev->eccUnfixed = 0; |
| 15113 | - dev->tagsEccFixed = 0; |
| 15114 | - dev->tagsEccUnfixed = 0; |
| 15115 | - dev->nErasureFailures = 0; |
| 15116 | - dev->nErasedBlocks = 0; |
| 15117 | - dev->isDoingGC = 0; |
| 15118 | - dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */ |
| 15119 | + dev->all_gcs = 0; |
| 15120 | + dev->passive_gc_count = 0; |
| 15121 | + dev->oldest_dirty_gc_count = 0; |
| 15122 | + dev->bg_gcs = 0; |
| 15123 | + dev->gc_block_finder = 0; |
| 15124 | + dev->buffered_block = -1; |
| 15125 | + dev->doing_buffered_block_rewrite = 0; |
| 15126 | + dev->n_deleted_files = 0; |
| 15127 | + dev->n_bg_deletions = 0; |
| 15128 | + dev->n_unlinked_files = 0; |
| 15129 | + dev->n_ecc_fixed = 0; |
| 15130 | + dev->n_ecc_unfixed = 0; |
| 15131 | + dev->n_tags_ecc_fixed = 0; |
| 15132 | + dev->n_tags_ecc_unfixed = 0; |
| 15133 | + dev->n_erase_failures = 0; |
| 15134 | + dev->n_erased_blocks = 0; |
| 15135 | + dev->gc_disable= 0; |
| 15136 | + dev->has_pending_prioritised_gc = 1; /* Assume the worst for now, will get fixed on first GC */ |
| 15137 | + YINIT_LIST_HEAD(&dev->dirty_dirs); |
| 15138 | + dev->oldest_dirty_seq = 0; |
| 15139 | + dev->oldest_dirty_block = 0; |
| 15140 | |
| 15141 | /* Initialise temporary buffers and caches. */ |
| 15142 | - if (!yaffs_InitialiseTempBuffers(dev)) |
| 15143 | + if (!yaffs_init_tmp_buffers(dev)) |
| 15144 | init_failed = 1; |
| 15145 | |
| 15146 | - dev->srCache = NULL; |
| 15147 | - dev->gcCleanupList = NULL; |
| 15148 | + dev->cache = NULL; |
| 15149 | + dev->gc_cleanup_list = NULL; |
| 15150 | |
| 15151 | |
| 15152 | if (!init_failed && |
| 15153 | - dev->nShortOpCaches > 0) { |
| 15154 | + dev->param.n_caches > 0) { |
| 15155 | int i; |
| 15156 | void *buf; |
| 15157 | - int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache); |
| 15158 | + int cacheBytes = dev->param.n_caches * sizeof(yaffs_cache_t); |
| 15159 | |
| 15160 | - if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) |
| 15161 | - dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; |
| 15162 | + if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES) |
| 15163 | + dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES; |
| 15164 | |
| 15165 | - dev->srCache = YMALLOC(srCacheBytes); |
| 15166 | + dev->cache = YMALLOC(cacheBytes); |
| 15167 | |
| 15168 | - buf = (__u8 *) dev->srCache; |
| 15169 | + buf = (__u8 *) dev->cache; |
| 15170 | |
| 15171 | - if (dev->srCache) |
| 15172 | - memset(dev->srCache, 0, srCacheBytes); |
| 15173 | + if (dev->cache) |
| 15174 | + memset(dev->cache, 0, cacheBytes); |
| 15175 | |
| 15176 | - for (i = 0; i < dev->nShortOpCaches && buf; i++) { |
| 15177 | - dev->srCache[i].object = NULL; |
| 15178 | - dev->srCache[i].lastUse = 0; |
| 15179 | - dev->srCache[i].dirty = 0; |
| 15180 | - dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk); |
| 15181 | + for (i = 0; i < dev->param.n_caches && buf; i++) { |
| 15182 | + dev->cache[i].object = NULL; |
| 15183 | + dev->cache[i].last_use = 0; |
| 15184 | + dev->cache[i].dirty = 0; |
| 15185 | + dev->cache[i].data = buf = YMALLOC_DMA(dev->param.total_bytes_per_chunk); |
| 15186 | } |
| 15187 | if (!buf) |
| 15188 | init_failed = 1; |
| 15189 | |
| 15190 | - dev->srLastUse = 0; |
| 15191 | + dev->cache_last_use = 0; |
| 15192 | } |
| 15193 | |
| 15194 | - dev->cacheHits = 0; |
| 15195 | + dev->cache_hits = 0; |
| 15196 | |
| 15197 | if (!init_failed) { |
| 15198 | - dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); |
| 15199 | - if (!dev->gcCleanupList) |
| 15200 | + dev->gc_cleanup_list = YMALLOC(dev->param.chunks_per_block * sizeof(__u32)); |
| 15201 | + if (!dev->gc_cleanup_list) |
| 15202 | init_failed = 1; |
| 15203 | } |
| 15204 | |
| 15205 | - if (dev->isYaffs2) |
| 15206 | - dev->useHeaderFileSize = 1; |
| 15207 | + if (dev->param.is_yaffs2) |
| 15208 | + dev->param.use_header_file_size = 1; |
| 15209 | |
| 15210 | - if (!init_failed && !yaffs_InitialiseBlocks(dev)) |
| 15211 | + if (!init_failed && !yaffs_init_blocks(dev)) |
| 15212 | init_failed = 1; |
| 15213 | |
| 15214 | - yaffs_InitialiseTnodes(dev); |
| 15215 | - yaffs_InitialiseObjects(dev); |
| 15216 | + yaffs_init_tnodes_and_objs(dev); |
| 15217 | |
| 15218 | - if (!init_failed && !yaffs_CreateInitialDirectories(dev)) |
| 15219 | + if (!init_failed && !yaffs_create_initial_dir(dev)) |
| 15220 | init_failed = 1; |
| 15221 | |
| 15222 | |
| 15223 | if (!init_failed) { |
| 15224 | /* Now scan the flash. */ |
| 15225 | - if (dev->isYaffs2) { |
| 15226 | - if (yaffs_CheckpointRestore(dev)) { |
| 15227 | - yaffs_CheckObjectDetailsLoaded(dev->rootDir); |
| 15228 | + if (dev->param.is_yaffs2) { |
| 15229 | + if (yaffs2_checkpt_restore(dev)) { |
| 15230 | + yaffs_check_obj_details_loaded(dev->root_dir); |
| 15231 | T(YAFFS_TRACE_ALWAYS, |
| 15232 | (TSTR("yaffs: restored from checkpoint" TENDSTR))); |
| 15233 | } else { |
| 15234 | @@ -7341,128 +5356,129 @@ int yaffs_GutsInitialise(yaffs_Device *d |
| 15235 | /* Clean up the mess caused by an aborted checkpoint load |
| 15236 | * and scan backwards. |
| 15237 | */ |
| 15238 | - yaffs_DeinitialiseBlocks(dev); |
| 15239 | - yaffs_DeinitialiseTnodes(dev); |
| 15240 | - yaffs_DeinitialiseObjects(dev); |
| 15241 | + yaffs_deinit_blocks(dev); |
| 15242 | |
| 15243 | + yaffs_deinit_tnodes_and_objs(dev); |
| 15244 | |
| 15245 | - dev->nErasedBlocks = 0; |
| 15246 | - dev->nFreeChunks = 0; |
| 15247 | - dev->allocationBlock = -1; |
| 15248 | - dev->allocationPage = -1; |
| 15249 | - dev->nDeletedFiles = 0; |
| 15250 | - dev->nUnlinkedFiles = 0; |
| 15251 | - dev->nBackgroundDeletions = 0; |
| 15252 | - dev->oldestDirtySequence = 0; |
| 15253 | + dev->n_erased_blocks = 0; |
| 15254 | + dev->n_free_chunks = 0; |
| 15255 | + dev->alloc_block = -1; |
| 15256 | + dev->alloc_page = -1; |
| 15257 | + dev->n_deleted_files = 0; |
| 15258 | + dev->n_unlinked_files = 0; |
| 15259 | + dev->n_bg_deletions = 0; |
| 15260 | |
| 15261 | - if (!init_failed && !yaffs_InitialiseBlocks(dev)) |
| 15262 | + if (!init_failed && !yaffs_init_blocks(dev)) |
| 15263 | init_failed = 1; |
| 15264 | |
| 15265 | - yaffs_InitialiseTnodes(dev); |
| 15266 | - yaffs_InitialiseObjects(dev); |
| 15267 | + yaffs_init_tnodes_and_objs(dev); |
| 15268 | |
| 15269 | - if (!init_failed && !yaffs_CreateInitialDirectories(dev)) |
| 15270 | + if (!init_failed && !yaffs_create_initial_dir(dev)) |
| 15271 | init_failed = 1; |
| 15272 | |
| 15273 | - if (!init_failed && !yaffs_ScanBackwards(dev)) |
| 15274 | + if (!init_failed && !yaffs2_scan_backwards(dev)) |
| 15275 | init_failed = 1; |
| 15276 | } |
| 15277 | - } else if (!yaffs_Scan(dev)) |
| 15278 | + } else if (!yaffs1_scan(dev)) |
| 15279 | init_failed = 1; |
| 15280 | |
| 15281 | - yaffs_StripDeletedObjects(dev); |
| 15282 | + yaffs_strip_deleted_objs(dev); |
| 15283 | + yaffs_fix_hanging_objs(dev); |
| 15284 | + if(dev->param.empty_lost_n_found) |
| 15285 | + yaffs_empty_l_n_f(dev); |
| 15286 | } |
| 15287 | |
| 15288 | if (init_failed) { |
| 15289 | /* Clean up the mess */ |
| 15290 | T(YAFFS_TRACE_TRACING, |
| 15291 | - (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR))); |
| 15292 | + (TSTR("yaffs: yaffs_guts_initialise() aborted.\n" TENDSTR))); |
| 15293 | |
| 15294 | - yaffs_Deinitialise(dev); |
| 15295 | + yaffs_deinitialise(dev); |
| 15296 | return YAFFS_FAIL; |
| 15297 | } |
| 15298 | |
| 15299 | /* Zero out stats */ |
| 15300 | - dev->nPageReads = 0; |
| 15301 | - dev->nPageWrites = 0; |
| 15302 | - dev->nBlockErasures = 0; |
| 15303 | - dev->nGCCopies = 0; |
| 15304 | - dev->nRetriedWrites = 0; |
| 15305 | - |
| 15306 | - dev->nRetiredBlocks = 0; |
| 15307 | - |
| 15308 | - yaffs_VerifyFreeChunks(dev); |
| 15309 | - yaffs_VerifyBlocks(dev); |
| 15310 | - |
| 15311 | + dev->n_page_reads = 0; |
| 15312 | + dev->n_page_writes = 0; |
| 15313 | + dev->n_erasures = 0; |
| 15314 | + dev->n_gc_copies = 0; |
| 15315 | + dev->n_retired_writes = 0; |
| 15316 | + |
| 15317 | + dev->n_retired_blocks = 0; |
| 15318 | + |
| 15319 | + yaffs_verify_free_chunks(dev); |
| 15320 | + yaffs_verify_blocks(dev); |
| 15321 | + |
| 15322 | + /* Clean up any aborted checkpoint data */ |
| 15323 | + if(!dev->is_checkpointed && dev->blocks_in_checkpt > 0) |
| 15324 | + yaffs2_checkpt_invalidate(dev); |
| 15325 | |
| 15326 | T(YAFFS_TRACE_TRACING, |
| 15327 | - (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); |
| 15328 | + (TSTR("yaffs: yaffs_guts_initialise() done.\n" TENDSTR))); |
| 15329 | return YAFFS_OK; |
| 15330 | |
| 15331 | } |
| 15332 | |
| 15333 | -void yaffs_Deinitialise(yaffs_Device *dev) |
| 15334 | +void yaffs_deinitialise(yaffs_dev_t *dev) |
| 15335 | { |
| 15336 | - if (dev->isMounted) { |
| 15337 | + if (dev->is_mounted) { |
| 15338 | int i; |
| 15339 | |
| 15340 | - yaffs_DeinitialiseBlocks(dev); |
| 15341 | - yaffs_DeinitialiseTnodes(dev); |
| 15342 | - yaffs_DeinitialiseObjects(dev); |
| 15343 | - if (dev->nShortOpCaches > 0 && |
| 15344 | - dev->srCache) { |
| 15345 | + yaffs_deinit_blocks(dev); |
| 15346 | + yaffs_deinit_tnodes_and_objs(dev); |
| 15347 | + if (dev->param.n_caches > 0 && |
| 15348 | + dev->cache) { |
| 15349 | |
| 15350 | - for (i = 0; i < dev->nShortOpCaches; i++) { |
| 15351 | - if (dev->srCache[i].data) |
| 15352 | - YFREE(dev->srCache[i].data); |
| 15353 | - dev->srCache[i].data = NULL; |
| 15354 | + for (i = 0; i < dev->param.n_caches; i++) { |
| 15355 | + if (dev->cache[i].data) |
| 15356 | + YFREE(dev->cache[i].data); |
| 15357 | + dev->cache[i].data = NULL; |
| 15358 | } |
| 15359 | |
| 15360 | - YFREE(dev->srCache); |
| 15361 | - dev->srCache = NULL; |
| 15362 | + YFREE(dev->cache); |
| 15363 | + dev->cache = NULL; |
| 15364 | } |
| 15365 | |
| 15366 | - YFREE(dev->gcCleanupList); |
| 15367 | + YFREE(dev->gc_cleanup_list); |
| 15368 | |
| 15369 | for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) |
| 15370 | - YFREE(dev->tempBuffer[i].buffer); |
| 15371 | + YFREE(dev->temp_buffer[i].buffer); |
| 15372 | |
| 15373 | - dev->isMounted = 0; |
| 15374 | + dev->is_mounted = 0; |
| 15375 | |
| 15376 | - if (dev->deinitialiseNAND) |
| 15377 | - dev->deinitialiseNAND(dev); |
| 15378 | + if (dev->param.deinitialise_flash_fn) |
| 15379 | + dev->param.deinitialise_flash_fn(dev); |
| 15380 | } |
| 15381 | } |
| 15382 | |
| 15383 | -static int yaffs_CountFreeChunks(yaffs_Device *dev) |
| 15384 | +int yaffs_count_free_chunks(yaffs_dev_t *dev) |
| 15385 | { |
| 15386 | - int nFree; |
| 15387 | + int nFree=0; |
| 15388 | int b; |
| 15389 | |
| 15390 | - yaffs_BlockInfo *blk; |
| 15391 | - |
| 15392 | - for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; |
| 15393 | - b++) { |
| 15394 | - blk = yaffs_GetBlockInfo(dev, b); |
| 15395 | + yaffs_block_info_t *blk; |
| 15396 | |
| 15397 | - switch (blk->blockState) { |
| 15398 | + blk = dev->block_info; |
| 15399 | + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { |
| 15400 | + switch (blk->block_state) { |
| 15401 | case YAFFS_BLOCK_STATE_EMPTY: |
| 15402 | case YAFFS_BLOCK_STATE_ALLOCATING: |
| 15403 | case YAFFS_BLOCK_STATE_COLLECTING: |
| 15404 | case YAFFS_BLOCK_STATE_FULL: |
| 15405 | nFree += |
| 15406 | - (dev->nChunksPerBlock - blk->pagesInUse + |
| 15407 | - blk->softDeletions); |
| 15408 | + (dev->param.chunks_per_block - blk->pages_in_use + |
| 15409 | + blk->soft_del_pages); |
| 15410 | break; |
| 15411 | default: |
| 15412 | break; |
| 15413 | } |
| 15414 | + blk++; |
| 15415 | } |
| 15416 | |
| 15417 | return nFree; |
| 15418 | } |
| 15419 | |
| 15420 | -int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) |
| 15421 | +int yaffs_get_n_free_chunks(yaffs_dev_t *dev) |
| 15422 | { |
| 15423 | /* This is what we report to the outside world */ |
| 15424 | |
| 15425 | @@ -7472,30 +5488,28 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De |
| 15426 | int i; |
| 15427 | |
| 15428 | #if 1 |
| 15429 | - nFree = dev->nFreeChunks; |
| 15430 | + nFree = dev->n_free_chunks; |
| 15431 | #else |
| 15432 | - nFree = yaffs_CountFreeChunks(dev); |
| 15433 | + nFree = yaffs_count_free_chunks(dev); |
| 15434 | #endif |
| 15435 | |
| 15436 | - nFree += dev->nDeletedFiles; |
| 15437 | + nFree += dev->n_deleted_files; |
| 15438 | |
| 15439 | /* Now count the number of dirty chunks in the cache and subtract those */ |
| 15440 | |
| 15441 | - for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) { |
| 15442 | - if (dev->srCache[i].dirty) |
| 15443 | + for (nDirtyCacheChunks = 0, i = 0; i < dev->param.n_caches; i++) { |
| 15444 | + if (dev->cache[i].dirty) |
| 15445 | nDirtyCacheChunks++; |
| 15446 | } |
| 15447 | |
| 15448 | nFree -= nDirtyCacheChunks; |
| 15449 | |
| 15450 | - nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); |
| 15451 | + nFree -= ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block); |
| 15452 | |
| 15453 | /* Now we figure out how much to reserve for the checkpoint and report that... */ |
| 15454 | - blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint; |
| 15455 | - if (blocksForCheckpoint < 0) |
| 15456 | - blocksForCheckpoint = 0; |
| 15457 | + blocksForCheckpoint = yaffs_calc_checkpt_blocks_required(dev); |
| 15458 | |
| 15459 | - nFree -= (blocksForCheckpoint * dev->nChunksPerBlock); |
| 15460 | + nFree -= (blocksForCheckpoint * dev->param.chunks_per_block); |
| 15461 | |
| 15462 | if (nFree < 0) |
| 15463 | nFree = 0; |
| 15464 | @@ -7504,49 +5518,27 @@ int yaffs_GetNumberOfFreeChunks(yaffs_De |
| 15465 | |
| 15466 | } |
| 15467 | |
| 15468 | -static int yaffs_freeVerificationFailures; |
| 15469 | - |
| 15470 | -static void yaffs_VerifyFreeChunks(yaffs_Device *dev) |
| 15471 | -{ |
| 15472 | - int counted; |
| 15473 | - int difference; |
| 15474 | - |
| 15475 | - if (yaffs_SkipVerification(dev)) |
| 15476 | - return; |
| 15477 | - |
| 15478 | - counted = yaffs_CountFreeChunks(dev); |
| 15479 | - |
| 15480 | - difference = dev->nFreeChunks - counted; |
| 15481 | - |
| 15482 | - if (difference) { |
| 15483 | - T(YAFFS_TRACE_ALWAYS, |
| 15484 | - (TSTR("Freechunks verification failure %d %d %d" TENDSTR), |
| 15485 | - dev->nFreeChunks, counted, difference)); |
| 15486 | - yaffs_freeVerificationFailures++; |
| 15487 | - } |
| 15488 | -} |
| 15489 | |
| 15490 | /*---------------------------------------- YAFFS test code ----------------------*/ |
| 15491 | |
| 15492 | -#define yaffs_CheckStruct(structure, syze, name) \ |
| 15493 | +#define yaffs_check_struct(structure, syze, name) \ |
| 15494 | do { \ |
| 15495 | if (sizeof(structure) != syze) { \ |
| 15496 | T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\ |
| 15497 | - name, syze, sizeof(structure))); \ |
| 15498 | + name, syze, (int) sizeof(structure))); \ |
| 15499 | return YAFFS_FAIL; \ |
| 15500 | } \ |
| 15501 | } while (0) |
| 15502 | |
| 15503 | -static int yaffs_CheckStructures(void) |
| 15504 | +static int yaffs_check_structures(void) |
| 15505 | { |
| 15506 | -/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */ |
| 15507 | -/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */ |
| 15508 | -/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */ |
| 15509 | -#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG |
| 15510 | - yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); |
| 15511 | -#endif |
| 15512 | +/* yaffs_check_struct(yaffs_tags_t,8,"yaffs_tags_t"); */ |
| 15513 | +/* yaffs_check_struct(yaffs_tags_union_t,8,"yaffs_tags_union_t"); */ |
| 15514 | +/* yaffs_check_struct(yaffs_spare,16,"yaffs_spare"); */ |
| 15515 | +/* yaffs_check_struct(yaffs_tnode_t, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_tnode_t"); */ |
| 15516 | + |
| 15517 | #ifndef CONFIG_YAFFS_WINCE |
| 15518 | - yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader"); |
| 15519 | + yaffs_check_struct(yaffs_obj_header, 512, "yaffs_obj_header"); |
| 15520 | #endif |
| 15521 | return YAFFS_OK; |
| 15522 | } |
| 15523 | --- a/fs/yaffs2/yaffs_guts.h |
| 15524 | +++ b/fs/yaffs2/yaffs_guts.h |
| 15525 | @@ -1,7 +1,7 @@ |
| 15526 | /* |
| 15527 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 15528 | * |
| 15529 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 15530 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 15531 | * for Toby Churchill Ltd and Brightstar Engineering |
| 15532 | * |
| 15533 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 15534 | @@ -16,8 +16,9 @@ |
| 15535 | #ifndef __YAFFS_GUTS_H__ |
| 15536 | #define __YAFFS_GUTS_H__ |
| 15537 | |
| 15538 | -#include "devextras.h" |
| 15539 | #include "yportenv.h" |
| 15540 | +#include "devextras.h" |
| 15541 | +#include "yaffs_list.h" |
| 15542 | |
| 15543 | #define YAFFS_OK 1 |
| 15544 | #define YAFFS_FAIL 0 |
| 15545 | @@ -52,7 +53,6 @@ |
| 15546 | |
| 15547 | #define YAFFS_MAX_CHUNK_ID 0x000FFFFF |
| 15548 | |
| 15549 | -#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF |
| 15550 | |
| 15551 | #define YAFFS_ALLOCATION_NOBJECTS 100 |
| 15552 | #define YAFFS_ALLOCATION_NTNODES 100 |
| 15553 | @@ -62,8 +62,9 @@ |
| 15554 | |
| 15555 | |
| 15556 | #define YAFFS_OBJECT_SPACE 0x40000 |
| 15557 | +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE -1) |
| 15558 | |
| 15559 | -#define YAFFS_CHECKPOINT_VERSION 3 |
| 15560 | +#define YAFFS_CHECKPOINT_VERSION 4 |
| 15561 | |
| 15562 | #ifdef CONFIG_YAFFS_UNICODE |
| 15563 | #define YAFFS_MAX_NAME_LENGTH 127 |
| 15564 | @@ -81,12 +82,11 @@ |
| 15565 | #define YAFFS_OBJECTID_UNLINKED 3 |
| 15566 | #define YAFFS_OBJECTID_DELETED 4 |
| 15567 | |
| 15568 | -/* Sseudo object ids for checkpointing */ |
| 15569 | +/* Pseudo object ids for checkpointing */ |
| 15570 | #define YAFFS_OBJECTID_SB_HEADER 0x10 |
| 15571 | #define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 |
| 15572 | #define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 |
| 15573 | |
| 15574 | -/* */ |
| 15575 | |
| 15576 | #define YAFFS_MAX_SHORT_OP_CACHES 20 |
| 15577 | |
| 15578 | @@ -113,18 +113,14 @@ |
| 15579 | |
| 15580 | /* ChunkCache is used for short read/write operations.*/ |
| 15581 | typedef struct { |
| 15582 | - struct yaffs_ObjectStruct *object; |
| 15583 | - int chunkId; |
| 15584 | - int lastUse; |
| 15585 | + struct yaffs_obj_s *object; |
| 15586 | + int chunk_id; |
| 15587 | + int last_use; |
| 15588 | int dirty; |
| 15589 | - int nBytes; /* Only valid if the cache is dirty */ |
| 15590 | + int n_bytes; /* Only valid if the cache is dirty */ |
| 15591 | int locked; /* Can't push out or flush while locked. */ |
| 15592 | -#ifdef CONFIG_YAFFS_YAFFS2 |
| 15593 | __u8 *data; |
| 15594 | -#else |
| 15595 | - __u8 data[YAFFS_BYTES_PER_CHUNK]; |
| 15596 | -#endif |
| 15597 | -} yaffs_ChunkCache; |
| 15598 | +} yaffs_cache_t; |
| 15599 | |
| 15600 | |
| 15601 | |
| 15602 | @@ -135,18 +131,18 @@ typedef struct { |
| 15603 | |
| 15604 | #ifndef CONFIG_YAFFS_NO_YAFFS1 |
| 15605 | typedef struct { |
| 15606 | - unsigned chunkId:20; |
| 15607 | - unsigned serialNumber:2; |
| 15608 | - unsigned byteCountLSB:10; |
| 15609 | - unsigned objectId:18; |
| 15610 | + unsigned chunk_id:20; |
| 15611 | + unsigned serial_number:2; |
| 15612 | + unsigned n_bytes_lsb:10; |
| 15613 | + unsigned obj_id:18; |
| 15614 | unsigned ecc:12; |
| 15615 | - unsigned byteCountMSB:2; |
| 15616 | -} yaffs_Tags; |
| 15617 | + unsigned n_bytes_msb:2; |
| 15618 | +} yaffs_tags_t; |
| 15619 | |
| 15620 | typedef union { |
| 15621 | - yaffs_Tags asTags; |
| 15622 | - __u8 asBytes[8]; |
| 15623 | -} yaffs_TagsUnion; |
| 15624 | + yaffs_tags_t as_tags; |
| 15625 | + __u8 as_bytes[8]; |
| 15626 | +} yaffs_tags_union_t; |
| 15627 | |
| 15628 | #endif |
| 15629 | |
| 15630 | @@ -157,7 +153,7 @@ typedef enum { |
| 15631 | YAFFS_ECC_RESULT_NO_ERROR, |
| 15632 | YAFFS_ECC_RESULT_FIXED, |
| 15633 | YAFFS_ECC_RESULT_UNFIXED |
| 15634 | -} yaffs_ECCResult; |
| 15635 | +} yaffs_ecc_result; |
| 15636 | |
| 15637 | typedef enum { |
| 15638 | YAFFS_OBJECT_TYPE_UNKNOWN, |
| 15639 | @@ -166,64 +162,64 @@ typedef enum { |
| 15640 | YAFFS_OBJECT_TYPE_DIRECTORY, |
| 15641 | YAFFS_OBJECT_TYPE_HARDLINK, |
| 15642 | YAFFS_OBJECT_TYPE_SPECIAL |
| 15643 | -} yaffs_ObjectType; |
| 15644 | +} yaffs_obj_type; |
| 15645 | |
| 15646 | #define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL |
| 15647 | |
| 15648 | typedef struct { |
| 15649 | |
| 15650 | - unsigned validMarker0; |
| 15651 | - unsigned chunkUsed; /* Status of the chunk: used or unused */ |
| 15652 | - unsigned objectId; /* If 0 then this is not part of an object (unused) */ |
| 15653 | - unsigned chunkId; /* If 0 then this is a header, else a data chunk */ |
| 15654 | - unsigned byteCount; /* Only valid for data chunks */ |
| 15655 | + unsigned validity1; |
| 15656 | + unsigned chunk_used; /* Status of the chunk: used or unused */ |
| 15657 | + unsigned obj_id; /* If 0 then this is not part of an object (unused) */ |
| 15658 | + unsigned chunk_id; /* If 0 then this is a header, else a data chunk */ |
| 15659 | + unsigned n_bytes; /* Only valid for data chunks */ |
| 15660 | |
| 15661 | /* The following stuff only has meaning when we read */ |
| 15662 | - yaffs_ECCResult eccResult; |
| 15663 | - unsigned blockBad; |
| 15664 | + yaffs_ecc_result ecc_result; |
| 15665 | + unsigned block_bad; |
| 15666 | |
| 15667 | /* YAFFS 1 stuff */ |
| 15668 | - unsigned chunkDeleted; /* The chunk is marked deleted */ |
| 15669 | - unsigned serialNumber; /* Yaffs1 2-bit serial number */ |
| 15670 | + unsigned is_deleted; /* The chunk is marked deleted */ |
| 15671 | + unsigned serial_number; /* Yaffs1 2-bit serial number */ |
| 15672 | |
| 15673 | /* YAFFS2 stuff */ |
| 15674 | - unsigned sequenceNumber; /* The sequence number of this block */ |
| 15675 | + unsigned seq_number; /* The sequence number of this block */ |
| 15676 | |
| 15677 | /* Extra info if this is an object header (YAFFS2 only) */ |
| 15678 | |
| 15679 | - unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */ |
| 15680 | - unsigned extraParentObjectId; /* The parent object */ |
| 15681 | - unsigned extraIsShrinkHeader; /* Is it a shrink header? */ |
| 15682 | - unsigned extraShadows; /* Does this shadow another object? */ |
| 15683 | + unsigned extra_available; /* There is extra info available if this is not zero */ |
| 15684 | + unsigned extra_parent_id; /* The parent object */ |
| 15685 | + unsigned extra_is_shrink; /* Is it a shrink header? */ |
| 15686 | + unsigned extra_shadows; /* Does this shadow another object? */ |
| 15687 | |
| 15688 | - yaffs_ObjectType extraObjectType; /* What object type? */ |
| 15689 | + yaffs_obj_type extra_obj_type; /* What object type? */ |
| 15690 | |
| 15691 | - unsigned extraFileLength; /* Length if it is a file */ |
| 15692 | - unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */ |
| 15693 | + unsigned extra_length; /* Length if it is a file */ |
| 15694 | + unsigned extra_equiv_id; /* Equivalent object Id if it is a hard link */ |
| 15695 | |
| 15696 | - unsigned validMarker1; |
| 15697 | + unsigned validty1; |
| 15698 | |
| 15699 | -} yaffs_ExtendedTags; |
| 15700 | +} yaffs_ext_tags; |
| 15701 | |
| 15702 | /* Spare structure for YAFFS1 */ |
| 15703 | typedef struct { |
| 15704 | - __u8 tagByte0; |
| 15705 | - __u8 tagByte1; |
| 15706 | - __u8 tagByte2; |
| 15707 | - __u8 tagByte3; |
| 15708 | - __u8 pageStatus; /* set to 0 to delete the chunk */ |
| 15709 | - __u8 blockStatus; |
| 15710 | - __u8 tagByte4; |
| 15711 | - __u8 tagByte5; |
| 15712 | + __u8 tb0; |
| 15713 | + __u8 tb1; |
| 15714 | + __u8 tb2; |
| 15715 | + __u8 tb3; |
| 15716 | + __u8 page_status; /* set to 0 to delete the chunk */ |
| 15717 | + __u8 block_status; |
| 15718 | + __u8 tb4; |
| 15719 | + __u8 tb5; |
| 15720 | __u8 ecc1[3]; |
| 15721 | - __u8 tagByte6; |
| 15722 | - __u8 tagByte7; |
| 15723 | + __u8 tb6; |
| 15724 | + __u8 tb7; |
| 15725 | __u8 ecc2[3]; |
| 15726 | -} yaffs_Spare; |
| 15727 | +} yaffs_spare; |
| 15728 | |
| 15729 | /*Special structure for passing through to mtd */ |
| 15730 | -struct yaffs_NANDSpare { |
| 15731 | - yaffs_Spare spare; |
| 15732 | +struct yaffs_nand_spare { |
| 15733 | + yaffs_spare spare; |
| 15734 | int eccres1; |
| 15735 | int eccres2; |
| 15736 | }; |
| 15737 | @@ -234,6 +230,8 @@ typedef enum { |
| 15738 | YAFFS_BLOCK_STATE_UNKNOWN = 0, |
| 15739 | |
| 15740 | YAFFS_BLOCK_STATE_SCANNING, |
| 15741 | + /* Being scanned */ |
| 15742 | + |
| 15743 | YAFFS_BLOCK_STATE_NEEDS_SCANNING, |
| 15744 | /* The block might have something on it (ie it is allocating or full, perhaps empty) |
| 15745 | * but it needs to be scanned to determine its true state. |
| 15746 | @@ -249,67 +247,69 @@ typedef enum { |
| 15747 | /* This block is partially allocated. |
| 15748 | * At least one page holds valid data. |
| 15749 | * This is the one currently being used for page |
| 15750 | - * allocation. Should never be more than one of these |
| 15751 | + * allocation. Should never be more than one of these. |
| 15752 | + * If a block is only partially allocated at mount it is treated as full. |
| 15753 | */ |
| 15754 | |
| 15755 | YAFFS_BLOCK_STATE_FULL, |
| 15756 | /* All the pages in this block have been allocated. |
| 15757 | + * If a block was only partially allocated when mounted we treat |
| 15758 | + * it as fully allocated. |
| 15759 | */ |
| 15760 | |
| 15761 | YAFFS_BLOCK_STATE_DIRTY, |
| 15762 | - /* All pages have been allocated and deleted. |
| 15763 | + /* The block was full and now all chunks have been deleted. |
| 15764 | * Erase me, reuse me. |
| 15765 | */ |
| 15766 | |
| 15767 | YAFFS_BLOCK_STATE_CHECKPOINT, |
| 15768 | - /* This block is assigned to holding checkpoint data. |
| 15769 | - */ |
| 15770 | + /* This block is assigned to holding checkpoint data. */ |
| 15771 | |
| 15772 | YAFFS_BLOCK_STATE_COLLECTING, |
| 15773 | /* This block is being garbage collected */ |
| 15774 | |
| 15775 | YAFFS_BLOCK_STATE_DEAD |
| 15776 | /* This block has failed and is not in use */ |
| 15777 | -} yaffs_BlockState; |
| 15778 | +} yaffs_block_state_t; |
| 15779 | |
| 15780 | #define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) |
| 15781 | |
| 15782 | |
| 15783 | typedef struct { |
| 15784 | |
| 15785 | - int softDeletions:10; /* number of soft deleted pages */ |
| 15786 | - int pagesInUse:10; /* number of pages in use */ |
| 15787 | - unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */ |
| 15788 | - __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */ |
| 15789 | + int soft_del_pages:10; /* number of soft deleted pages */ |
| 15790 | + int pages_in_use:10; /* number of pages in use */ |
| 15791 | + unsigned block_state:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */ |
| 15792 | + __u32 needs_retiring:1; /* Data has failed on this block, need to get valid data off */ |
| 15793 | /* and retire the block. */ |
| 15794 | - __u32 skipErasedCheck:1; /* If this is set we can skip the erased check on this block */ |
| 15795 | - __u32 gcPrioritise:1; /* An ECC check or blank check has failed on this block. |
| 15796 | + __u32 skip_erased_check:1; /* If this is set we can skip the erased check on this block */ |
| 15797 | + __u32 gc_prioritise:1; /* An ECC check or blank check has failed on this block. |
| 15798 | It should be prioritised for GC */ |
| 15799 | - __u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */ |
| 15800 | + __u32 chunk_error_strikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */ |
| 15801 | |
| 15802 | #ifdef CONFIG_YAFFS_YAFFS2 |
| 15803 | - __u32 hasShrinkHeader:1; /* This block has at least one shrink object header */ |
| 15804 | - __u32 sequenceNumber; /* block sequence number for yaffs2 */ |
| 15805 | + __u32 has_shrink_hdr:1; /* This block has at least one shrink object header */ |
| 15806 | + __u32 seq_number; /* block sequence number for yaffs2 */ |
| 15807 | #endif |
| 15808 | |
| 15809 | -} yaffs_BlockInfo; |
| 15810 | +} yaffs_block_info_t; |
| 15811 | |
| 15812 | /* -------------------------- Object structure -------------------------------*/ |
| 15813 | /* This is the object structure as stored on NAND */ |
| 15814 | |
| 15815 | typedef struct { |
| 15816 | - yaffs_ObjectType type; |
| 15817 | + yaffs_obj_type type; |
| 15818 | |
| 15819 | /* Apply to everything */ |
| 15820 | - int parentObjectId; |
| 15821 | - __u16 sum__NoLongerUsed; /* checksum of name. No longer used */ |
| 15822 | + int parent_obj_id; |
| 15823 | + __u16 sum_no_longer_used; /* checksum of name. No longer used */ |
| 15824 | YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; |
| 15825 | |
| 15826 | /* The following apply to directories, files, symlinks - not hard links */ |
| 15827 | __u32 yst_mode; /* protection */ |
| 15828 | |
| 15829 | #ifdef CONFIG_YAFFS_WINCE |
| 15830 | - __u32 notForWinCE[5]; |
| 15831 | + __u32 not_for_wince[5]; |
| 15832 | #else |
| 15833 | __u32 yst_uid; |
| 15834 | __u32 yst_gid; |
| 15835 | @@ -319,10 +319,10 @@ typedef struct { |
| 15836 | #endif |
| 15837 | |
| 15838 | /* File size applies to files only */ |
| 15839 | - int fileSize; |
| 15840 | + int file_size; |
| 15841 | |
| 15842 | /* Equivalent object id applies to hard links only. */ |
| 15843 | - int equivalentObjectId; |
| 15844 | + int equiv_id; |
| 15845 | |
| 15846 | /* Alias is for symlinks only. */ |
| 15847 | YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; |
| 15848 | @@ -334,40 +334,29 @@ typedef struct { |
| 15849 | __u32 win_atime[2]; |
| 15850 | __u32 win_mtime[2]; |
| 15851 | #else |
| 15852 | - __u32 roomToGrow[6]; |
| 15853 | + __u32 room_to_grow[6]; |
| 15854 | |
| 15855 | #endif |
| 15856 | - __u32 inbandShadowsObject; |
| 15857 | - __u32 inbandIsShrink; |
| 15858 | + __u32 inband_shadowed_obj_id; |
| 15859 | + __u32 inband_is_shrink; |
| 15860 | |
| 15861 | - __u32 reservedSpace[2]; |
| 15862 | - int shadowsObject; /* This object header shadows the specified object if > 0 */ |
| 15863 | + __u32 reserved[2]; |
| 15864 | + int shadows_obj; /* This object header shadows the specified object if > 0 */ |
| 15865 | |
| 15866 | - /* isShrink applies to object headers written when we shrink the file (ie resize) */ |
| 15867 | - __u32 isShrink; |
| 15868 | + /* is_shrink applies to object headers written when we shrink the file (ie resize) */ |
| 15869 | + __u32 is_shrink; |
| 15870 | |
| 15871 | -} yaffs_ObjectHeader; |
| 15872 | +} yaffs_obj_header; |
| 15873 | |
| 15874 | /*--------------------------- Tnode -------------------------- */ |
| 15875 | |
| 15876 | -union yaffs_Tnode_union { |
| 15877 | -#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG |
| 15878 | - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1]; |
| 15879 | -#else |
| 15880 | - union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL]; |
| 15881 | -#endif |
| 15882 | -/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */ |
| 15883 | +union yaffs_tnode_union { |
| 15884 | + union yaffs_tnode_union *internal[YAFFS_NTNODES_INTERNAL]; |
| 15885 | |
| 15886 | }; |
| 15887 | |
| 15888 | -typedef union yaffs_Tnode_union yaffs_Tnode; |
| 15889 | +typedef union yaffs_tnode_union yaffs_tnode_t; |
| 15890 | |
| 15891 | -struct yaffs_TnodeList_struct { |
| 15892 | - struct yaffs_TnodeList_struct *next; |
| 15893 | - yaffs_Tnode *tnodes; |
| 15894 | -}; |
| 15895 | - |
| 15896 | -typedef struct yaffs_TnodeList_struct yaffs_TnodeList; |
| 15897 | |
| 15898 | /*------------------------ Object -----------------------------*/ |
| 15899 | /* An object can be one of: |
| 15900 | @@ -378,82 +367,85 @@ typedef struct yaffs_TnodeList_struct ya |
| 15901 | */ |
| 15902 | |
| 15903 | typedef struct { |
| 15904 | - __u32 fileSize; |
| 15905 | - __u32 scannedFileSize; |
| 15906 | - __u32 shrinkSize; |
| 15907 | - int topLevel; |
| 15908 | - yaffs_Tnode *top; |
| 15909 | -} yaffs_FileStructure; |
| 15910 | + __u32 file_size; |
| 15911 | + __u32 scanned_size; |
| 15912 | + __u32 shrink_size; |
| 15913 | + int top_level; |
| 15914 | + yaffs_tnode_t *top; |
| 15915 | +} yaffs_file_s; |
| 15916 | |
| 15917 | typedef struct { |
| 15918 | struct ylist_head children; /* list of child links */ |
| 15919 | -} yaffs_DirectoryStructure; |
| 15920 | + struct ylist_head dirty; /* Entry for list of dirty directories */ |
| 15921 | +} yaffs_dir_s; |
| 15922 | |
| 15923 | typedef struct { |
| 15924 | YCHAR *alias; |
| 15925 | -} yaffs_SymLinkStructure; |
| 15926 | +} yaffs_symlink_t; |
| 15927 | |
| 15928 | typedef struct { |
| 15929 | - struct yaffs_ObjectStruct *equivalentObject; |
| 15930 | - __u32 equivalentObjectId; |
| 15931 | -} yaffs_HardLinkStructure; |
| 15932 | + struct yaffs_obj_s *equiv_obj; |
| 15933 | + __u32 equiv_id; |
| 15934 | +} yaffs_hard_link_s; |
| 15935 | |
| 15936 | typedef union { |
| 15937 | - yaffs_FileStructure fileVariant; |
| 15938 | - yaffs_DirectoryStructure directoryVariant; |
| 15939 | - yaffs_SymLinkStructure symLinkVariant; |
| 15940 | - yaffs_HardLinkStructure hardLinkVariant; |
| 15941 | -} yaffs_ObjectVariant; |
| 15942 | + yaffs_file_s file_variant; |
| 15943 | + yaffs_dir_s dir_variant; |
| 15944 | + yaffs_symlink_t symlink_variant; |
| 15945 | + yaffs_hard_link_s hardlink_variant; |
| 15946 | +} yaffs_obj_variant; |
| 15947 | + |
| 15948 | + |
| 15949 | |
| 15950 | -struct yaffs_ObjectStruct { |
| 15951 | +struct yaffs_obj_s { |
| 15952 | __u8 deleted:1; /* This should only apply to unlinked files. */ |
| 15953 | - __u8 softDeleted:1; /* it has also been soft deleted */ |
| 15954 | + __u8 soft_del:1; /* it has also been soft deleted */ |
| 15955 | __u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/ |
| 15956 | __u8 fake:1; /* A fake object has no presence on NAND. */ |
| 15957 | - __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */ |
| 15958 | - __u8 unlinkAllowed:1; |
| 15959 | + __u8 rename_allowed:1; /* Some objects are not allowed to be renamed. */ |
| 15960 | + __u8 unlink_allowed:1; |
| 15961 | __u8 dirty:1; /* the object needs to be written to flash */ |
| 15962 | __u8 valid:1; /* When the file system is being loaded up, this |
| 15963 | * object might be created before the data |
| 15964 | * is available (ie. file data records appear before the header). |
| 15965 | */ |
| 15966 | - __u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */ |
| 15967 | + __u8 lazy_loaded:1; /* This object has been lazy loaded and is missing some detail */ |
| 15968 | |
| 15969 | - __u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is |
| 15970 | + __u8 defered_free:1; /* For Linux kernel. Object is removed from NAND, but is |
| 15971 | * still in the inode cache. Free of object is defered. |
| 15972 | * until the inode is released. |
| 15973 | */ |
| 15974 | - __u8 beingCreated:1; /* This object is still being created so skip some checks. */ |
| 15975 | + __u8 being_created:1; /* This object is still being created so skip some checks. */ |
| 15976 | + __u8 is_shadowed:1; /* This object is shadowed on the way to being renamed. */ |
| 15977 | + |
| 15978 | + __u8 xattr_known:1; /* We know if this has object has xattribs or not. */ |
| 15979 | + __u8 has_xattr:1; /* This object has xattribs. Valid if xattr_known. */ |
| 15980 | |
| 15981 | __u8 serial; /* serial number of chunk in NAND. Cached here */ |
| 15982 | __u16 sum; /* sum of the name to speed searching */ |
| 15983 | |
| 15984 | - struct yaffs_DeviceStruct *myDev; /* The device I'm on */ |
| 15985 | + struct yaffs_dev_s *my_dev; /* The device I'm on */ |
| 15986 | |
| 15987 | - struct ylist_head hashLink; /* list of objects in this hash bucket */ |
| 15988 | + struct ylist_head hash_link; /* list of objects in this hash bucket */ |
| 15989 | |
| 15990 | - struct ylist_head hardLinks; /* all the equivalent hard linked objects */ |
| 15991 | + struct ylist_head hard_links; /* all the equivalent hard linked objects */ |
| 15992 | |
| 15993 | /* directory structure stuff */ |
| 15994 | /* also used for linking up the free list */ |
| 15995 | - struct yaffs_ObjectStruct *parent; |
| 15996 | + struct yaffs_obj_s *parent; |
| 15997 | struct ylist_head siblings; |
| 15998 | |
| 15999 | /* Where's my object header in NAND? */ |
| 16000 | - int hdrChunk; |
| 16001 | + int hdr_chunk; |
| 16002 | |
| 16003 | - int nDataChunks; /* Number of data chunks attached to the file. */ |
| 16004 | + int n_data_chunks; /* Number of data chunks attached to the file. */ |
| 16005 | |
| 16006 | - __u32 objectId; /* the object id value */ |
| 16007 | + __u32 obj_id; /* the object id value */ |
| 16008 | |
| 16009 | __u32 yst_mode; |
| 16010 | |
| 16011 | #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM |
| 16012 | - YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1]; |
| 16013 | -#endif |
| 16014 | - |
| 16015 | -#ifndef __KERNEL__ |
| 16016 | - __u32 inUse; |
| 16017 | + YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1]; |
| 16018 | #endif |
| 16019 | |
| 16020 | #ifdef CONFIG_YAFFS_WINCE |
| 16021 | @@ -470,53 +462,43 @@ struct yaffs_ObjectStruct { |
| 16022 | |
| 16023 | __u32 yst_rdev; |
| 16024 | |
| 16025 | -#ifdef __KERNEL__ |
| 16026 | - struct inode *myInode; |
| 16027 | + void *my_inode; |
| 16028 | |
| 16029 | -#endif |
| 16030 | + yaffs_obj_type variant_type; |
| 16031 | |
| 16032 | - yaffs_ObjectType variantType; |
| 16033 | + yaffs_obj_variant variant; |
| 16034 | |
| 16035 | - yaffs_ObjectVariant variant; |
| 16036 | - |
| 16037 | -}; |
| 16038 | - |
| 16039 | -typedef struct yaffs_ObjectStruct yaffs_Object; |
| 16040 | - |
| 16041 | -struct yaffs_ObjectList_struct { |
| 16042 | - yaffs_Object *objects; |
| 16043 | - struct yaffs_ObjectList_struct *next; |
| 16044 | }; |
| 16045 | |
| 16046 | -typedef struct yaffs_ObjectList_struct yaffs_ObjectList; |
| 16047 | +typedef struct yaffs_obj_s yaffs_obj_t; |
| 16048 | |
| 16049 | typedef struct { |
| 16050 | struct ylist_head list; |
| 16051 | int count; |
| 16052 | -} yaffs_ObjectBucket; |
| 16053 | +} yaffs_obj_bucket; |
| 16054 | |
| 16055 | |
| 16056 | -/* yaffs_CheckpointObject holds the definition of an object as dumped |
| 16057 | +/* yaffs_checkpt_obj_t holds the definition of an object as dumped |
| 16058 | * by checkpointing. |
| 16059 | */ |
| 16060 | |
| 16061 | typedef struct { |
| 16062 | - int structType; |
| 16063 | - __u32 objectId; |
| 16064 | - __u32 parentId; |
| 16065 | - int hdrChunk; |
| 16066 | - yaffs_ObjectType variantType:3; |
| 16067 | + int struct_type; |
| 16068 | + __u32 obj_id; |
| 16069 | + __u32 parent_id; |
| 16070 | + int hdr_chunk; |
| 16071 | + yaffs_obj_type variant_type:3; |
| 16072 | __u8 deleted:1; |
| 16073 | - __u8 softDeleted:1; |
| 16074 | + __u8 soft_del:1; |
| 16075 | __u8 unlinked:1; |
| 16076 | __u8 fake:1; |
| 16077 | - __u8 renameAllowed:1; |
| 16078 | - __u8 unlinkAllowed:1; |
| 16079 | + __u8 rename_allowed:1; |
| 16080 | + __u8 unlink_allowed:1; |
| 16081 | __u8 serial; |
| 16082 | |
| 16083 | - int nDataChunks; |
| 16084 | - __u32 fileSizeOrEquivalentObjectId; |
| 16085 | -} yaffs_CheckpointObject; |
| 16086 | + int n_data_chunks; |
| 16087 | + __u32 size_or_equiv_obj; |
| 16088 | +} yaffs_checkpt_obj_t; |
| 16089 | |
| 16090 | /*--------------------- Temporary buffers ---------------- |
| 16091 | * |
| 16092 | @@ -526,379 +508,462 @@ typedef struct { |
| 16093 | typedef struct { |
| 16094 | __u8 *buffer; |
| 16095 | int line; /* track from whence this buffer was allocated */ |
| 16096 | - int maxLine; |
| 16097 | -} yaffs_TempBuffer; |
| 16098 | + int max_line; |
| 16099 | +} yaffs_buffer_t; |
| 16100 | |
| 16101 | /*----------------- Device ---------------------------------*/ |
| 16102 | |
| 16103 | -struct yaffs_DeviceStruct { |
| 16104 | - struct ylist_head devList; |
| 16105 | - const char *name; |
| 16106 | - |
| 16107 | - /* Entry parameters set up way early. Yaffs sets up the rest.*/ |
| 16108 | - int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */ |
| 16109 | - int nChunksPerBlock; /* does not need to be a power of 2 */ |
| 16110 | - int spareBytesPerChunk; /* spare area size */ |
| 16111 | - int startBlock; /* Start block we're allowed to use */ |
| 16112 | - int endBlock; /* End block we're allowed to use */ |
| 16113 | - int nReservedBlocks; /* We want this tuneable so that we can reduce */ |
| 16114 | - /* reserved blocks on NOR and RAM. */ |
| 16115 | - |
| 16116 | |
| 16117 | - /* Stuff used by the shared space checkpointing mechanism */ |
| 16118 | - /* If this value is zero, then this mechanism is disabled */ |
| 16119 | +struct yaffs_param_s { |
| 16120 | + const YCHAR *name; |
| 16121 | |
| 16122 | -/* int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */ |
| 16123 | + /* |
| 16124 | + * Entry parameters set up way early. Yaffs sets up the rest. |
| 16125 | + * The structure should be zeroed out before use so that unused |
| 16126 | + * and defualt values are zero. |
| 16127 | + */ |
| 16128 | + |
| 16129 | + int inband_tags; /* Use unband tags */ |
| 16130 | + __u32 total_bytes_per_chunk; /* Should be >= 512, does not need to be a power of 2 */ |
| 16131 | + int chunks_per_block; /* does not need to be a power of 2 */ |
| 16132 | + int spare_bytes_per_chunk; /* spare area size */ |
| 16133 | + int start_block; /* Start block we're allowed to use */ |
| 16134 | + int end_block; /* End block we're allowed to use */ |
| 16135 | + int n_reserved_blocks; /* We want this tuneable so that we can reduce */ |
| 16136 | + /* reserved blocks on NOR and RAM. */ |
| 16137 | |
| 16138 | |
| 16139 | - int nShortOpCaches; /* If <= 0, then short op caching is disabled, else |
| 16140 | - * the number of short op caches (don't use too many) |
| 16141 | + int n_caches; /* If <= 0, then short op caching is disabled, else |
| 16142 | + * the number of short op caches (don't use too many). |
| 16143 | + * 10 to 20 is a good bet. |
| 16144 | */ |
| 16145 | + int use_nand_ecc; /* Flag to decide whether or not to use NANDECC on data (yaffs1) */ |
| 16146 | + int no_tags_ecc; /* Flag to decide whether or not to do ECC on packed tags (yaffs2) */ |
| 16147 | |
| 16148 | - int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */ |
| 16149 | + int is_yaffs2; /* Use yaffs2 mode on this device */ |
| 16150 | |
| 16151 | - int useNANDECC; /* Flag to decide whether or not to use NANDECC */ |
| 16152 | + int empty_lost_n_found; /* Auto-empty lost+found directory on mount */ |
| 16153 | |
| 16154 | - void *genericDevice; /* Pointer to device context |
| 16155 | - * On an mtd this holds the mtd pointer. |
| 16156 | - */ |
| 16157 | - void *superBlock; |
| 16158 | + int refresh_period; /* How often we should check to do a block refresh */ |
| 16159 | + |
| 16160 | + /* Checkpoint control. Can be set before or after initialisation */ |
| 16161 | + __u8 skip_checkpt_rd; |
| 16162 | + __u8 skip_checkpt_wr; |
| 16163 | + |
| 16164 | + int enable_xattr; /* Enable xattribs */ |
| 16165 | |
| 16166 | /* NAND access functions (Must be set before calling YAFFS)*/ |
| 16167 | |
| 16168 | - int (*writeChunkToNAND) (struct yaffs_DeviceStruct *dev, |
| 16169 | - int chunkInNAND, const __u8 *data, |
| 16170 | - const yaffs_Spare *spare); |
| 16171 | - int (*readChunkFromNAND) (struct yaffs_DeviceStruct *dev, |
| 16172 | - int chunkInNAND, __u8 *data, |
| 16173 | - yaffs_Spare *spare); |
| 16174 | - int (*eraseBlockInNAND) (struct yaffs_DeviceStruct *dev, |
| 16175 | - int blockInNAND); |
| 16176 | - int (*initialiseNAND) (struct yaffs_DeviceStruct *dev); |
| 16177 | - int (*deinitialiseNAND) (struct yaffs_DeviceStruct *dev); |
| 16178 | + int (*write_chunk_fn) (struct yaffs_dev_s *dev, |
| 16179 | + int nand_chunk, const __u8 *data, |
| 16180 | + const yaffs_spare *spare); |
| 16181 | + int (*read_chunk_fn) (struct yaffs_dev_s *dev, |
| 16182 | + int nand_chunk, __u8 *data, |
| 16183 | + yaffs_spare *spare); |
| 16184 | + int (*erase_fn) (struct yaffs_dev_s *dev, |
| 16185 | + int flash_block); |
| 16186 | + int (*initialise_flash_fn) (struct yaffs_dev_s *dev); |
| 16187 | + int (*deinitialise_flash_fn) (struct yaffs_dev_s *dev); |
| 16188 | |
| 16189 | #ifdef CONFIG_YAFFS_YAFFS2 |
| 16190 | - int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct *dev, |
| 16191 | - int chunkInNAND, const __u8 *data, |
| 16192 | - const yaffs_ExtendedTags *tags); |
| 16193 | - int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct *dev, |
| 16194 | - int chunkInNAND, __u8 *data, |
| 16195 | - yaffs_ExtendedTags *tags); |
| 16196 | - int (*markNANDBlockBad) (struct yaffs_DeviceStruct *dev, int blockNo); |
| 16197 | - int (*queryNANDBlock) (struct yaffs_DeviceStruct *dev, int blockNo, |
| 16198 | - yaffs_BlockState *state, __u32 *sequenceNumber); |
| 16199 | -#endif |
| 16200 | - |
| 16201 | - int isYaffs2; |
| 16202 | - |
| 16203 | - /* The removeObjectCallback function must be supplied by OS flavours that |
| 16204 | - * need it. The Linux kernel does not use this, but yaffs direct does use |
| 16205 | - * it to implement the faster readdir |
| 16206 | + int (*write_chunk_tags_fn) (struct yaffs_dev_s *dev, |
| 16207 | + int nand_chunk, const __u8 *data, |
| 16208 | + const yaffs_ext_tags *tags); |
| 16209 | + int (*read_chunk_tags_fn) (struct yaffs_dev_s *dev, |
| 16210 | + int nand_chunk, __u8 *data, |
| 16211 | + yaffs_ext_tags *tags); |
| 16212 | + int (*bad_block_fn) (struct yaffs_dev_s *dev, int block_no); |
| 16213 | + int (*query_block_fn) (struct yaffs_dev_s *dev, int block_no, |
| 16214 | + yaffs_block_state_t *state, __u32 *seq_number); |
| 16215 | +#endif |
| 16216 | + |
| 16217 | + /* The remove_obj_fn function must be supplied by OS flavours that |
| 16218 | + * need it. |
| 16219 | + * yaffs direct uses it to implement the faster readdir. |
| 16220 | + * Linux uses it to protect the directory during unlocking. |
| 16221 | */ |
| 16222 | - void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj); |
| 16223 | + void (*remove_obj_fn)(struct yaffs_obj_s *obj); |
| 16224 | |
| 16225 | - /* Callback to mark the superblock dirsty */ |
| 16226 | - void (*markSuperBlockDirty)(void *superblock); |
| 16227 | + /* Callback to mark the superblock dirty */ |
| 16228 | + void (*sb_dirty_fn)(struct yaffs_dev_s *dev); |
| 16229 | + |
| 16230 | + /* Callback to control garbage collection. */ |
| 16231 | + unsigned (*gc_control)(struct yaffs_dev_s *dev); |
| 16232 | + |
| 16233 | + /* Debug control flags. Don't use unless you know what you're doing */ |
| 16234 | + int use_header_file_size; /* Flag to determine if we should use file sizes from the header */ |
| 16235 | + int disable_lazy_load; /* Disable lazy loading on this device */ |
| 16236 | + int wide_tnodes_disabled; /* Set to disable wide tnodes */ |
| 16237 | + int disable_soft_del; /* yaffs 1 only: Set to disable the use of softdeletion. */ |
| 16238 | + |
| 16239 | + int defered_dir_update; /* Set to defer directory updates */ |
| 16240 | |
| 16241 | - int wideTnodesDisabled; /* Set to disable wide tnodes */ |
| 16242 | +#ifdef CONFIG_YAFFS_AUTO_UNICODE |
| 16243 | + int auto_unicode; |
| 16244 | +#endif |
| 16245 | + int always_check_erased; /* Force chunk erased check always on */ |
| 16246 | +}; |
| 16247 | |
| 16248 | - YCHAR *pathDividers; /* String of legal path dividers */ |
| 16249 | +typedef struct yaffs_param_s yaffs_param_t; |
| 16250 | |
| 16251 | +struct yaffs_dev_s { |
| 16252 | + struct yaffs_param_s param; |
| 16253 | |
| 16254 | - /* End of stuff that must be set before initialisation. */ |
| 16255 | + /* Context storage. Holds extra OS specific data for this device */ |
| 16256 | |
| 16257 | - /* Checkpoint control. Can be set before or after initialisation */ |
| 16258 | - __u8 skipCheckpointRead; |
| 16259 | - __u8 skipCheckpointWrite; |
| 16260 | + void *os_context; |
| 16261 | + void *driver_context; |
| 16262 | + |
| 16263 | + struct ylist_head dev_list; |
| 16264 | |
| 16265 | /* Runtime parameters. Set up by YAFFS. */ |
| 16266 | + int data_bytes_per_chunk; |
| 16267 | |
| 16268 | - __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */ |
| 16269 | - __u16 chunkGroupSize; /* == 2^^chunkGroupBits */ |
| 16270 | + /* Non-wide tnode stuff */ |
| 16271 | + __u16 chunk_grp_bits; /* Number of bits that need to be resolved if |
| 16272 | + * the tnodes are not wide enough. |
| 16273 | + */ |
| 16274 | + __u16 chunk_grp_size; /* == 2^^chunk_grp_bits */ |
| 16275 | |
| 16276 | /* Stuff to support wide tnodes */ |
| 16277 | - __u32 tnodeWidth; |
| 16278 | - __u32 tnodeMask; |
| 16279 | + __u32 tnode_width; |
| 16280 | + __u32 tnode_mask; |
| 16281 | + __u32 tnode_size; |
| 16282 | |
| 16283 | /* Stuff for figuring out file offset to chunk conversions */ |
| 16284 | - __u32 chunkShift; /* Shift value */ |
| 16285 | - __u32 chunkDiv; /* Divisor after shifting: 1 for power-of-2 sizes */ |
| 16286 | - __u32 chunkMask; /* Mask to use for power-of-2 case */ |
| 16287 | - |
| 16288 | - /* Stuff to handle inband tags */ |
| 16289 | - int inbandTags; |
| 16290 | - __u32 totalBytesPerChunk; |
| 16291 | - |
| 16292 | -#ifdef __KERNEL__ |
| 16293 | - |
| 16294 | - struct semaphore sem; /* Semaphore for waiting on erasure.*/ |
| 16295 | - struct semaphore grossLock; /* Gross locking semaphore */ |
| 16296 | - __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer |
| 16297 | - * at compile time so we have to allocate it. |
| 16298 | - */ |
| 16299 | - void (*putSuperFunc) (struct super_block *sb); |
| 16300 | -#endif |
| 16301 | + __u32 chunk_shift; /* Shift value */ |
| 16302 | + __u32 chunk_div; /* Divisor after shifting: 1 for power-of-2 sizes */ |
| 16303 | + __u32 chunk_mask; /* Mask to use for power-of-2 case */ |
| 16304 | |
| 16305 | - int isMounted; |
| 16306 | |
| 16307 | - int isCheckpointed; |
| 16308 | + |
| 16309 | + int is_mounted; |
| 16310 | + int read_only; |
| 16311 | + int is_checkpointed; |
| 16312 | |
| 16313 | |
| 16314 | /* Stuff to support block offsetting to support start block zero */ |
| 16315 | - int internalStartBlock; |
| 16316 | - int internalEndBlock; |
| 16317 | - int blockOffset; |
| 16318 | - int chunkOffset; |
| 16319 | + int internal_start_block; |
| 16320 | + int internal_end_block; |
| 16321 | + int block_offset; |
| 16322 | + int chunk_offset; |
| 16323 | |
| 16324 | |
| 16325 | /* Runtime checkpointing stuff */ |
| 16326 | - int checkpointPageSequence; /* running sequence number of checkpoint pages */ |
| 16327 | - int checkpointByteCount; |
| 16328 | - int checkpointByteOffset; |
| 16329 | - __u8 *checkpointBuffer; |
| 16330 | - int checkpointOpenForWrite; |
| 16331 | - int blocksInCheckpoint; |
| 16332 | - int checkpointCurrentChunk; |
| 16333 | - int checkpointCurrentBlock; |
| 16334 | - int checkpointNextBlock; |
| 16335 | - int *checkpointBlockList; |
| 16336 | - int checkpointMaxBlocks; |
| 16337 | - __u32 checkpointSum; |
| 16338 | - __u32 checkpointXor; |
| 16339 | + int checkpt_page_seq; /* running sequence number of checkpoint pages */ |
| 16340 | + int checkpt_byte_count; |
| 16341 | + int checkpt_byte_offs; |
| 16342 | + __u8 *checkpt_buffer; |
| 16343 | + int checkpt_open_write; |
| 16344 | + int blocks_in_checkpt; |
| 16345 | + int checkpt_cur_chunk; |
| 16346 | + int checkpt_cur_block; |
| 16347 | + int checkpt_next_block; |
| 16348 | + int *checkpt_block_list; |
| 16349 | + int checkpt_max_blocks; |
| 16350 | + __u32 checkpt_sum; |
| 16351 | + __u32 checkpt_xor; |
| 16352 | |
| 16353 | - int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */ |
| 16354 | + int checkpoint_blocks_required; /* Number of blocks needed to store current checkpoint set */ |
| 16355 | |
| 16356 | /* Block Info */ |
| 16357 | - yaffs_BlockInfo *blockInfo; |
| 16358 | - __u8 *chunkBits; /* bitmap of chunks in use */ |
| 16359 | - unsigned blockInfoAlt:1; /* was allocated using alternative strategy */ |
| 16360 | - unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */ |
| 16361 | - int chunkBitmapStride; /* Number of bytes of chunkBits per block. |
| 16362 | - * Must be consistent with nChunksPerBlock. |
| 16363 | + yaffs_block_info_t *block_info; |
| 16364 | + __u8 *chunk_bits; /* bitmap of chunks in use */ |
| 16365 | + unsigned block_info_alt:1; /* was allocated using alternative strategy */ |
| 16366 | + unsigned chunk_bits_alt:1; /* was allocated using alternative strategy */ |
| 16367 | + int chunk_bit_stride; /* Number of bytes of chunk_bits per block. |
| 16368 | + * Must be consistent with chunks_per_block. |
| 16369 | */ |
| 16370 | |
| 16371 | - int nErasedBlocks; |
| 16372 | - int allocationBlock; /* Current block being allocated off */ |
| 16373 | - __u32 allocationPage; |
| 16374 | - int allocationBlockFinder; /* Used to search for next allocation block */ |
| 16375 | - |
| 16376 | - /* Runtime state */ |
| 16377 | - int nTnodesCreated; |
| 16378 | - yaffs_Tnode *freeTnodes; |
| 16379 | - int nFreeTnodes; |
| 16380 | - yaffs_TnodeList *allocatedTnodeList; |
| 16381 | - |
| 16382 | - int isDoingGC; |
| 16383 | - int gcBlock; |
| 16384 | - int gcChunk; |
| 16385 | - |
| 16386 | - int nObjectsCreated; |
| 16387 | - yaffs_Object *freeObjects; |
| 16388 | - int nFreeObjects; |
| 16389 | - |
| 16390 | - int nHardLinks; |
| 16391 | - |
| 16392 | - yaffs_ObjectList *allocatedObjectList; |
| 16393 | - |
| 16394 | - yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS]; |
| 16395 | - |
| 16396 | - int nFreeChunks; |
| 16397 | - |
| 16398 | - int currentDirtyChecker; /* Used to find current dirtiest block */ |
| 16399 | - |
| 16400 | - __u32 *gcCleanupList; /* objects to delete at the end of a GC. */ |
| 16401 | - int nonAggressiveSkip; /* GC state/mode */ |
| 16402 | - |
| 16403 | - /* Statistcs */ |
| 16404 | - int nPageWrites; |
| 16405 | - int nPageReads; |
| 16406 | - int nBlockErasures; |
| 16407 | - int nErasureFailures; |
| 16408 | - int nGCCopies; |
| 16409 | - int garbageCollections; |
| 16410 | - int passiveGarbageCollections; |
| 16411 | - int nRetriedWrites; |
| 16412 | - int nRetiredBlocks; |
| 16413 | - int eccFixed; |
| 16414 | - int eccUnfixed; |
| 16415 | - int tagsEccFixed; |
| 16416 | - int tagsEccUnfixed; |
| 16417 | - int nDeletions; |
| 16418 | - int nUnmarkedDeletions; |
| 16419 | - |
| 16420 | - int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ |
| 16421 | + int n_erased_blocks; |
| 16422 | + int alloc_block; /* Current block being allocated off */ |
| 16423 | + __u32 alloc_page; |
| 16424 | + int alloc_block_finder; /* Used to search for next allocation block */ |
| 16425 | + |
| 16426 | + /* Object and Tnode memory management */ |
| 16427 | + void *allocator; |
| 16428 | + int n_obj; |
| 16429 | + int n_tnodes; |
| 16430 | + |
| 16431 | + int n_hardlinks; |
| 16432 | + |
| 16433 | + yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS]; |
| 16434 | + __u32 bucket_finder; |
| 16435 | + |
| 16436 | + int n_free_chunks; |
| 16437 | + |
| 16438 | + /* Garbage collection control */ |
| 16439 | + __u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */ |
| 16440 | + __u32 n_clean_ups; |
| 16441 | + |
| 16442 | + unsigned has_pending_prioritised_gc; /* We think this device might have pending prioritised gcs */ |
| 16443 | + unsigned gc_disable; |
| 16444 | + unsigned gc_block_finder; |
| 16445 | + unsigned gc_dirtiest; |
| 16446 | + unsigned gc_pages_in_use; |
| 16447 | + unsigned gc_not_done; |
| 16448 | + unsigned gc_block; |
| 16449 | + unsigned gc_chunk; |
| 16450 | + unsigned gc_skip; |
| 16451 | |
| 16452 | /* Special directories */ |
| 16453 | - yaffs_Object *rootDir; |
| 16454 | - yaffs_Object *lostNFoundDir; |
| 16455 | + yaffs_obj_t *root_dir; |
| 16456 | + yaffs_obj_t *lost_n_found; |
| 16457 | |
| 16458 | /* Buffer areas for storing data to recover from write failures TODO |
| 16459 | - * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; |
| 16460 | - * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK]; |
| 16461 | + * __u8 buffered_data[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; |
| 16462 | + * yaffs_spare buffered_spare[YAFFS_CHUNKS_PER_BLOCK]; |
| 16463 | */ |
| 16464 | |
| 16465 | - int bufferedBlock; /* Which block is buffered here? */ |
| 16466 | - int doingBufferedBlockRewrite; |
| 16467 | - |
| 16468 | - yaffs_ChunkCache *srCache; |
| 16469 | - int srLastUse; |
| 16470 | + int buffered_block; /* Which block is buffered here? */ |
| 16471 | + int doing_buffered_block_rewrite; |
| 16472 | |
| 16473 | - int cacheHits; |
| 16474 | + yaffs_cache_t *cache; |
| 16475 | + int cache_last_use; |
| 16476 | |
| 16477 | /* Stuff for background deletion and unlinked files.*/ |
| 16478 | - yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */ |
| 16479 | - yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */ |
| 16480 | - yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/ |
| 16481 | - int nDeletedFiles; /* Count of files awaiting deletion;*/ |
| 16482 | - int nUnlinkedFiles; /* Count of unlinked files. */ |
| 16483 | - int nBackgroundDeletions; /* Count of background deletions. */ |
| 16484 | - |
| 16485 | + yaffs_obj_t *unlinked_dir; /* Directory where unlinked and deleted files live. */ |
| 16486 | + yaffs_obj_t *del_dir; /* Directory where deleted objects are sent to disappear. */ |
| 16487 | + yaffs_obj_t *unlinked_deletion; /* Current file being background deleted.*/ |
| 16488 | + int n_deleted_files; /* Count of files awaiting deletion;*/ |
| 16489 | + int n_unlinked_files; /* Count of unlinked files. */ |
| 16490 | + int n_bg_deletions; /* Count of background deletions. */ |
| 16491 | |
| 16492 | /* Temporary buffer management */ |
| 16493 | - yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS]; |
| 16494 | - int maxTemp; |
| 16495 | - int tempInUse; |
| 16496 | - int unmanagedTempAllocations; |
| 16497 | - int unmanagedTempDeallocations; |
| 16498 | + yaffs_buffer_t temp_buffer[YAFFS_N_TEMP_BUFFERS]; |
| 16499 | + int max_temp; |
| 16500 | + int temp_in_use; |
| 16501 | + int unmanaged_buffer_allocs; |
| 16502 | + int unmanaged_buffer_deallocs; |
| 16503 | |
| 16504 | /* yaffs2 runtime stuff */ |
| 16505 | - unsigned sequenceNumber; /* Sequence number of currently allocating block */ |
| 16506 | - unsigned oldestDirtySequence; |
| 16507 | + unsigned seq_number; /* Sequence number of currently allocating block */ |
| 16508 | + unsigned oldest_dirty_seq; |
| 16509 | + unsigned oldest_dirty_block; |
| 16510 | + |
| 16511 | + /* Block refreshing */ |
| 16512 | + int refresh_skip; /* A skip down counter. Refresh happens when this gets to zero. */ |
| 16513 | + |
| 16514 | + /* Dirty directory handling */ |
| 16515 | + struct ylist_head dirty_dirs; /* List of dirty directories */ |
| 16516 | + |
| 16517 | + |
| 16518 | + /* Statistcs */ |
| 16519 | + __u32 n_page_writes; |
| 16520 | + __u32 n_page_reads; |
| 16521 | + __u32 n_erasures; |
| 16522 | + __u32 n_erase_failures; |
| 16523 | + __u32 n_gc_copies; |
| 16524 | + __u32 all_gcs; |
| 16525 | + __u32 passive_gc_count; |
| 16526 | + __u32 oldest_dirty_gc_count; |
| 16527 | + __u32 n_gc_blocks; |
| 16528 | + __u32 bg_gcs; |
| 16529 | + __u32 n_retired_writes; |
| 16530 | + __u32 n_retired_blocks; |
| 16531 | + __u32 n_ecc_fixed; |
| 16532 | + __u32 n_ecc_unfixed; |
| 16533 | + __u32 n_tags_ecc_fixed; |
| 16534 | + __u32 n_tags_ecc_unfixed; |
| 16535 | + __u32 n_deletions; |
| 16536 | + __u32 n_unmarked_deletions; |
| 16537 | + __u32 refresh_count; |
| 16538 | + __u32 cache_hits; |
| 16539 | |
| 16540 | }; |
| 16541 | |
| 16542 | -typedef struct yaffs_DeviceStruct yaffs_Device; |
| 16543 | +typedef struct yaffs_dev_s yaffs_dev_t; |
| 16544 | |
| 16545 | /* The static layout of block usage etc is stored in the super block header */ |
| 16546 | typedef struct { |
| 16547 | int StructType; |
| 16548 | int version; |
| 16549 | - int checkpointStartBlock; |
| 16550 | - int checkpointEndBlock; |
| 16551 | - int startBlock; |
| 16552 | - int endBlock; |
| 16553 | + int checkpt_start_block; |
| 16554 | + int checkpt_end_block; |
| 16555 | + int start_block; |
| 16556 | + int end_block; |
| 16557 | int rfu[100]; |
| 16558 | -} yaffs_SuperBlockHeader; |
| 16559 | +} yaffs_sb_header; |
| 16560 | |
| 16561 | /* The CheckpointDevice structure holds the device information that changes at runtime and |
| 16562 | * must be preserved over unmount/mount cycles. |
| 16563 | */ |
| 16564 | typedef struct { |
| 16565 | - int structType; |
| 16566 | - int nErasedBlocks; |
| 16567 | - int allocationBlock; /* Current block being allocated off */ |
| 16568 | - __u32 allocationPage; |
| 16569 | - int nFreeChunks; |
| 16570 | - |
| 16571 | - int nDeletedFiles; /* Count of files awaiting deletion;*/ |
| 16572 | - int nUnlinkedFiles; /* Count of unlinked files. */ |
| 16573 | - int nBackgroundDeletions; /* Count of background deletions. */ |
| 16574 | + int struct_type; |
| 16575 | + int n_erased_blocks; |
| 16576 | + int alloc_block; /* Current block being allocated off */ |
| 16577 | + __u32 alloc_page; |
| 16578 | + int n_free_chunks; |
| 16579 | + |
| 16580 | + int n_deleted_files; /* Count of files awaiting deletion;*/ |
| 16581 | + int n_unlinked_files; /* Count of unlinked files. */ |
| 16582 | + int n_bg_deletions; /* Count of background deletions. */ |
| 16583 | |
| 16584 | /* yaffs2 runtime stuff */ |
| 16585 | - unsigned sequenceNumber; /* Sequence number of currently allocating block */ |
| 16586 | - unsigned oldestDirtySequence; |
| 16587 | + unsigned seq_number; /* Sequence number of currently allocating block */ |
| 16588 | |
| 16589 | -} yaffs_CheckpointDevice; |
| 16590 | +} yaffs_checkpt_dev_t; |
| 16591 | |
| 16592 | |
| 16593 | typedef struct { |
| 16594 | - int structType; |
| 16595 | + int struct_type; |
| 16596 | __u32 magic; |
| 16597 | __u32 version; |
| 16598 | __u32 head; |
| 16599 | -} yaffs_CheckpointValidity; |
| 16600 | +} yaffs_checkpt_validty_t; |
| 16601 | + |
| 16602 | + |
| 16603 | +struct yaffs_shadow_fixer_s { |
| 16604 | + int obj_id; |
| 16605 | + int shadowed_id; |
| 16606 | + struct yaffs_shadow_fixer_s *next; |
| 16607 | +}; |
| 16608 | + |
| 16609 | +/* Structure for doing xattr modifications */ |
| 16610 | +typedef struct { |
| 16611 | + int set; /* If 0 then this is a deletion */ |
| 16612 | + const YCHAR *name; |
| 16613 | + const void *data; |
| 16614 | + int size; |
| 16615 | + int flags; |
| 16616 | + int result; |
| 16617 | +}yaffs_xattr_mod; |
| 16618 | |
| 16619 | |
| 16620 | /*----------------------- YAFFS Functions -----------------------*/ |
| 16621 | |
| 16622 | -int yaffs_GutsInitialise(yaffs_Device *dev); |
| 16623 | -void yaffs_Deinitialise(yaffs_Device *dev); |
| 16624 | +int yaffs_guts_initialise(yaffs_dev_t *dev); |
| 16625 | +void yaffs_deinitialise(yaffs_dev_t *dev); |
| 16626 | |
| 16627 | -int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev); |
| 16628 | +int yaffs_get_n_free_chunks(yaffs_dev_t *dev); |
| 16629 | |
| 16630 | -int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, |
| 16631 | - yaffs_Object *newDir, const YCHAR *newName); |
| 16632 | +int yaffs_rename_obj(yaffs_obj_t *old_dir, const YCHAR *old_name, |
| 16633 | + yaffs_obj_t *new_dir, const YCHAR *new_name); |
| 16634 | |
| 16635 | -int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name); |
| 16636 | -int yaffs_DeleteObject(yaffs_Object *obj); |
| 16637 | +int yaffs_unlinker(yaffs_obj_t *dir, const YCHAR *name); |
| 16638 | +int yaffs_del_obj(yaffs_obj_t *obj); |
| 16639 | |
| 16640 | -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize); |
| 16641 | -int yaffs_GetObjectFileLength(yaffs_Object *obj); |
| 16642 | -int yaffs_GetObjectInode(yaffs_Object *obj); |
| 16643 | -unsigned yaffs_GetObjectType(yaffs_Object *obj); |
| 16644 | -int yaffs_GetObjectLinkCount(yaffs_Object *obj); |
| 16645 | +int yaffs_get_obj_name(yaffs_obj_t *obj, YCHAR *name, int buffer_size); |
| 16646 | +int yaffs_get_obj_length(yaffs_obj_t *obj); |
| 16647 | +int yaffs_get_obj_inode(yaffs_obj_t *obj); |
| 16648 | +unsigned yaffs_get_obj_type(yaffs_obj_t *obj); |
| 16649 | +int yaffs_get_obj_link_count(yaffs_obj_t *obj); |
| 16650 | |
| 16651 | -int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr); |
| 16652 | -int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr); |
| 16653 | +int yaffs_set_attribs(yaffs_obj_t *obj, struct iattr *attr); |
| 16654 | +int yaffs_get_attribs(yaffs_obj_t *obj, struct iattr *attr); |
| 16655 | |
| 16656 | /* File operations */ |
| 16657 | -int yaffs_ReadDataFromFile(yaffs_Object *obj, __u8 *buffer, loff_t offset, |
| 16658 | - int nBytes); |
| 16659 | -int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, loff_t offset, |
| 16660 | - int nBytes, int writeThrough); |
| 16661 | -int yaffs_ResizeFile(yaffs_Object *obj, loff_t newSize); |
| 16662 | +int yaffs_file_rd(yaffs_obj_t *obj, __u8 *buffer, loff_t offset, |
| 16663 | + int n_bytes); |
| 16664 | +int yaffs_wr_file(yaffs_obj_t *obj, const __u8 *buffer, loff_t offset, |
| 16665 | + int n_bytes, int write_trhrough); |
| 16666 | +int yaffs_resize_file(yaffs_obj_t *obj, loff_t new_size); |
| 16667 | |
| 16668 | -yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name, |
| 16669 | +yaffs_obj_t *yaffs_create_file(yaffs_obj_t *parent, const YCHAR *name, |
| 16670 | __u32 mode, __u32 uid, __u32 gid); |
| 16671 | -int yaffs_FlushFile(yaffs_Object *obj, int updateTime); |
| 16672 | + |
| 16673 | +int yaffs_flush_file(yaffs_obj_t *obj, int update_time, int data_sync); |
| 16674 | |
| 16675 | /* Flushing and checkpointing */ |
| 16676 | -void yaffs_FlushEntireDeviceCache(yaffs_Device *dev); |
| 16677 | +void yaffs_flush_whole_cache(yaffs_dev_t *dev); |
| 16678 | |
| 16679 | -int yaffs_CheckpointSave(yaffs_Device *dev); |
| 16680 | -int yaffs_CheckpointRestore(yaffs_Device *dev); |
| 16681 | +int yaffs_checkpoint_save(yaffs_dev_t *dev); |
| 16682 | +int yaffs_checkpoint_restore(yaffs_dev_t *dev); |
| 16683 | |
| 16684 | /* Directory operations */ |
| 16685 | -yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name, |
| 16686 | +yaffs_obj_t *yaffs_create_dir(yaffs_obj_t *parent, const YCHAR *name, |
| 16687 | __u32 mode, __u32 uid, __u32 gid); |
| 16688 | -yaffs_Object *yaffs_FindObjectByName(yaffs_Object *theDir, const YCHAR *name); |
| 16689 | -int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir, |
| 16690 | - int (*fn) (yaffs_Object *)); |
| 16691 | +yaffs_obj_t *yaffs_find_by_name(yaffs_obj_t *the_dir, const YCHAR *name); |
| 16692 | +int yaffs_ApplyToDirectoryChildren(yaffs_obj_t *the_dir, |
| 16693 | + int (*fn) (yaffs_obj_t *)); |
| 16694 | |
| 16695 | -yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number); |
| 16696 | +yaffs_obj_t *yaffs_find_by_number(yaffs_dev_t *dev, __u32 number); |
| 16697 | |
| 16698 | /* Link operations */ |
| 16699 | -yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, |
| 16700 | - yaffs_Object *equivalentObject); |
| 16701 | +yaffs_obj_t *yaffs_link_obj(yaffs_obj_t *parent, const YCHAR *name, |
| 16702 | + yaffs_obj_t *equiv_obj); |
| 16703 | |
| 16704 | -yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj); |
| 16705 | +yaffs_obj_t *yaffs_get_equivalent_obj(yaffs_obj_t *obj); |
| 16706 | |
| 16707 | /* Symlink operations */ |
| 16708 | -yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name, |
| 16709 | +yaffs_obj_t *yaffs_create_symlink(yaffs_obj_t *parent, const YCHAR *name, |
| 16710 | __u32 mode, __u32 uid, __u32 gid, |
| 16711 | const YCHAR *alias); |
| 16712 | -YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj); |
| 16713 | +YCHAR *yaffs_get_symlink_alias(yaffs_obj_t *obj); |
| 16714 | |
| 16715 | /* Special inodes (fifos, sockets and devices) */ |
| 16716 | -yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name, |
| 16717 | +yaffs_obj_t *yaffs_create_special(yaffs_obj_t *parent, const YCHAR *name, |
| 16718 | __u32 mode, __u32 uid, __u32 gid, __u32 rdev); |
| 16719 | |
| 16720 | + |
| 16721 | +int yaffs_set_xattrib(yaffs_obj_t *obj, const YCHAR *name, const void * value, int size, int flags); |
| 16722 | +int yaffs_get_xattrib(yaffs_obj_t *obj, const YCHAR *name, void *value, int size); |
| 16723 | +int yaffs_list_xattrib(yaffs_obj_t *obj, char *buffer, int size); |
| 16724 | +int yaffs_remove_xattrib(yaffs_obj_t *obj, const YCHAR *name); |
| 16725 | + |
| 16726 | /* Special directories */ |
| 16727 | -yaffs_Object *yaffs_Root(yaffs_Device *dev); |
| 16728 | -yaffs_Object *yaffs_LostNFound(yaffs_Device *dev); |
| 16729 | +yaffs_obj_t *yaffs_root(yaffs_dev_t *dev); |
| 16730 | +yaffs_obj_t *yaffs_lost_n_found(yaffs_dev_t *dev); |
| 16731 | |
| 16732 | #ifdef CONFIG_YAFFS_WINCE |
| 16733 | /* CONFIG_YAFFS_WINCE special stuff */ |
| 16734 | -void yfsd_WinFileTimeNow(__u32 target[2]); |
| 16735 | +void yfsd_win_file_time_now(__u32 target[2]); |
| 16736 | #endif |
| 16737 | |
| 16738 | -#ifdef __KERNEL__ |
| 16739 | +void yaffs_handle_defered_free(yaffs_obj_t *obj); |
| 16740 | |
| 16741 | -void yaffs_HandleDeferedFree(yaffs_Object *obj); |
| 16742 | -#endif |
| 16743 | +void yaffs_update_dirty_dirs(yaffs_dev_t *dev); |
| 16744 | + |
| 16745 | +int yaffs_bg_gc(yaffs_dev_t *dev, unsigned urgency); |
| 16746 | |
| 16747 | /* Debug dump */ |
| 16748 | -int yaffs_DumpObject(yaffs_Object *obj); |
| 16749 | +int yaffs_dump_obj(yaffs_obj_t *obj); |
| 16750 | |
| 16751 | -void yaffs_GutsTest(yaffs_Device *dev); |
| 16752 | +void yaffs_guts_test(yaffs_dev_t *dev); |
| 16753 | |
| 16754 | -/* A few useful functions */ |
| 16755 | -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags); |
| 16756 | -void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn); |
| 16757 | -int yaffs_CheckFF(__u8 *buffer, int nBytes); |
| 16758 | -void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); |
| 16759 | +/* A few useful functions to be used within the core files*/ |
| 16760 | +void yaffs_chunk_del(yaffs_dev_t *dev, int chunk_id, int mark_flash, int lyn); |
| 16761 | +int yaffs_check_ff(__u8 *buffer, int n_bytes); |
| 16762 | +void yaffs_handle_chunk_error(yaffs_dev_t *dev, yaffs_block_info_t *bi); |
| 16763 | + |
| 16764 | +__u8 *yaffs_get_temp_buffer(yaffs_dev_t *dev, int line_no); |
| 16765 | +void yaffs_release_temp_buffer(yaffs_dev_t *dev, __u8 *buffer, int line_no); |
| 16766 | + |
| 16767 | +yaffs_obj_t *yaffs_find_or_create_by_number(yaffs_dev_t *dev, |
| 16768 | + int number, |
| 16769 | + yaffs_obj_type type); |
| 16770 | +int yaffs_put_chunk_in_file(yaffs_obj_t *in, int inode_chunk, |
| 16771 | + int nand_chunk, int in_scan); |
| 16772 | +void yaffs_set_obj_name(yaffs_obj_t *obj, const YCHAR *name); |
| 16773 | +void yaffs_set_obj_name_from_oh(yaffs_obj_t *obj, const yaffs_obj_header *oh); |
| 16774 | +void yaffs_add_obj_to_dir(yaffs_obj_t *directory, |
| 16775 | + yaffs_obj_t *obj); |
| 16776 | +YCHAR *yaffs_clone_str(const YCHAR *str); |
| 16777 | +void yaffs_link_fixup(yaffs_dev_t *dev, yaffs_obj_t *hard_list); |
| 16778 | +void yaffs_block_became_dirty(yaffs_dev_t *dev, int block_no); |
| 16779 | +int yaffs_update_oh(yaffs_obj_t *in, const YCHAR *name, |
| 16780 | + int force, int is_shrink, int shadows, |
| 16781 | + yaffs_xattr_mod *xop); |
| 16782 | +void yaffs_handle_shadowed_obj(yaffs_dev_t *dev, int obj_id, |
| 16783 | + int backward_scanning); |
| 16784 | +int yaffs_check_alloc_available(yaffs_dev_t *dev, int n_chunks); |
| 16785 | +yaffs_tnode_t *yaffs_get_tnode(yaffs_dev_t *dev); |
| 16786 | +yaffs_tnode_t *yaffs_add_find_tnode_0(yaffs_dev_t *dev, |
| 16787 | + yaffs_file_s *file_struct, |
| 16788 | + __u32 chunk_id, |
| 16789 | + yaffs_tnode_t *passed_tn); |
| 16790 | + |
| 16791 | +int yaffs_do_file_wr(yaffs_obj_t *in, const __u8 *buffer, loff_t offset, |
| 16792 | + int n_bytes, int write_trhrough); |
| 16793 | +void yaffs_resize_file_down( yaffs_obj_t *obj, loff_t new_size); |
| 16794 | +void yaffs_skip_rest_of_block(yaffs_dev_t *dev); |
| 16795 | + |
| 16796 | +int yaffs_count_free_chunks(yaffs_dev_t *dev); |
| 16797 | + |
| 16798 | +yaffs_tnode_t *yaffs_find_tnode_0(yaffs_dev_t *dev, |
| 16799 | + yaffs_file_s *file_struct, |
| 16800 | + __u32 chunk_id); |
| 16801 | |
| 16802 | -__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo); |
| 16803 | -void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo); |
| 16804 | +__u32 yaffs_get_group_base(yaffs_dev_t *dev, yaffs_tnode_t *tn, unsigned pos); |
| 16805 | |
| 16806 | #endif |
| 16807 | --- a/fs/yaffs2/yaffsinterface.h |
| 16808 | +++ b/fs/yaffs2/yaffsinterface.h |
| 16809 | @@ -1,7 +1,7 @@ |
| 16810 | /* |
| 16811 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 16812 | * |
| 16813 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 16814 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 16815 | * for Toby Churchill Ltd and Brightstar Engineering |
| 16816 | * |
| 16817 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 16818 | @@ -16,6 +16,6 @@ |
| 16819 | #ifndef __YAFFSINTERFACE_H__ |
| 16820 | #define __YAFFSINTERFACE_H__ |
| 16821 | |
| 16822 | -int yaffs_Initialise(unsigned nBlocks); |
| 16823 | +int yaffs_initialise(unsigned nBlocks); |
| 16824 | |
| 16825 | #endif |
| 16826 | --- /dev/null |
| 16827 | +++ b/fs/yaffs2/yaffs_linux_allocator.c |
| 16828 | @@ -0,0 +1,200 @@ |
| 16829 | +/* |
| 16830 | + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 16831 | + * |
| 16832 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 16833 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 16834 | + * |
| 16835 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 16836 | + * |
| 16837 | + * This program is free software; you can redistribute it and/or modify |
| 16838 | + * it under the terms of the GNU Lesser General Public License version 2.1 as |
| 16839 | + * published by the Free Software Foundation. |
| 16840 | + * |
| 16841 | + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| 16842 | + * |
| 16843 | + * Note: Tis code is currently unused. Being checked in in case it becomes useful. |
| 16844 | + */ |
| 16845 | + |
| 16846 | + |
| 16847 | +#include "yaffs_allocator.h" |
| 16848 | +#include "yaffs_guts.h" |
| 16849 | +#include "yaffs_trace.h" |
| 16850 | +#include "yportenv.h" |
| 16851 | +#include "yaffs_linux.h" |
| 16852 | +/* |
| 16853 | + * Start out with the same allocator as yaffs direct. |
| 16854 | + * Todo: Change to Linux slab allocator. |
| 16855 | + */ |
| 16856 | + |
| 16857 | + |
| 16858 | + |
| 16859 | +#define NAMELEN 20 |
| 16860 | +struct yaffs_AllocatorStruct { |
| 16861 | + char tnode_name[NAMELEN+1]; |
| 16862 | + char object_name[NAMELEN+1]; |
| 16863 | + struct kmem_cache *tnode_cache; |
| 16864 | + struct kmem_cache *object_cache; |
| 16865 | +}; |
| 16866 | + |
| 16867 | +typedef struct yaffs_AllocatorStruct yaffs_Allocator; |
| 16868 | + |
| 16869 | +int mount_id; |
| 16870 | + |
| 16871 | +void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev) |
| 16872 | +{ |
| 16873 | + yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator; |
| 16874 | + |
| 16875 | + T(YAFFS_TRACE_ALLOCATE,(TSTR("Deinitialising yaffs allocator\n"))); |
| 16876 | + |
| 16877 | + if(allocator){ |
| 16878 | + if(allocator->tnode_cache){ |
| 16879 | + kmem_cache_destroy(allocator->tnode_cache); |
| 16880 | + allocator->tnode_cache = NULL; |
| 16881 | + } else { |
| 16882 | + T(YAFFS_TRACE_ALWAYS, |
| 16883 | + (TSTR("NULL tnode cache\n"))); |
| 16884 | + YBUG(); |
| 16885 | + } |
| 16886 | + |
| 16887 | + if(allocator->object_cache){ |
| 16888 | + kmem_cache_destroy(allocator->object_cache); |
| 16889 | + allocator->object_cache = NULL; |
| 16890 | + } else { |
| 16891 | + T(YAFFS_TRACE_ALWAYS, |
| 16892 | + (TSTR("NULL object cache\n"))); |
| 16893 | + YBUG(); |
| 16894 | + } |
| 16895 | + |
| 16896 | + YFREE(allocator); |
| 16897 | + |
| 16898 | + } else { |
| 16899 | + T(YAFFS_TRACE_ALWAYS, |
| 16900 | + (TSTR("Deinitialising NULL allocator\n"))); |
| 16901 | + YBUG(); |
| 16902 | + } |
| 16903 | + dev->allocator = NULL; |
| 16904 | +} |
| 16905 | + |
| 16906 | + |
| 16907 | +static void fake_ctor0(void *data){data = data;} |
| 16908 | +static void fake_ctor1(void *data){data = data;} |
| 16909 | +static void fake_ctor2(void *data){data = data;} |
| 16910 | +static void fake_ctor3(void *data){data = data;} |
| 16911 | +static void fake_ctor4(void *data){data = data;} |
| 16912 | +static void fake_ctor5(void *data){data = data;} |
| 16913 | +static void fake_ctor6(void *data){data = data;} |
| 16914 | +static void fake_ctor7(void *data){data = data;} |
| 16915 | +static void fake_ctor8(void *data){data = data;} |
| 16916 | +static void fake_ctor9(void *data){data = data;} |
| 16917 | + |
| 16918 | +static void (*fake_ctor_list[10]) (void *) = { |
| 16919 | + fake_ctor0, |
| 16920 | + fake_ctor1, |
| 16921 | + fake_ctor2, |
| 16922 | + fake_ctor3, |
| 16923 | + fake_ctor4, |
| 16924 | + fake_ctor5, |
| 16925 | + fake_ctor6, |
| 16926 | + fake_ctor7, |
| 16927 | + fake_ctor8, |
| 16928 | + fake_ctor9, |
| 16929 | +}; |
| 16930 | + |
| 16931 | +void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev) |
| 16932 | +{ |
| 16933 | + yaffs_Allocator *allocator; |
| 16934 | + unsigned mount_id = yaffs_dev_to_lc(dev)->mount_id; |
| 16935 | + |
| 16936 | + T(YAFFS_TRACE_ALLOCATE,(TSTR("Initialising yaffs allocator\n"))); |
| 16937 | + |
| 16938 | + if(dev->allocator) |
| 16939 | + YBUG(); |
| 16940 | + else if(mount_id >= 10){ |
| 16941 | + T(YAFFS_TRACE_ALWAYS,(TSTR("Bad mount_id %u\n"),mount_id)); |
| 16942 | + } else { |
| 16943 | + allocator = YMALLOC(sizeof(yaffs_Allocator)); |
| 16944 | + memset(allocator,0,sizeof(yaffs_Allocator)); |
| 16945 | + dev->allocator = allocator; |
| 16946 | + |
| 16947 | + if(!dev->allocator){ |
| 16948 | + T(YAFFS_TRACE_ALWAYS, |
| 16949 | + (TSTR("yaffs allocator creation failed\n"))); |
| 16950 | + YBUG(); |
| 16951 | + return; |
| 16952 | + |
| 16953 | + } |
| 16954 | + |
| 16955 | + sprintf(allocator->tnode_name,"yaffs_t_%u",mount_id); |
| 16956 | + sprintf(allocator->object_name,"yaffs_o_%u",mount_id); |
| 16957 | + |
| 16958 | + allocator->tnode_cache = |
| 16959 | + kmem_cache_create(allocator->tnode_name, |
| 16960 | + dev->tnode_size, |
| 16961 | + 0, 0, |
| 16962 | + fake_ctor_list[mount_id]); |
| 16963 | + if(allocator->tnode_cache) |
| 16964 | + T(YAFFS_TRACE_ALLOCATE, |
| 16965 | + (TSTR("tnode cache \"%s\" %p\n"), |
| 16966 | + allocator->tnode_name,allocator->tnode_cache)); |
| 16967 | + else { |
| 16968 | + T(YAFFS_TRACE_ALWAYS, |
| 16969 | + (TSTR("yaffs cache creation failed\n"))); |
| 16970 | + YBUG(); |
| 16971 | + } |
| 16972 | + |
| 16973 | + |
| 16974 | + allocator->object_cache = |
| 16975 | + kmem_cache_create(allocator->object_name, |
| 16976 | + sizeof(yaffs_obj_t), |
| 16977 | + 0, 0, |
| 16978 | + fake_ctor_list[mount_id]); |
| 16979 | + |
| 16980 | + if(allocator->object_cache) |
| 16981 | + T(YAFFS_TRACE_ALLOCATE, |
| 16982 | + (TSTR("object cache \"%s\" %p\n"), |
| 16983 | + allocator->object_name,allocator->object_cache)); |
| 16984 | + |
| 16985 | + else { |
| 16986 | + T(YAFFS_TRACE_ALWAYS, |
| 16987 | + (TSTR("yaffs cache creation failed\n"))); |
| 16988 | + YBUG(); |
| 16989 | + } |
| 16990 | + } |
| 16991 | +} |
| 16992 | + |
| 16993 | + |
| 16994 | +yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev) |
| 16995 | +{ |
| 16996 | + yaffs_Allocator *allocator = dev->allocator; |
| 16997 | + if(!allocator || !allocator->tnode_cache){ |
| 16998 | + YBUG(); |
| 16999 | + return NULL; |
| 17000 | + } |
| 17001 | + return kmem_cache_alloc(allocator->tnode_cache, GFP_NOFS); |
| 17002 | +} |
| 17003 | + |
| 17004 | +void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn) |
| 17005 | +{ |
| 17006 | + yaffs_Allocator *allocator = dev->allocator; |
| 17007 | + kmem_cache_free(allocator->tnode_cache,tn); |
| 17008 | +} |
| 17009 | + |
| 17010 | +yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev) |
| 17011 | +{ |
| 17012 | + yaffs_Allocator *allocator = dev->allocator; |
| 17013 | + if(!allocator){ |
| 17014 | + YBUG(); |
| 17015 | + return NULL; |
| 17016 | + } |
| 17017 | + if(!allocator->object_cache){ |
| 17018 | + YBUG(); |
| 17019 | + return NULL; |
| 17020 | + } |
| 17021 | + return kmem_cache_alloc(allocator->object_cache, GFP_NOFS); |
| 17022 | +} |
| 17023 | + |
| 17024 | +void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj) |
| 17025 | +{ |
| 17026 | + yaffs_Allocator *allocator = dev->allocator; |
| 17027 | + kmem_cache_free(allocator->object_cache,obj); |
| 17028 | +} |
| 17029 | --- /dev/null |
| 17030 | +++ b/fs/yaffs2/yaffs_linux.h |
| 17031 | @@ -0,0 +1,43 @@ |
| 17032 | +/* |
| 17033 | + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 17034 | + * |
| 17035 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 17036 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 17037 | + * |
| 17038 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 17039 | + * |
| 17040 | + * This program is free software; you can redistribute it and/or modify |
| 17041 | + * it under the terms of the GNU Lesser General Public License version 2.1 as |
| 17042 | + * published by the Free Software Foundation. |
| 17043 | + * |
| 17044 | + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| 17045 | + */ |
| 17046 | + |
| 17047 | +#ifndef __YAFFS_LINUX_H__ |
| 17048 | +#define __YAFFS_LINUX_H__ |
| 17049 | + |
| 17050 | +#include "devextras.h" |
| 17051 | +#include "yportenv.h" |
| 17052 | + |
| 17053 | +struct yaffs_LinuxContext { |
| 17054 | + struct ylist_head contextList; /* List of these we have mounted */ |
| 17055 | + struct yaffs_dev_s *dev; |
| 17056 | + struct super_block * superBlock; |
| 17057 | + struct task_struct *bgThread; /* Background thread for this device */ |
| 17058 | + int bgRunning; |
| 17059 | + struct semaphore grossLock; /* Gross locking semaphore */ |
| 17060 | + __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer |
| 17061 | + * at compile time so we have to allocate it. |
| 17062 | + */ |
| 17063 | + struct ylist_head searchContexts; |
| 17064 | + void (*putSuperFunc)(struct super_block *sb); |
| 17065 | + |
| 17066 | + struct task_struct *readdirProcess; |
| 17067 | + unsigned mount_id; |
| 17068 | +}; |
| 17069 | + |
| 17070 | +#define yaffs_dev_to_lc(dev) ((struct yaffs_LinuxContext *)((dev)->os_context)) |
| 17071 | +#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context)) |
| 17072 | + |
| 17073 | +#endif |
| 17074 | + |
| 17075 | --- /dev/null |
| 17076 | +++ b/fs/yaffs2/yaffs_list.h |
| 17077 | @@ -0,0 +1,127 @@ |
| 17078 | +/* |
| 17079 | + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 17080 | + * |
| 17081 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 17082 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 17083 | + * |
| 17084 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 17085 | + * |
| 17086 | + * This program is free software; you can redistribute it and/or modify |
| 17087 | + * it under the terms of the GNU Lesser General Public License version 2.1 as |
| 17088 | + * published by the Free Software Foundation. |
| 17089 | + * |
| 17090 | + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| 17091 | + */ |
| 17092 | + |
| 17093 | +/* |
| 17094 | + * This file is just holds extra declarations of macros that would normally |
| 17095 | + * be providesd in the Linux kernel. These macros have been written from |
| 17096 | + * scratch but are functionally equivalent to the Linux ones. |
| 17097 | + * |
| 17098 | + */ |
| 17099 | + |
| 17100 | +#ifndef __YAFFS_LIST_H__ |
| 17101 | +#define __YAFFS_LIST_H__ |
| 17102 | + |
| 17103 | + |
| 17104 | +#include "yportenv.h" |
| 17105 | + |
| 17106 | +/* |
| 17107 | + * This is a simple doubly linked list implementation that matches the |
| 17108 | + * way the Linux kernel doubly linked list implementation works. |
| 17109 | + */ |
| 17110 | + |
| 17111 | +struct ylist_head { |
| 17112 | + struct ylist_head *next; /* next in chain */ |
| 17113 | + struct ylist_head *prev; /* previous in chain */ |
| 17114 | +}; |
| 17115 | + |
| 17116 | + |
| 17117 | +/* Initialise a static list */ |
| 17118 | +#define YLIST_HEAD(name) \ |
| 17119 | +struct ylist_head name = { &(name), &(name)} |
| 17120 | + |
| 17121 | + |
| 17122 | + |
| 17123 | +/* Initialise a list head to an empty list */ |
| 17124 | +#define YINIT_LIST_HEAD(p) \ |
| 17125 | +do { \ |
| 17126 | + (p)->next = (p);\ |
| 17127 | + (p)->prev = (p); \ |
| 17128 | +} while (0) |
| 17129 | + |
| 17130 | + |
| 17131 | +/* Add an element to a list */ |
| 17132 | +static Y_INLINE void ylist_add(struct ylist_head *newEntry, |
| 17133 | + struct ylist_head *list) |
| 17134 | +{ |
| 17135 | + struct ylist_head *listNext = list->next; |
| 17136 | + |
| 17137 | + list->next = newEntry; |
| 17138 | + newEntry->prev = list; |
| 17139 | + newEntry->next = listNext; |
| 17140 | + listNext->prev = newEntry; |
| 17141 | + |
| 17142 | +} |
| 17143 | + |
| 17144 | +static Y_INLINE void ylist_add_tail(struct ylist_head *newEntry, |
| 17145 | + struct ylist_head *list) |
| 17146 | +{ |
| 17147 | + struct ylist_head *listPrev = list->prev; |
| 17148 | + |
| 17149 | + list->prev = newEntry; |
| 17150 | + newEntry->next = list; |
| 17151 | + newEntry->prev = listPrev; |
| 17152 | + listPrev->next = newEntry; |
| 17153 | + |
| 17154 | +} |
| 17155 | + |
| 17156 | + |
| 17157 | +/* Take an element out of its current list, with or without |
| 17158 | + * reinitialising the links.of the entry*/ |
| 17159 | +static Y_INLINE void ylist_del(struct ylist_head *entry) |
| 17160 | +{ |
| 17161 | + struct ylist_head *listNext = entry->next; |
| 17162 | + struct ylist_head *listPrev = entry->prev; |
| 17163 | + |
| 17164 | + listNext->prev = listPrev; |
| 17165 | + listPrev->next = listNext; |
| 17166 | + |
| 17167 | +} |
| 17168 | + |
| 17169 | +static Y_INLINE void ylist_del_init(struct ylist_head *entry) |
| 17170 | +{ |
| 17171 | + ylist_del(entry); |
| 17172 | + entry->next = entry->prev = entry; |
| 17173 | +} |
| 17174 | + |
| 17175 | + |
| 17176 | +/* Test if the list is empty */ |
| 17177 | +static Y_INLINE int ylist_empty(struct ylist_head *entry) |
| 17178 | +{ |
| 17179 | + return (entry->next == entry); |
| 17180 | +} |
| 17181 | + |
| 17182 | + |
| 17183 | +/* ylist_entry takes a pointer to a list entry and offsets it to that |
| 17184 | + * we can find a pointer to the object it is embedded in. |
| 17185 | + */ |
| 17186 | + |
| 17187 | + |
| 17188 | +#define ylist_entry(entry, type, member) \ |
| 17189 | + ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) |
| 17190 | + |
| 17191 | + |
| 17192 | +/* ylist_for_each and list_for_each_safe iterate over lists. |
| 17193 | + * ylist_for_each_safe uses temporary storage to make the list delete safe |
| 17194 | + */ |
| 17195 | + |
| 17196 | +#define ylist_for_each(itervar, list) \ |
| 17197 | + for (itervar = (list)->next; itervar != (list); itervar = itervar->next) |
| 17198 | + |
| 17199 | +#define ylist_for_each_safe(itervar, saveVar, list) \ |
| 17200 | + for (itervar = (list)->next, saveVar = (list)->next->next; \ |
| 17201 | + itervar != (list); itervar = saveVar, saveVar = saveVar->next) |
| 17202 | + |
| 17203 | + |
| 17204 | +#endif |
| 17205 | --- a/fs/yaffs2/yaffs_mtdif1.c |
| 17206 | +++ b/fs/yaffs2/yaffs_mtdif1.c |
| 17207 | @@ -2,7 +2,7 @@ |
| 17208 | * YAFFS: Yet another FFS. A NAND-flash specific file system. |
| 17209 | * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND. |
| 17210 | * |
| 17211 | - * Copyright (C) 2002 Aleph One Ltd. |
| 17212 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 17213 | * for Toby Churchill Ltd and Brightstar Engineering |
| 17214 | * |
| 17215 | * This program is free software; you can redistribute it and/or modify |
| 17216 | @@ -18,15 +18,17 @@ |
| 17217 | * |
| 17218 | * These functions are invoked via function pointers in yaffs_nand.c. |
| 17219 | * This replaces functionality provided by functions in yaffs_mtdif.c |
| 17220 | - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are |
| 17221 | + * and the yaffs_tags_tCompatability functions in yaffs_tagscompat.c that are |
| 17222 | * called in yaffs_mtdif.c when the function pointers are NULL. |
| 17223 | - * We assume the MTD layer is performing ECC (useNANDECC is true). |
| 17224 | + * We assume the MTD layer is performing ECC (use_nand_ecc is true). |
| 17225 | */ |
| 17226 | |
| 17227 | #include "yportenv.h" |
| 17228 | +#include "yaffs_trace.h" |
| 17229 | #include "yaffs_guts.h" |
| 17230 | #include "yaffs_packedtags1.h" |
| 17231 | -#include "yaffs_tagscompat.h" /* for yaffs_CalcTagsECC */ |
| 17232 | +#include "yaffs_tagscompat.h" /* for yaffs_calc_tags_ecc */ |
| 17233 | +#include "yaffs_linux.h" |
| 17234 | |
| 17235 | #include "linux/kernel.h" |
| 17236 | #include "linux/version.h" |
| 17237 | @@ -36,8 +38,6 @@ |
| 17238 | /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ |
| 17239 | #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) |
| 17240 | |
| 17241 | -const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $"; |
| 17242 | - |
| 17243 | #ifndef CONFIG_YAFFS_9BYTE_TAGS |
| 17244 | # define YTAG1_SIZE 8 |
| 17245 | #else |
| 17246 | @@ -51,12 +51,12 @@ const char *yaffs_mtdif1_c_version = "$I |
| 17247 | * adjust 'oobfree' to match your existing Yaffs data. |
| 17248 | * |
| 17249 | * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the |
| 17250 | - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to |
| 17251 | + * page_status byte (at NAND spare offset 4) scattered/gathered from/to |
| 17252 | * the 9th byte. |
| 17253 | * |
| 17254 | * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5 |
| 17255 | - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P |
| 17256 | - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus |
| 17257 | + * We have/need PackedTags1 plus page_status: T0,T1,T2,T3,T4,T5,T6,T7,P |
| 17258 | + * where Tn are the tag bytes, En are MTD's ECC bytes, P is the page_status |
| 17259 | * byte and B is the small-page bad-block indicator byte. |
| 17260 | */ |
| 17261 | static struct nand_ecclayout nand_oob_16 = { |
| 17262 | @@ -88,42 +88,40 @@ static struct nand_ecclayout nand_oob_16 |
| 17263 | * Any underlying MTD error results in YAFFS_FAIL. |
| 17264 | * Returns YAFFS_OK or YAFFS_FAIL. |
| 17265 | */ |
| 17266 | -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, |
| 17267 | - int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags) |
| 17268 | +int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, |
| 17269 | + int nand_chunk, const __u8 *data, const yaffs_ext_tags *etags) |
| 17270 | { |
| 17271 | - struct mtd_info *mtd = dev->genericDevice; |
| 17272 | - int chunkBytes = dev->nDataBytesPerChunk; |
| 17273 | - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; |
| 17274 | + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); |
| 17275 | + int chunkBytes = dev->data_bytes_per_chunk; |
| 17276 | + loff_t addr = ((loff_t)nand_chunk) * chunkBytes; |
| 17277 | struct mtd_oob_ops ops; |
| 17278 | yaffs_PackedTags1 pt1; |
| 17279 | int retval; |
| 17280 | |
| 17281 | - /* we assume that PackedTags1 and yaffs_Tags are compatible */ |
| 17282 | + /* we assume that PackedTags1 and yaffs_tags_t are compatible */ |
| 17283 | compile_time_assertion(sizeof(yaffs_PackedTags1) == 12); |
| 17284 | - compile_time_assertion(sizeof(yaffs_Tags) == 8); |
| 17285 | - |
| 17286 | - dev->nPageWrites++; |
| 17287 | + compile_time_assertion(sizeof(yaffs_tags_t) == 8); |
| 17288 | |
| 17289 | yaffs_PackTags1(&pt1, etags); |
| 17290 | - yaffs_CalcTagsECC((yaffs_Tags *)&pt1); |
| 17291 | + yaffs_calc_tags_ecc((yaffs_tags_t *)&pt1); |
| 17292 | |
| 17293 | /* When deleting a chunk, the upper layer provides only skeletal |
| 17294 | - * etags, one with chunkDeleted set. However, we need to update the |
| 17295 | + * etags, one with is_deleted set. However, we need to update the |
| 17296 | * tags, not erase them completely. So we use the NAND write property |
| 17297 | * that only zeroed-bits stick and set tag bytes to all-ones and |
| 17298 | * zero just the (not) deleted bit. |
| 17299 | */ |
| 17300 | #ifndef CONFIG_YAFFS_9BYTE_TAGS |
| 17301 | - if (etags->chunkDeleted) { |
| 17302 | + if (etags->is_deleted) { |
| 17303 | memset(&pt1, 0xff, 8); |
| 17304 | /* clear delete status bit to indicate deleted */ |
| 17305 | pt1.deleted = 0; |
| 17306 | } |
| 17307 | #else |
| 17308 | ((__u8 *)&pt1)[8] = 0xff; |
| 17309 | - if (etags->chunkDeleted) { |
| 17310 | + if (etags->is_deleted) { |
| 17311 | memset(&pt1, 0xff, 8); |
| 17312 | - /* zero pageStatus byte to indicate deleted */ |
| 17313 | + /* zero page_status byte to indicate deleted */ |
| 17314 | ((__u8 *)&pt1)[8] = 0; |
| 17315 | } |
| 17316 | #endif |
| 17317 | @@ -137,20 +135,20 @@ int nandmtd1_WriteChunkWithTagsToNAND(ya |
| 17318 | |
| 17319 | retval = mtd->write_oob(mtd, addr, &ops); |
| 17320 | if (retval) { |
| 17321 | - yaffs_trace(YAFFS_TRACE_MTD, |
| 17322 | - "write_oob failed, chunk %d, mtd error %d\n", |
| 17323 | - chunkInNAND, retval); |
| 17324 | + T(YAFFS_TRACE_MTD, |
| 17325 | + (TSTR("write_oob failed, chunk %d, mtd error %d"TENDSTR), |
| 17326 | + nand_chunk, retval)); |
| 17327 | } |
| 17328 | return retval ? YAFFS_FAIL : YAFFS_OK; |
| 17329 | } |
| 17330 | |
| 17331 | -/* Return with empty ExtendedTags but add eccResult. |
| 17332 | +/* Return with empty ExtendedTags but add ecc_result. |
| 17333 | */ |
| 17334 | -static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval) |
| 17335 | +static int rettags(yaffs_ext_tags *etags, int ecc_result, int retval) |
| 17336 | { |
| 17337 | if (etags) { |
| 17338 | memset(etags, 0, sizeof(*etags)); |
| 17339 | - etags->eccResult = eccResult; |
| 17340 | + etags->ecc_result = ecc_result; |
| 17341 | } |
| 17342 | return retval; |
| 17343 | } |
| 17344 | @@ -158,30 +156,28 @@ static int rettags(yaffs_ExtendedTags *e |
| 17345 | /* Read a chunk (page) from NAND. |
| 17346 | * |
| 17347 | * Caller expects ExtendedTags data to be usable even on error; that is, |
| 17348 | - * all members except eccResult and blockBad are zeroed. |
| 17349 | + * all members except ecc_result and block_bad are zeroed. |
| 17350 | * |
| 17351 | * - Check ECC results for data (if applicable) |
| 17352 | * - Check for blank/erased block (return empty ExtendedTags if blank) |
| 17353 | * - Check the PackedTags1 mini-ECC (correct if necessary/possible) |
| 17354 | * - Convert PackedTags1 to ExtendedTags |
| 17355 | - * - Update eccResult and blockBad members to refect state. |
| 17356 | + * - Update ecc_result and block_bad members to refect state. |
| 17357 | * |
| 17358 | * Returns YAFFS_OK or YAFFS_FAIL. |
| 17359 | */ |
| 17360 | -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, |
| 17361 | - int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags) |
| 17362 | +int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, |
| 17363 | + int nand_chunk, __u8 *data, yaffs_ext_tags *etags) |
| 17364 | { |
| 17365 | - struct mtd_info *mtd = dev->genericDevice; |
| 17366 | - int chunkBytes = dev->nDataBytesPerChunk; |
| 17367 | - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; |
| 17368 | + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); |
| 17369 | + int chunkBytes = dev->data_bytes_per_chunk; |
| 17370 | + loff_t addr = ((loff_t)nand_chunk) * chunkBytes; |
| 17371 | int eccres = YAFFS_ECC_RESULT_NO_ERROR; |
| 17372 | struct mtd_oob_ops ops; |
| 17373 | yaffs_PackedTags1 pt1; |
| 17374 | int retval; |
| 17375 | int deleted; |
| 17376 | |
| 17377 | - dev->nPageReads++; |
| 17378 | - |
| 17379 | memset(&ops, 0, sizeof(ops)); |
| 17380 | ops.mode = MTD_OOB_AUTO; |
| 17381 | ops.len = (data) ? chunkBytes : 0; |
| 17382 | @@ -200,9 +196,9 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y |
| 17383 | */ |
| 17384 | retval = mtd->read_oob(mtd, addr, &ops); |
| 17385 | if (retval) { |
| 17386 | - yaffs_trace(YAFFS_TRACE_MTD, |
| 17387 | - "read_oob failed, chunk %d, mtd error %d\n", |
| 17388 | - chunkInNAND, retval); |
| 17389 | + T(YAFFS_TRACE_MTD, |
| 17390 | + (TSTR("read_oob failed, chunk %d, mtd error %d"TENDSTR), |
| 17391 | + nand_chunk, retval)); |
| 17392 | } |
| 17393 | |
| 17394 | switch (retval) { |
| 17395 | @@ -213,23 +209,23 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y |
| 17396 | case -EUCLEAN: |
| 17397 | /* MTD's ECC fixed the data */ |
| 17398 | eccres = YAFFS_ECC_RESULT_FIXED; |
| 17399 | - dev->eccFixed++; |
| 17400 | + dev->n_ecc_fixed++; |
| 17401 | break; |
| 17402 | |
| 17403 | case -EBADMSG: |
| 17404 | /* MTD's ECC could not fix the data */ |
| 17405 | - dev->eccUnfixed++; |
| 17406 | + dev->n_ecc_unfixed++; |
| 17407 | /* fall into... */ |
| 17408 | default: |
| 17409 | rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0); |
| 17410 | - etags->blockBad = (mtd->block_isbad)(mtd, addr); |
| 17411 | + etags->block_bad = (mtd->block_isbad)(mtd, addr); |
| 17412 | return YAFFS_FAIL; |
| 17413 | } |
| 17414 | |
| 17415 | /* Check for a blank/erased chunk. |
| 17416 | */ |
| 17417 | - if (yaffs_CheckFF((__u8 *)&pt1, 8)) { |
| 17418 | - /* when blank, upper layers want eccResult to be <= NO_ERROR */ |
| 17419 | + if (yaffs_check_ff((__u8 *)&pt1, 8)) { |
| 17420 | + /* when blank, upper layers want ecc_result to be <= NO_ERROR */ |
| 17421 | return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK); |
| 17422 | } |
| 17423 | |
| 17424 | @@ -241,37 +237,37 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y |
| 17425 | deleted = !pt1.deleted; |
| 17426 | pt1.deleted = 1; |
| 17427 | #else |
| 17428 | - deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7); |
| 17429 | + deleted = (yaffs_count_bits(((__u8 *)&pt1)[8]) < 7); |
| 17430 | #endif |
| 17431 | |
| 17432 | /* Check the packed tags mini-ECC and correct if necessary/possible. |
| 17433 | */ |
| 17434 | - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); |
| 17435 | + retval = yaffs_check_tags_ecc((yaffs_tags_t *)&pt1); |
| 17436 | switch (retval) { |
| 17437 | case 0: |
| 17438 | /* no tags error, use MTD result */ |
| 17439 | break; |
| 17440 | case 1: |
| 17441 | /* recovered tags-ECC error */ |
| 17442 | - dev->tagsEccFixed++; |
| 17443 | + dev->n_tags_ecc_fixed++; |
| 17444 | if (eccres == YAFFS_ECC_RESULT_NO_ERROR) |
| 17445 | eccres = YAFFS_ECC_RESULT_FIXED; |
| 17446 | break; |
| 17447 | default: |
| 17448 | /* unrecovered tags-ECC error */ |
| 17449 | - dev->tagsEccUnfixed++; |
| 17450 | + dev->n_tags_ecc_unfixed++; |
| 17451 | return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL); |
| 17452 | } |
| 17453 | |
| 17454 | /* Unpack the tags to extended form and set ECC result. |
| 17455 | - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy] |
| 17456 | + * [set shouldBeFF just to keep yaffs_unpack_tags1 happy] |
| 17457 | */ |
| 17458 | pt1.shouldBeFF = 0xFFFFFFFF; |
| 17459 | - yaffs_UnpackTags1(etags, &pt1); |
| 17460 | - etags->eccResult = eccres; |
| 17461 | + yaffs_unpack_tags1(etags, &pt1); |
| 17462 | + etags->ecc_result = eccres; |
| 17463 | |
| 17464 | /* Set deleted state */ |
| 17465 | - etags->chunkDeleted = deleted; |
| 17466 | + etags->is_deleted = deleted; |
| 17467 | return YAFFS_OK; |
| 17468 | } |
| 17469 | |
| 17470 | @@ -282,15 +278,15 @@ int nandmtd1_ReadChunkWithTagsFromNAND(y |
| 17471 | * |
| 17472 | * Returns YAFFS_OK or YAFFS_FAIL. |
| 17473 | */ |
| 17474 | -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) |
| 17475 | +int nandmtd1_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no) |
| 17476 | { |
| 17477 | - struct mtd_info *mtd = dev->genericDevice; |
| 17478 | - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; |
| 17479 | + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); |
| 17480 | + int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk; |
| 17481 | int retval; |
| 17482 | |
| 17483 | - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo); |
| 17484 | + T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("marking block %d bad"TENDSTR), block_no)); |
| 17485 | |
| 17486 | - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo); |
| 17487 | + retval = mtd->block_markbad(mtd, (loff_t)blocksize * block_no); |
| 17488 | return (retval) ? YAFFS_FAIL : YAFFS_OK; |
| 17489 | } |
| 17490 | |
| 17491 | @@ -305,9 +301,9 @@ static int nandmtd1_TestPrerequists(stru |
| 17492 | int oobavail = mtd->ecclayout->oobavail; |
| 17493 | |
| 17494 | if (oobavail < YTAG1_SIZE) { |
| 17495 | - yaffs_trace(YAFFS_TRACE_ERROR, |
| 17496 | - "mtd device has only %d bytes for tags, need %d\n", |
| 17497 | - oobavail, YTAG1_SIZE); |
| 17498 | + T(YAFFS_TRACE_ERROR, |
| 17499 | + (TSTR("mtd device has only %d bytes for tags, need %d"TENDSTR), |
| 17500 | + oobavail, YTAG1_SIZE)); |
| 17501 | return YAFFS_FAIL; |
| 17502 | } |
| 17503 | return YAFFS_OK; |
| 17504 | @@ -322,13 +318,13 @@ static int nandmtd1_TestPrerequists(stru |
| 17505 | * |
| 17506 | * Always returns YAFFS_OK. |
| 17507 | */ |
| 17508 | -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, |
| 17509 | - yaffs_BlockState *pState, __u32 *pSequenceNumber) |
| 17510 | +int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no, |
| 17511 | + yaffs_block_state_t *pState, __u32 *pSequenceNumber) |
| 17512 | { |
| 17513 | - struct mtd_info *mtd = dev->genericDevice; |
| 17514 | - int chunkNo = blockNo * dev->nChunksPerBlock; |
| 17515 | - loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk; |
| 17516 | - yaffs_ExtendedTags etags; |
| 17517 | + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); |
| 17518 | + int chunkNo = block_no * dev->param.chunks_per_block; |
| 17519 | + loff_t addr = (loff_t)chunkNo * dev->data_bytes_per_chunk; |
| 17520 | + yaffs_ext_tags etags; |
| 17521 | int state = YAFFS_BLOCK_STATE_DEAD; |
| 17522 | int seqnum = 0; |
| 17523 | int retval; |
| 17524 | @@ -340,17 +336,17 @@ int nandmtd1_QueryNANDBlock(struct yaffs |
| 17525 | return YAFFS_FAIL; |
| 17526 | |
| 17527 | retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); |
| 17528 | - etags.blockBad = (mtd->block_isbad)(mtd, addr); |
| 17529 | - if (etags.blockBad) { |
| 17530 | - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, |
| 17531 | - "block %d is marked bad\n", blockNo); |
| 17532 | + etags.block_bad = (mtd->block_isbad)(mtd, addr); |
| 17533 | + if (etags.block_bad) { |
| 17534 | + T(YAFFS_TRACE_BAD_BLOCKS, |
| 17535 | + (TSTR("block %d is marked bad"TENDSTR), block_no)); |
| 17536 | state = YAFFS_BLOCK_STATE_DEAD; |
| 17537 | - } else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) { |
| 17538 | + } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) { |
| 17539 | /* bad tags, need to look more closely */ |
| 17540 | state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; |
| 17541 | - } else if (etags.chunkUsed) { |
| 17542 | + } else if (etags.chunk_used) { |
| 17543 | state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; |
| 17544 | - seqnum = etags.sequenceNumber; |
| 17545 | + seqnum = etags.seq_number; |
| 17546 | } else { |
| 17547 | state = YAFFS_BLOCK_STATE_EMPTY; |
| 17548 | } |
| 17549 | --- a/fs/yaffs2/yaffs_mtdif1-compat.c |
| 17550 | +++ /dev/null |
| 17551 | @@ -1,434 +0,0 @@ |
| 17552 | -From ian@brightstareng.com Fri May 18 15:06:49 2007 |
| 17553 | -From ian@brightstareng.com Fri May 18 15:08:21 2007 |
| 17554 | -Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com) |
| 17555 | - by apollo.linkchoose.co.uk with esmtp (Exim 4.60) |
| 17556 | - (envelope-from <ian@brightstareng.com>) |
| 17557 | - id 1Hp380-00011e-T6 |
| 17558 | - for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100 |
| 17559 | -Received: from localhost (localhost.localdomain [127.0.0.1]) |
| 17560 | - by zebra.brightstareng.com (Postfix) with ESMTP |
| 17561 | - id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT) |
| 17562 | -Received: from zebra.brightstareng.com ([127.0.0.1]) |
| 17563 | - by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP |
| 17564 | - id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT) |
| 17565 | -Received: from pippin (unknown [192.168.1.25]) |
| 17566 | - by zebra.brightstareng.com (Postfix) with ESMTP |
| 17567 | - id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT) |
| 17568 | -From: Ian McDonnell <ian@brightstareng.com> |
| 17569 | -To: David Goodenough <david.goodenough@linkchoose.co.uk> |
| 17570 | -Subject: Re: something tested this time -- yaffs_mtdif1-compat.c |
| 17571 | -Date: Fri, 18 May 2007 10:06:49 -0400 |
| 17572 | -User-Agent: KMail/1.9.1 |
| 17573 | -References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk> |
| 17574 | -In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk> |
| 17575 | -Cc: Andrea Conti <alyf@alyf.net>, |
| 17576 | - Charles Manning <manningc2@actrix.gen.nz> |
| 17577 | -MIME-Version: 1.0 |
| 17578 | -Content-Type: Multipart/Mixed; |
| 17579 | - boundary="Boundary-00=_5LbTGmt62YoutxM" |
| 17580 | -Message-Id: <200705181006.49860.ian@brightstareng.com> |
| 17581 | -X-Virus-Scanned: by amavisd-new at brightstareng.com |
| 17582 | -Status: R |
| 17583 | -X-Status: NT |
| 17584 | -X-KMail-EncryptionState: |
| 17585 | -X-KMail-SignatureState: |
| 17586 | -X-KMail-MDN-Sent: |
| 17587 | - |
| 17588 | ---Boundary-00=_5LbTGmt62YoutxM |
| 17589 | -Content-Type: text/plain; |
| 17590 | - charset="iso-8859-15" |
| 17591 | -Content-Transfer-Encoding: 7bit |
| 17592 | -Content-Disposition: inline |
| 17593 | - |
| 17594 | -David, Andrea, |
| 17595 | - |
| 17596 | -On Friday 18 May 2007 08:34, you wrote: |
| 17597 | -> Yea team. With this fix in place (I put it in the wrong place |
| 17598 | -> at first) I can now mount and ls the Yaffs partition without |
| 17599 | -> an error messages! |
| 17600 | - |
| 17601 | -Good news! |
| 17602 | - |
| 17603 | -Attached is a newer yaffs_mtdif1.c with a bandaid to help the |
| 17604 | -2.6.18 and 2.6.19 versions of MTD not trip on the oob read. |
| 17605 | -See the LINUX_VERSION_CODE conditional in |
| 17606 | -nandmtd1_ReadChunkWithTagsFromNAND. |
| 17607 | - |
| 17608 | --imcd |
| 17609 | - |
| 17610 | ---Boundary-00=_5LbTGmt62YoutxM |
| 17611 | -Content-Type: text/x-csrc; |
| 17612 | - charset="iso-8859-15"; |
| 17613 | - name="yaffs_mtdif1.c" |
| 17614 | -Content-Transfer-Encoding: 7bit |
| 17615 | -Content-Disposition: attachment; |
| 17616 | - filename="yaffs_mtdif1.c" |
| 17617 | - |
| 17618 | -/* |
| 17619 | - * YAFFS: Yet another FFS. A NAND-flash specific file system. |
| 17620 | - * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND. |
| 17621 | - * |
| 17622 | - * Copyright (C) 2002 Aleph One Ltd. |
| 17623 | - * for Toby Churchill Ltd and Brightstar Engineering |
| 17624 | - * |
| 17625 | - * This program is free software; you can redistribute it and/or modify |
| 17626 | - * it under the terms of the GNU General Public License version 2 as |
| 17627 | - * published by the Free Software Foundation. |
| 17628 | - */ |
| 17629 | - |
| 17630 | -/* |
| 17631 | - * This module provides the interface between yaffs_nand.c and the |
| 17632 | - * MTD API. This version is used when the MTD interface supports the |
| 17633 | - * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17, |
| 17634 | - * and we have small-page NAND device. |
| 17635 | - * |
| 17636 | - * These functions are invoked via function pointers in yaffs_nand.c. |
| 17637 | - * This replaces functionality provided by functions in yaffs_mtdif.c |
| 17638 | - * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are |
| 17639 | - * called in yaffs_mtdif.c when the function pointers are NULL. |
| 17640 | - * We assume the MTD layer is performing ECC (useNANDECC is true). |
| 17641 | - */ |
| 17642 | - |
| 17643 | -#include "yportenv.h" |
| 17644 | -#include "yaffs_guts.h" |
| 17645 | -#include "yaffs_packedtags1.h" |
| 17646 | -#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC |
| 17647 | - |
| 17648 | -#include "linux/kernel.h" |
| 17649 | -#include "linux/version.h" |
| 17650 | -#include "linux/types.h" |
| 17651 | -#include "linux/mtd/mtd.h" |
| 17652 | - |
| 17653 | -/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */ |
| 17654 | -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) |
| 17655 | - |
| 17656 | -const char *yaffs_mtdif1_c_version = "$Id$"; |
| 17657 | - |
| 17658 | -#ifndef CONFIG_YAFFS_9BYTE_TAGS |
| 17659 | -# define YTAG1_SIZE 8 |
| 17660 | -#else |
| 17661 | -# define YTAG1_SIZE 9 |
| 17662 | -#endif |
| 17663 | - |
| 17664 | -#if 0 |
| 17665 | -/* Use the following nand_ecclayout with MTD when using |
| 17666 | - * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout. |
| 17667 | - * If you have existing Yaffs images and the byte order differs from this, |
| 17668 | - * adjust 'oobfree' to match your existing Yaffs data. |
| 17669 | - * |
| 17670 | - * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the |
| 17671 | - * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to |
| 17672 | - * the 9th byte. |
| 17673 | - * |
| 17674 | - * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5 |
| 17675 | - * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P |
| 17676 | - * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus |
| 17677 | - * byte and B is the small-page bad-block indicator byte. |
| 17678 | - */ |
| 17679 | -static struct nand_ecclayout nand_oob_16 = { |
| 17680 | - .eccbytes = 6, |
| 17681 | - .eccpos = { 8, 9, 10, 13, 14, 15 }, |
| 17682 | - .oobavail = 9, |
| 17683 | - .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } } |
| 17684 | -}; |
| 17685 | -#endif |
| 17686 | - |
| 17687 | -/* Write a chunk (page) of data to NAND. |
| 17688 | - * |
| 17689 | - * Caller always provides ExtendedTags data which are converted to a more |
| 17690 | - * compact (packed) form for storage in NAND. A mini-ECC runs over the |
| 17691 | - * contents of the tags meta-data; used to valid the tags when read. |
| 17692 | - * |
| 17693 | - * - Pack ExtendedTags to PackedTags1 form |
| 17694 | - * - Compute mini-ECC for PackedTags1 |
| 17695 | - * - Write data and packed tags to NAND. |
| 17696 | - * |
| 17697 | - * Note: Due to the use of the PackedTags1 meta-data which does not include |
| 17698 | - * a full sequence number (as found in the larger PackedTags2 form) it is |
| 17699 | - * necessary for Yaffs to re-write a chunk/page (just once) to mark it as |
| 17700 | - * discarded and dirty. This is not ideal: newer NAND parts are supposed |
| 17701 | - * to be written just once. When Yaffs performs this operation, this |
| 17702 | - * function is called with a NULL data pointer -- calling MTD write_oob |
| 17703 | - * without data is valid usage (2.6.17). |
| 17704 | - * |
| 17705 | - * Any underlying MTD error results in YAFFS_FAIL. |
| 17706 | - * Returns YAFFS_OK or YAFFS_FAIL. |
| 17707 | - */ |
| 17708 | -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, |
| 17709 | - int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags) |
| 17710 | -{ |
| 17711 | - struct mtd_info * mtd = dev->genericDevice; |
| 17712 | - int chunkBytes = dev->nDataBytesPerChunk; |
| 17713 | - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; |
| 17714 | - struct mtd_oob_ops ops; |
| 17715 | - yaffs_PackedTags1 pt1; |
| 17716 | - int retval; |
| 17717 | - |
| 17718 | - /* we assume that PackedTags1 and yaffs_Tags are compatible */ |
| 17719 | - compile_time_assertion(sizeof(yaffs_PackedTags1) == 12); |
| 17720 | - compile_time_assertion(sizeof(yaffs_Tags) == 8); |
| 17721 | - |
| 17722 | - yaffs_PackTags1(&pt1, etags); |
| 17723 | - yaffs_CalcTagsECC((yaffs_Tags *)&pt1); |
| 17724 | - |
| 17725 | - /* When deleting a chunk, the upper layer provides only skeletal |
| 17726 | - * etags, one with chunkDeleted set. However, we need to update the |
| 17727 | - * tags, not erase them completely. So we use the NAND write property |
| 17728 | - * that only zeroed-bits stick and set tag bytes to all-ones and |
| 17729 | - * zero just the (not) deleted bit. |
| 17730 | - */ |
| 17731 | -#ifndef CONFIG_YAFFS_9BYTE_TAGS |
| 17732 | - if (etags->chunkDeleted) { |
| 17733 | - memset(&pt1, 0xff, 8); |
| 17734 | - /* clear delete status bit to indicate deleted */ |
| 17735 | - pt1.deleted = 0; |
| 17736 | - } |
| 17737 | -#else |
| 17738 | - ((__u8 *)&pt1)[8] = 0xff; |
| 17739 | - if (etags->chunkDeleted) { |
| 17740 | - memset(&pt1, 0xff, 8); |
| 17741 | - /* zero pageStatus byte to indicate deleted */ |
| 17742 | - ((__u8 *)&pt1)[8] = 0; |
| 17743 | - } |
| 17744 | -#endif |
| 17745 | - |
| 17746 | - memset(&ops, 0, sizeof(ops)); |
| 17747 | - ops.mode = MTD_OOB_AUTO; |
| 17748 | - ops.len = (data) ? chunkBytes : 0; |
| 17749 | - ops.ooblen = YTAG1_SIZE; |
| 17750 | - ops.datbuf = (__u8 *)data; |
| 17751 | - ops.oobbuf = (__u8 *)&pt1; |
| 17752 | - |
| 17753 | - retval = mtd->write_oob(mtd, addr, &ops); |
| 17754 | - if (retval) { |
| 17755 | - yaffs_trace(YAFFS_TRACE_MTD, |
| 17756 | - "write_oob failed, chunk %d, mtd error %d\n", |
| 17757 | - chunkInNAND, retval); |
| 17758 | - } |
| 17759 | - return retval ? YAFFS_FAIL : YAFFS_OK; |
| 17760 | -} |
| 17761 | - |
| 17762 | -/* Return with empty ExtendedTags but add eccResult. |
| 17763 | - */ |
| 17764 | -static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval) |
| 17765 | -{ |
| 17766 | - if (etags) { |
| 17767 | - memset(etags, 0, sizeof(*etags)); |
| 17768 | - etags->eccResult = eccResult; |
| 17769 | - } |
| 17770 | - return retval; |
| 17771 | -} |
| 17772 | - |
| 17773 | -/* Read a chunk (page) from NAND. |
| 17774 | - * |
| 17775 | - * Caller expects ExtendedTags data to be usable even on error; that is, |
| 17776 | - * all members except eccResult and blockBad are zeroed. |
| 17777 | - * |
| 17778 | - * - Check ECC results for data (if applicable) |
| 17779 | - * - Check for blank/erased block (return empty ExtendedTags if blank) |
| 17780 | - * - Check the PackedTags1 mini-ECC (correct if necessary/possible) |
| 17781 | - * - Convert PackedTags1 to ExtendedTags |
| 17782 | - * - Update eccResult and blockBad members to refect state. |
| 17783 | - * |
| 17784 | - * Returns YAFFS_OK or YAFFS_FAIL. |
| 17785 | - */ |
| 17786 | -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, |
| 17787 | - int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags) |
| 17788 | -{ |
| 17789 | - struct mtd_info * mtd = dev->genericDevice; |
| 17790 | - int chunkBytes = dev->nDataBytesPerChunk; |
| 17791 | - loff_t addr = ((loff_t)chunkInNAND) * chunkBytes; |
| 17792 | - int eccres = YAFFS_ECC_RESULT_NO_ERROR; |
| 17793 | - struct mtd_oob_ops ops; |
| 17794 | - yaffs_PackedTags1 pt1; |
| 17795 | - int retval; |
| 17796 | - int deleted; |
| 17797 | - |
| 17798 | - memset(&ops, 0, sizeof(ops)); |
| 17799 | - ops.mode = MTD_OOB_AUTO; |
| 17800 | - ops.len = (data) ? chunkBytes : 0; |
| 17801 | - ops.ooblen = YTAG1_SIZE; |
| 17802 | - ops.datbuf = data; |
| 17803 | - ops.oobbuf = (__u8 *)&pt1; |
| 17804 | - |
| 17805 | -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) |
| 17806 | - /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug; |
| 17807 | - * help it out with ops.len = ops.ooblen when ops.datbuf == NULL. |
| 17808 | - */ |
| 17809 | - ops.len = (ops.datbuf) ? ops.len : ops.ooblen; |
| 17810 | -#endif |
| 17811 | - /* Read page and oob using MTD. |
| 17812 | - * Check status and determine ECC result. |
| 17813 | - */ |
| 17814 | - retval = mtd->read_oob(mtd, addr, &ops); |
| 17815 | - if (retval) { |
| 17816 | - yaffs_trace(YAFFS_TRACE_MTD, |
| 17817 | - "read_oob failed, chunk %d, mtd error %d\n", |
| 17818 | - chunkInNAND, retval); |
| 17819 | - } |
| 17820 | - |
| 17821 | - switch (retval) { |
| 17822 | - case 0: |
| 17823 | - /* no error */ |
| 17824 | - break; |
| 17825 | - |
| 17826 | - case -EUCLEAN: |
| 17827 | - /* MTD's ECC fixed the data */ |
| 17828 | - eccres = YAFFS_ECC_RESULT_FIXED; |
| 17829 | - dev->eccFixed++; |
| 17830 | - break; |
| 17831 | - |
| 17832 | - case -EBADMSG: |
| 17833 | - /* MTD's ECC could not fix the data */ |
| 17834 | - dev->eccUnfixed++; |
| 17835 | - /* fall into... */ |
| 17836 | - default: |
| 17837 | - rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0); |
| 17838 | - etags->blockBad = (mtd->block_isbad)(mtd, addr); |
| 17839 | - return YAFFS_FAIL; |
| 17840 | - } |
| 17841 | - |
| 17842 | - /* Check for a blank/erased chunk. |
| 17843 | - */ |
| 17844 | - if (yaffs_CheckFF((__u8 *)&pt1, 8)) { |
| 17845 | - /* when blank, upper layers want eccResult to be <= NO_ERROR */ |
| 17846 | - return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK); |
| 17847 | - } |
| 17848 | - |
| 17849 | -#ifndef CONFIG_YAFFS_9BYTE_TAGS |
| 17850 | - /* Read deleted status (bit) then return it to it's non-deleted |
| 17851 | - * state before performing tags mini-ECC check. pt1.deleted is |
| 17852 | - * inverted. |
| 17853 | - */ |
| 17854 | - deleted = !pt1.deleted; |
| 17855 | - pt1.deleted = 1; |
| 17856 | -#else |
| 17857 | - (void) deleted; /* not used */ |
| 17858 | -#endif |
| 17859 | - |
| 17860 | - /* Check the packed tags mini-ECC and correct if necessary/possible. |
| 17861 | - */ |
| 17862 | - retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1); |
| 17863 | - switch (retval) { |
| 17864 | - case 0: |
| 17865 | - /* no tags error, use MTD result */ |
| 17866 | - break; |
| 17867 | - case 1: |
| 17868 | - /* recovered tags-ECC error */ |
| 17869 | - dev->tagsEccFixed++; |
| 17870 | - eccres = YAFFS_ECC_RESULT_FIXED; |
| 17871 | - break; |
| 17872 | - default: |
| 17873 | - /* unrecovered tags-ECC error */ |
| 17874 | - dev->tagsEccUnfixed++; |
| 17875 | - return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL); |
| 17876 | - } |
| 17877 | - |
| 17878 | - /* Unpack the tags to extended form and set ECC result. |
| 17879 | - * [set shouldBeFF just to keep yaffs_UnpackTags1 happy] |
| 17880 | - */ |
| 17881 | - pt1.shouldBeFF = 0xFFFFFFFF; |
| 17882 | - yaffs_UnpackTags1(etags, &pt1); |
| 17883 | - etags->eccResult = eccres; |
| 17884 | - |
| 17885 | - /* Set deleted state. |
| 17886 | - */ |
| 17887 | -#ifndef CONFIG_YAFFS_9BYTE_TAGS |
| 17888 | - etags->chunkDeleted = deleted; |
| 17889 | -#else |
| 17890 | - etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7); |
| 17891 | -#endif |
| 17892 | - return YAFFS_OK; |
| 17893 | -} |
| 17894 | - |
| 17895 | -/* Mark a block bad. |
| 17896 | - * |
| 17897 | - * This is a persistant state. |
| 17898 | - * Use of this function should be rare. |
| 17899 | - * |
| 17900 | - * Returns YAFFS_OK or YAFFS_FAIL. |
| 17901 | - */ |
| 17902 | -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) |
| 17903 | -{ |
| 17904 | - struct mtd_info * mtd = dev->genericDevice; |
| 17905 | - int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk; |
| 17906 | - int retval; |
| 17907 | - |
| 17908 | - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo); |
| 17909 | - |
| 17910 | - retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo); |
| 17911 | - return (retval) ? YAFFS_FAIL : YAFFS_OK; |
| 17912 | -} |
| 17913 | - |
| 17914 | -/* Check any MTD prerequists. |
| 17915 | - * |
| 17916 | - * Returns YAFFS_OK or YAFFS_FAIL. |
| 17917 | - */ |
| 17918 | -static int nandmtd1_TestPrerequists(struct mtd_info * mtd) |
| 17919 | -{ |
| 17920 | - /* 2.6.18 has mtd->ecclayout->oobavail */ |
| 17921 | - /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */ |
| 17922 | - int oobavail = mtd->ecclayout->oobavail; |
| 17923 | - |
| 17924 | - if (oobavail < YTAG1_SIZE) { |
| 17925 | - yaffs_trace(YAFFS_TRACE_ERROR, |
| 17926 | - "mtd device has only %d bytes for tags, need %d", |
| 17927 | - oobavail, YTAG1_SIZE); |
| 17928 | - return YAFFS_FAIL; |
| 17929 | - } |
| 17930 | - return YAFFS_OK; |
| 17931 | -} |
| 17932 | - |
| 17933 | -/* Query for the current state of a specific block. |
| 17934 | - * |
| 17935 | - * Examine the tags of the first chunk of the block and return the state: |
| 17936 | - * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad |
| 17937 | - * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use |
| 17938 | - * - YAFFS_BLOCK_STATE_EMPTY, the block is clean |
| 17939 | - * |
| 17940 | - * Always returns YAFFS_OK. |
| 17941 | - */ |
| 17942 | -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, |
| 17943 | - yaffs_BlockState * pState, int *pSequenceNumber) |
| 17944 | -{ |
| 17945 | - struct mtd_info * mtd = dev->genericDevice; |
| 17946 | - int chunkNo = blockNo * dev->nChunksPerBlock; |
| 17947 | - yaffs_ExtendedTags etags; |
| 17948 | - int state = YAFFS_BLOCK_STATE_DEAD; |
| 17949 | - int seqnum = 0; |
| 17950 | - int retval; |
| 17951 | - |
| 17952 | - /* We don't yet have a good place to test for MTD config prerequists. |
| 17953 | - * Do it here as we are called during the initial scan. |
| 17954 | - */ |
| 17955 | - if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) { |
| 17956 | - return YAFFS_FAIL; |
| 17957 | - } |
| 17958 | - |
| 17959 | - retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags); |
| 17960 | - if (etags.blockBad) { |
| 17961 | - yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, |
| 17962 | - "block %d is marked bad", blockNo); |
| 17963 | - state = YAFFS_BLOCK_STATE_DEAD; |
| 17964 | - } |
| 17965 | - else if (etags.chunkUsed) { |
| 17966 | - state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; |
| 17967 | - seqnum = etags.sequenceNumber; |
| 17968 | - } |
| 17969 | - else { |
| 17970 | - state = YAFFS_BLOCK_STATE_EMPTY; |
| 17971 | - } |
| 17972 | - |
| 17973 | - *pState = state; |
| 17974 | - *pSequenceNumber = seqnum; |
| 17975 | - |
| 17976 | - /* query always succeeds */ |
| 17977 | - return YAFFS_OK; |
| 17978 | -} |
| 17979 | - |
| 17980 | -#endif /*KERNEL_VERSION*/ |
| 17981 | - |
| 17982 | ---Boundary-00=_5LbTGmt62YoutxM-- |
| 17983 | - |
| 17984 | - |
| 17985 | - |
| 17986 | --- a/fs/yaffs2/yaffs_mtdif1.h |
| 17987 | +++ b/fs/yaffs2/yaffs_mtdif1.h |
| 17988 | @@ -1,7 +1,7 @@ |
| 17989 | /* |
| 17990 | * YAFFS: Yet another Flash File System. A NAND-flash specific file system. |
| 17991 | * |
| 17992 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 17993 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 17994 | * for Toby Churchill Ltd and Brightstar Engineering |
| 17995 | * |
| 17996 | * This program is free software; you can redistribute it and/or modify |
| 17997 | @@ -14,15 +14,15 @@ |
| 17998 | #ifndef __YAFFS_MTDIF1_H__ |
| 17999 | #define __YAFFS_MTDIF1_H__ |
| 18000 | |
| 18001 | -int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, |
| 18002 | - const __u8 *data, const yaffs_ExtendedTags *tags); |
| 18003 | +int nandmtd1_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk, |
| 18004 | + const __u8 *data, const yaffs_ext_tags *tags); |
| 18005 | |
| 18006 | -int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, |
| 18007 | - __u8 *data, yaffs_ExtendedTags *tags); |
| 18008 | +int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk, |
| 18009 | + __u8 *data, yaffs_ext_tags *tags); |
| 18010 | |
| 18011 | -int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); |
| 18012 | +int nandmtd1_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no); |
| 18013 | |
| 18014 | -int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, |
| 18015 | - yaffs_BlockState *state, __u32 *sequenceNumber); |
| 18016 | +int nandmtd1_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no, |
| 18017 | + yaffs_block_state_t *state, __u32 *seq_number); |
| 18018 | |
| 18019 | #endif |
| 18020 | --- a/fs/yaffs2/yaffs_mtdif2.c |
| 18021 | +++ b/fs/yaffs2/yaffs_mtdif2.c |
| 18022 | @@ -1,7 +1,7 @@ |
| 18023 | /* |
| 18024 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 18025 | * |
| 18026 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 18027 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 18028 | * for Toby Churchill Ltd and Brightstar Engineering |
| 18029 | * |
| 18030 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 18031 | @@ -13,11 +13,8 @@ |
| 18032 | |
| 18033 | /* mtd interface for YAFFS2 */ |
| 18034 | |
| 18035 | -const char *yaffs_mtdif2_c_version = |
| 18036 | - "$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $"; |
| 18037 | - |
| 18038 | #include "yportenv.h" |
| 18039 | - |
| 18040 | +#include "yaffs_trace.h" |
| 18041 | |
| 18042 | #include "yaffs_mtdif2.h" |
| 18043 | |
| 18044 | @@ -27,15 +24,17 @@ const char *yaffs_mtdif2_c_version = |
| 18045 | |
| 18046 | #include "yaffs_packedtags2.h" |
| 18047 | |
| 18048 | +#include "yaffs_linux.h" |
| 18049 | + |
| 18050 | /* NB For use with inband tags.... |
| 18051 | * We assume that the data buffer is of size totalBytersPerChunk so that we can also |
| 18052 | * use it to load the tags. |
| 18053 | */ |
| 18054 | -int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, |
| 18055 | +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk, |
| 18056 | const __u8 *data, |
| 18057 | - const yaffs_ExtendedTags *tags) |
| 18058 | + const yaffs_ext_tags *tags) |
| 18059 | { |
| 18060 | - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
| 18061 | + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); |
| 18062 | #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) |
| 18063 | struct mtd_oob_ops ops; |
| 18064 | #else |
| 18065 | @@ -47,13 +46,16 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya |
| 18066 | |
| 18067 | yaffs_PackedTags2 pt; |
| 18068 | |
| 18069 | + int packed_tags_size = dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); |
| 18070 | + void * packed_tags_ptr = dev->param.no_tags_ecc ? (void *) &pt.t : (void *)&pt; |
| 18071 | + |
| 18072 | T(YAFFS_TRACE_MTD, |
| 18073 | (TSTR |
| 18074 | ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" |
| 18075 | - TENDSTR), chunkInNAND, data, tags)); |
| 18076 | + TENDSTR), nand_chunk, data, tags)); |
| 18077 | |
| 18078 | |
| 18079 | - addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; |
| 18080 | + addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; |
| 18081 | |
| 18082 | /* For yaffs2 writing there must be both data and tags. |
| 18083 | * If we're using inband tags, then the tags are stuffed into |
| 18084 | @@ -61,30 +63,30 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya |
| 18085 | */ |
| 18086 | if (!data || !tags) |
| 18087 | BUG(); |
| 18088 | - else if (dev->inbandTags) { |
| 18089 | + else if (dev->param.inband_tags) { |
| 18090 | yaffs_PackedTags2TagsPart *pt2tp; |
| 18091 | - pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk); |
| 18092 | + pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->data_bytes_per_chunk); |
| 18093 | yaffs_PackTags2TagsPart(pt2tp, tags); |
| 18094 | } else |
| 18095 | - yaffs_PackTags2(&pt, tags); |
| 18096 | + yaffs_PackTags2(&pt, tags, !dev->param.no_tags_ecc); |
| 18097 | |
| 18098 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 18099 | ops.mode = MTD_OOB_AUTO; |
| 18100 | - ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt); |
| 18101 | - ops.len = dev->totalBytesPerChunk; |
| 18102 | + ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size; |
| 18103 | + ops.len = dev->param.total_bytes_per_chunk; |
| 18104 | ops.ooboffs = 0; |
| 18105 | ops.datbuf = (__u8 *)data; |
| 18106 | - ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt; |
| 18107 | + ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr; |
| 18108 | retval = mtd->write_oob(mtd, addr, &ops); |
| 18109 | |
| 18110 | #else |
| 18111 | - if (!dev->inbandTags) { |
| 18112 | + if (!dev->param.inband_tags) { |
| 18113 | retval = |
| 18114 | - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, |
| 18115 | - &dummy, data, (__u8 *) &pt, NULL); |
| 18116 | + mtd->write_ecc(mtd, addr, dev->data_bytes_per_chunk, |
| 18117 | + &dummy, data, (__u8 *) packed_tags_ptr, NULL); |
| 18118 | } else { |
| 18119 | retval = |
| 18120 | - mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy, |
| 18121 | + mtd->write(mtd, addr, dev->param.total_bytes_per_chunk, &dummy, |
| 18122 | data); |
| 18123 | } |
| 18124 | #endif |
| 18125 | @@ -95,10 +97,10 @@ int nandmtd2_WriteChunkWithTagsToNAND(ya |
| 18126 | return YAFFS_FAIL; |
| 18127 | } |
| 18128 | |
| 18129 | -int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, |
| 18130 | - __u8 *data, yaffs_ExtendedTags *tags) |
| 18131 | +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk, |
| 18132 | + __u8 *data, yaffs_ext_tags *tags) |
| 18133 | { |
| 18134 | - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
| 18135 | + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); |
| 18136 | #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) |
| 18137 | struct mtd_oob_ops ops; |
| 18138 | #endif |
| 18139 | @@ -106,20 +108,23 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y |
| 18140 | int retval = 0; |
| 18141 | int localData = 0; |
| 18142 | |
| 18143 | - loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk; |
| 18144 | + loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk; |
| 18145 | |
| 18146 | yaffs_PackedTags2 pt; |
| 18147 | |
| 18148 | + int packed_tags_size = dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt); |
| 18149 | + void * packed_tags_ptr = dev->param.no_tags_ecc ? (void *) &pt.t: (void *)&pt; |
| 18150 | + |
| 18151 | T(YAFFS_TRACE_MTD, |
| 18152 | (TSTR |
| 18153 | ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p" |
| 18154 | - TENDSTR), chunkInNAND, data, tags)); |
| 18155 | + TENDSTR), nand_chunk, data, tags)); |
| 18156 | |
| 18157 | - if (dev->inbandTags) { |
| 18158 | + if (dev->param.inband_tags) { |
| 18159 | |
| 18160 | if (!data) { |
| 18161 | localData = 1; |
| 18162 | - data = yaffs_GetTempBuffer(dev, __LINE__); |
| 18163 | + data = yaffs_get_temp_buffer(dev, __LINE__); |
| 18164 | } |
| 18165 | |
| 18166 | |
| 18167 | @@ -127,30 +132,30 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y |
| 18168 | |
| 18169 | |
| 18170 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 18171 | - if (dev->inbandTags || (data && !tags)) |
| 18172 | - retval = mtd->read(mtd, addr, dev->totalBytesPerChunk, |
| 18173 | + if (dev->param.inband_tags || (data && !tags)) |
| 18174 | + retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk, |
| 18175 | &dummy, data); |
| 18176 | else if (tags) { |
| 18177 | ops.mode = MTD_OOB_AUTO; |
| 18178 | - ops.ooblen = sizeof(pt); |
| 18179 | - ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt); |
| 18180 | + ops.ooblen = packed_tags_size; |
| 18181 | + ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size; |
| 18182 | ops.ooboffs = 0; |
| 18183 | ops.datbuf = data; |
| 18184 | - ops.oobbuf = dev->spareBuffer; |
| 18185 | + ops.oobbuf = yaffs_dev_to_lc(dev)->spareBuffer; |
| 18186 | retval = mtd->read_oob(mtd, addr, &ops); |
| 18187 | } |
| 18188 | #else |
| 18189 | - if (!dev->inbandTags && data && tags) { |
| 18190 | + if (!dev->param.inband_tags && data && tags) { |
| 18191 | |
| 18192 | - retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, |
| 18193 | + retval = mtd->read_ecc(mtd, addr, dev->data_bytes_per_chunk, |
| 18194 | &dummy, data, dev->spareBuffer, |
| 18195 | NULL); |
| 18196 | } else { |
| 18197 | if (data) |
| 18198 | retval = |
| 18199 | - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, |
| 18200 | + mtd->read(mtd, addr, dev->data_bytes_per_chunk, &dummy, |
| 18201 | data); |
| 18202 | - if (!dev->inbandTags && tags) |
| 18203 | + if (!dev->param.inband_tags && tags) |
| 18204 | retval = |
| 18205 | mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, |
| 18206 | dev->spareBuffer); |
| 18207 | @@ -158,41 +163,47 @@ int nandmtd2_ReadChunkWithTagsFromNAND(y |
| 18208 | #endif |
| 18209 | |
| 18210 | |
| 18211 | - if (dev->inbandTags) { |
| 18212 | + if (dev->param.inband_tags) { |
| 18213 | if (tags) { |
| 18214 | yaffs_PackedTags2TagsPart *pt2tp; |
| 18215 | - pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk]; |
| 18216 | - yaffs_UnpackTags2TagsPart(tags, pt2tp); |
| 18217 | + pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->data_bytes_per_chunk]; |
| 18218 | + yaffs_unpack_tags2tags_part(tags, pt2tp); |
| 18219 | } |
| 18220 | } else { |
| 18221 | if (tags) { |
| 18222 | - memcpy(&pt, dev->spareBuffer, sizeof(pt)); |
| 18223 | - yaffs_UnpackTags2(tags, &pt); |
| 18224 | + memcpy(packed_tags_ptr, yaffs_dev_to_lc(dev)->spareBuffer, packed_tags_size); |
| 18225 | + yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc); |
| 18226 | } |
| 18227 | } |
| 18228 | |
| 18229 | if (localData) |
| 18230 | - yaffs_ReleaseTempBuffer(dev, data, __LINE__); |
| 18231 | + yaffs_release_temp_buffer(dev, data, __LINE__); |
| 18232 | |
| 18233 | - if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) |
| 18234 | - tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; |
| 18235 | + if (tags && retval == -EBADMSG && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) { |
| 18236 | + tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED; |
| 18237 | + dev->n_ecc_unfixed++; |
| 18238 | + } |
| 18239 | + if(tags && retval == -EUCLEAN && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) { |
| 18240 | + tags->ecc_result = YAFFS_ECC_RESULT_FIXED; |
| 18241 | + dev->n_ecc_fixed++; |
| 18242 | + } |
| 18243 | if (retval == 0) |
| 18244 | return YAFFS_OK; |
| 18245 | else |
| 18246 | return YAFFS_FAIL; |
| 18247 | } |
| 18248 | |
| 18249 | -int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) |
| 18250 | +int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no) |
| 18251 | { |
| 18252 | - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
| 18253 | + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); |
| 18254 | int retval; |
| 18255 | T(YAFFS_TRACE_MTD, |
| 18256 | - (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo)); |
| 18257 | + (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), block_no)); |
| 18258 | |
| 18259 | retval = |
| 18260 | mtd->block_markbad(mtd, |
| 18261 | - blockNo * dev->nChunksPerBlock * |
| 18262 | - dev->totalBytesPerChunk); |
| 18263 | + block_no * dev->param.chunks_per_block * |
| 18264 | + dev->param.total_bytes_per_chunk); |
| 18265 | |
| 18266 | if (retval == 0) |
| 18267 | return YAFFS_OK; |
| 18268 | @@ -201,41 +212,41 @@ int nandmtd2_MarkNANDBlockBad(struct yaf |
| 18269 | |
| 18270 | } |
| 18271 | |
| 18272 | -int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, |
| 18273 | - yaffs_BlockState *state, __u32 *sequenceNumber) |
| 18274 | +int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no, |
| 18275 | + yaffs_block_state_t *state, __u32 *seq_number) |
| 18276 | { |
| 18277 | - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
| 18278 | + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); |
| 18279 | int retval; |
| 18280 | |
| 18281 | T(YAFFS_TRACE_MTD, |
| 18282 | - (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); |
| 18283 | + (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), block_no)); |
| 18284 | retval = |
| 18285 | mtd->block_isbad(mtd, |
| 18286 | - blockNo * dev->nChunksPerBlock * |
| 18287 | - dev->totalBytesPerChunk); |
| 18288 | + block_no * dev->param.chunks_per_block * |
| 18289 | + dev->param.total_bytes_per_chunk); |
| 18290 | |
| 18291 | if (retval) { |
| 18292 | T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); |
| 18293 | |
| 18294 | *state = YAFFS_BLOCK_STATE_DEAD; |
| 18295 | - *sequenceNumber = 0; |
| 18296 | + *seq_number = 0; |
| 18297 | } else { |
| 18298 | - yaffs_ExtendedTags t; |
| 18299 | + yaffs_ext_tags t; |
| 18300 | nandmtd2_ReadChunkWithTagsFromNAND(dev, |
| 18301 | - blockNo * |
| 18302 | - dev->nChunksPerBlock, NULL, |
| 18303 | + block_no * |
| 18304 | + dev->param.chunks_per_block, NULL, |
| 18305 | &t); |
| 18306 | |
| 18307 | - if (t.chunkUsed) { |
| 18308 | - *sequenceNumber = t.sequenceNumber; |
| 18309 | + if (t.chunk_used) { |
| 18310 | + *seq_number = t.seq_number; |
| 18311 | *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; |
| 18312 | } else { |
| 18313 | - *sequenceNumber = 0; |
| 18314 | + *seq_number = 0; |
| 18315 | *state = YAFFS_BLOCK_STATE_EMPTY; |
| 18316 | } |
| 18317 | } |
| 18318 | T(YAFFS_TRACE_MTD, |
| 18319 | - (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber, |
| 18320 | + (TSTR("block is bad seq %d state %d" TENDSTR), *seq_number, |
| 18321 | *state)); |
| 18322 | |
| 18323 | if (retval == 0) |
| 18324 | --- a/fs/yaffs2/yaffs_mtdif2.h |
| 18325 | +++ b/fs/yaffs2/yaffs_mtdif2.h |
| 18326 | @@ -1,7 +1,7 @@ |
| 18327 | /* |
| 18328 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 18329 | * |
| 18330 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 18331 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 18332 | * for Toby Churchill Ltd and Brightstar Engineering |
| 18333 | * |
| 18334 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 18335 | @@ -17,13 +17,13 @@ |
| 18336 | #define __YAFFS_MTDIF2_H__ |
| 18337 | |
| 18338 | #include "yaffs_guts.h" |
| 18339 | -int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND, |
| 18340 | +int nandmtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int nand_chunk, |
| 18341 | const __u8 *data, |
| 18342 | - const yaffs_ExtendedTags *tags); |
| 18343 | -int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, |
| 18344 | - __u8 *data, yaffs_ExtendedTags *tags); |
| 18345 | -int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); |
| 18346 | -int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, |
| 18347 | - yaffs_BlockState *state, __u32 *sequenceNumber); |
| 18348 | + const yaffs_ext_tags *tags); |
| 18349 | +int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int nand_chunk, |
| 18350 | + __u8 *data, yaffs_ext_tags *tags); |
| 18351 | +int nandmtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no); |
| 18352 | +int nandmtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no, |
| 18353 | + yaffs_block_state_t *state, __u32 *seq_number); |
| 18354 | |
| 18355 | #endif |
| 18356 | --- a/fs/yaffs2/yaffs_mtdif.c |
| 18357 | +++ b/fs/yaffs2/yaffs_mtdif.c |
| 18358 | @@ -1,7 +1,7 @@ |
| 18359 | /* |
| 18360 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 18361 | * |
| 18362 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 18363 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 18364 | * for Toby Churchill Ltd and Brightstar Engineering |
| 18365 | * |
| 18366 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 18367 | @@ -11,9 +11,6 @@ |
| 18368 | * published by the Free Software Foundation. |
| 18369 | */ |
| 18370 | |
| 18371 | -const char *yaffs_mtdif_c_version = |
| 18372 | - "$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $"; |
| 18373 | - |
| 18374 | #include "yportenv.h" |
| 18375 | |
| 18376 | |
| 18377 | @@ -24,208 +21,26 @@ const char *yaffs_mtdif_c_version = |
| 18378 | #include "linux/time.h" |
| 18379 | #include "linux/mtd/nand.h" |
| 18380 | |
| 18381 | -#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18)) |
| 18382 | -static struct nand_oobinfo yaffs_oobinfo = { |
| 18383 | - .useecc = 1, |
| 18384 | - .eccbytes = 6, |
| 18385 | - .eccpos = {8, 9, 10, 13, 14, 15} |
| 18386 | -}; |
| 18387 | - |
| 18388 | -static struct nand_oobinfo yaffs_noeccinfo = { |
| 18389 | - .useecc = 0, |
| 18390 | -}; |
| 18391 | -#endif |
| 18392 | - |
| 18393 | -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) |
| 18394 | -static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob) |
| 18395 | -{ |
| 18396 | - oob[0] = spare->tagByte0; |
| 18397 | - oob[1] = spare->tagByte1; |
| 18398 | - oob[2] = spare->tagByte2; |
| 18399 | - oob[3] = spare->tagByte3; |
| 18400 | - oob[4] = spare->tagByte4; |
| 18401 | - oob[5] = spare->tagByte5 & 0x3f; |
| 18402 | - oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80; |
| 18403 | - oob[5] |= spare->pageStatus == 0 ? 0 : 0x40; |
| 18404 | - oob[6] = spare->tagByte6; |
| 18405 | - oob[7] = spare->tagByte7; |
| 18406 | -} |
| 18407 | - |
| 18408 | -static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob) |
| 18409 | -{ |
| 18410 | - struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare; |
| 18411 | - spare->tagByte0 = oob[0]; |
| 18412 | - spare->tagByte1 = oob[1]; |
| 18413 | - spare->tagByte2 = oob[2]; |
| 18414 | - spare->tagByte3 = oob[3]; |
| 18415 | - spare->tagByte4 = oob[4]; |
| 18416 | - spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f; |
| 18417 | - spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y'; |
| 18418 | - spare->pageStatus = oob[5] & 0x40 ? 0xff : 0; |
| 18419 | - spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff; |
| 18420 | - spare->tagByte6 = oob[6]; |
| 18421 | - spare->tagByte7 = oob[7]; |
| 18422 | - spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff; |
| 18423 | - |
| 18424 | - nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */ |
| 18425 | -} |
| 18426 | -#endif |
| 18427 | - |
| 18428 | -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND, |
| 18429 | - const __u8 *data, const yaffs_Spare *spare) |
| 18430 | -{ |
| 18431 | - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
| 18432 | -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) |
| 18433 | - struct mtd_oob_ops ops; |
| 18434 | -#endif |
| 18435 | - size_t dummy; |
| 18436 | - int retval = 0; |
| 18437 | - |
| 18438 | - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; |
| 18439 | -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) |
| 18440 | - __u8 spareAsBytes[8]; /* OOB */ |
| 18441 | - |
| 18442 | - if (data && !spare) |
| 18443 | - retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk, |
| 18444 | - &dummy, data); |
| 18445 | - else if (spare) { |
| 18446 | - if (dev->useNANDECC) { |
| 18447 | - translate_spare2oob(spare, spareAsBytes); |
| 18448 | - ops.mode = MTD_OOB_AUTO; |
| 18449 | - ops.ooblen = 8; /* temp hack */ |
| 18450 | - } else { |
| 18451 | - ops.mode = MTD_OOB_RAW; |
| 18452 | - ops.ooblen = YAFFS_BYTES_PER_SPARE; |
| 18453 | - } |
| 18454 | - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; |
| 18455 | - ops.datbuf = (u8 *)data; |
| 18456 | - ops.ooboffs = 0; |
| 18457 | - ops.oobbuf = spareAsBytes; |
| 18458 | - retval = mtd->write_oob(mtd, addr, &ops); |
| 18459 | - } |
| 18460 | -#else |
| 18461 | - __u8 *spareAsBytes = (__u8 *) spare; |
| 18462 | - |
| 18463 | - if (data && spare) { |
| 18464 | - if (dev->useNANDECC) |
| 18465 | - retval = |
| 18466 | - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, |
| 18467 | - &dummy, data, spareAsBytes, |
| 18468 | - &yaffs_oobinfo); |
| 18469 | - else |
| 18470 | - retval = |
| 18471 | - mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, |
| 18472 | - &dummy, data, spareAsBytes, |
| 18473 | - &yaffs_noeccinfo); |
| 18474 | - } else { |
| 18475 | - if (data) |
| 18476 | - retval = |
| 18477 | - mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, |
| 18478 | - data); |
| 18479 | - if (spare) |
| 18480 | - retval = |
| 18481 | - mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, |
| 18482 | - &dummy, spareAsBytes); |
| 18483 | - } |
| 18484 | -#endif |
| 18485 | - |
| 18486 | - if (retval == 0) |
| 18487 | - return YAFFS_OK; |
| 18488 | - else |
| 18489 | - return YAFFS_FAIL; |
| 18490 | -} |
| 18491 | - |
| 18492 | -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, |
| 18493 | - yaffs_Spare *spare) |
| 18494 | -{ |
| 18495 | - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
| 18496 | -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) |
| 18497 | - struct mtd_oob_ops ops; |
| 18498 | -#endif |
| 18499 | - size_t dummy; |
| 18500 | - int retval = 0; |
| 18501 | +#include "yaffs_linux.h" |
| 18502 | |
| 18503 | - loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; |
| 18504 | -#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17)) |
| 18505 | - __u8 spareAsBytes[8]; /* OOB */ |
| 18506 | - |
| 18507 | - if (data && !spare) |
| 18508 | - retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, |
| 18509 | - &dummy, data); |
| 18510 | - else if (spare) { |
| 18511 | - if (dev->useNANDECC) { |
| 18512 | - ops.mode = MTD_OOB_AUTO; |
| 18513 | - ops.ooblen = 8; /* temp hack */ |
| 18514 | - } else { |
| 18515 | - ops.mode = MTD_OOB_RAW; |
| 18516 | - ops.ooblen = YAFFS_BYTES_PER_SPARE; |
| 18517 | - } |
| 18518 | - ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen; |
| 18519 | - ops.datbuf = data; |
| 18520 | - ops.ooboffs = 0; |
| 18521 | - ops.oobbuf = spareAsBytes; |
| 18522 | - retval = mtd->read_oob(mtd, addr, &ops); |
| 18523 | - if (dev->useNANDECC) |
| 18524 | - translate_oob2spare(spare, spareAsBytes); |
| 18525 | - } |
| 18526 | -#else |
| 18527 | - __u8 *spareAsBytes = (__u8 *) spare; |
| 18528 | - |
| 18529 | - if (data && spare) { |
| 18530 | - if (dev->useNANDECC) { |
| 18531 | - /* Careful, this call adds 2 ints */ |
| 18532 | - /* to the end of the spare data. Calling function */ |
| 18533 | - /* should allocate enough memory for spare, */ |
| 18534 | - /* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */ |
| 18535 | - retval = |
| 18536 | - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, |
| 18537 | - &dummy, data, spareAsBytes, |
| 18538 | - &yaffs_oobinfo); |
| 18539 | - } else { |
| 18540 | - retval = |
| 18541 | - mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, |
| 18542 | - &dummy, data, spareAsBytes, |
| 18543 | - &yaffs_noeccinfo); |
| 18544 | - } |
| 18545 | - } else { |
| 18546 | - if (data) |
| 18547 | - retval = |
| 18548 | - mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, |
| 18549 | - data); |
| 18550 | - if (spare) |
| 18551 | - retval = |
| 18552 | - mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE, |
| 18553 | - &dummy, spareAsBytes); |
| 18554 | - } |
| 18555 | -#endif |
| 18556 | - |
| 18557 | - if (retval == 0) |
| 18558 | - return YAFFS_OK; |
| 18559 | - else |
| 18560 | - return YAFFS_FAIL; |
| 18561 | -} |
| 18562 | - |
| 18563 | -int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber) |
| 18564 | +int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber) |
| 18565 | { |
| 18566 | - struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
| 18567 | + struct mtd_info *mtd = yaffs_dev_to_mtd(dev); |
| 18568 | __u32 addr = |
| 18569 | - ((loff_t) blockNumber) * dev->nDataBytesPerChunk |
| 18570 | - * dev->nChunksPerBlock; |
| 18571 | + ((loff_t) blockNumber) * dev->param.total_bytes_per_chunk |
| 18572 | + * dev->param.chunks_per_block; |
| 18573 | struct erase_info ei; |
| 18574 | + |
| 18575 | int retval = 0; |
| 18576 | |
| 18577 | ei.mtd = mtd; |
| 18578 | ei.addr = addr; |
| 18579 | - ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock; |
| 18580 | + ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block; |
| 18581 | ei.time = 1000; |
| 18582 | ei.retries = 2; |
| 18583 | ei.callback = NULL; |
| 18584 | ei.priv = (u_long) dev; |
| 18585 | |
| 18586 | - /* Todo finish off the ei if required */ |
| 18587 | - |
| 18588 | - sema_init(&dev->sem, 0); |
| 18589 | - |
| 18590 | retval = mtd->erase(mtd, &ei); |
| 18591 | |
| 18592 | if (retval == 0) |
| 18593 | @@ -234,7 +49,7 @@ int nandmtd_EraseBlockInNAND(yaffs_Devic |
| 18594 | return YAFFS_FAIL; |
| 18595 | } |
| 18596 | |
| 18597 | -int nandmtd_InitialiseNAND(yaffs_Device *dev) |
| 18598 | +int nandmtd_InitialiseNAND(yaffs_dev_t *dev) |
| 18599 | { |
| 18600 | return YAFFS_OK; |
| 18601 | } |
| 18602 | --- a/fs/yaffs2/yaffs_mtdif.h |
| 18603 | +++ b/fs/yaffs2/yaffs_mtdif.h |
| 18604 | @@ -1,7 +1,7 @@ |
| 18605 | /* |
| 18606 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 18607 | * |
| 18608 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 18609 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 18610 | * for Toby Churchill Ltd and Brightstar Engineering |
| 18611 | * |
| 18612 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 18613 | @@ -22,11 +22,6 @@ |
| 18614 | extern struct nand_oobinfo yaffs_oobinfo; |
| 18615 | extern struct nand_oobinfo yaffs_noeccinfo; |
| 18616 | #endif |
| 18617 | - |
| 18618 | -int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND, |
| 18619 | - const __u8 *data, const yaffs_Spare *spare); |
| 18620 | -int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data, |
| 18621 | - yaffs_Spare *spare); |
| 18622 | -int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber); |
| 18623 | -int nandmtd_InitialiseNAND(yaffs_Device *dev); |
| 18624 | +int nandmtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber); |
| 18625 | +int nandmtd_InitialiseNAND(yaffs_dev_t *dev); |
| 18626 | #endif |
| 18627 | --- /dev/null |
| 18628 | +++ b/fs/yaffs2/yaffs_nameval.c |
| 18629 | @@ -0,0 +1,197 @@ |
| 18630 | +/* |
| 18631 | + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 18632 | + * |
| 18633 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 18634 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 18635 | + * |
| 18636 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 18637 | + * |
| 18638 | + * This program is free software; you can redistribute it and/or modify |
| 18639 | + * it under the terms of the GNU General Public License version 2 as |
| 18640 | + * published by the Free Software Foundation. |
| 18641 | + */ |
| 18642 | + |
| 18643 | +/* |
| 18644 | + * This simple implementation of a name-value store assumes a small number of values and fits |
| 18645 | + * into a small finite buffer. |
| 18646 | + * |
| 18647 | + * Each attribute is stored as a record: |
| 18648 | + * sizeof(int) bytes record size. |
| 18649 | + * strnlen+1 bytes name null terminated. |
| 18650 | + * nbytes value. |
| 18651 | + * ---------- |
| 18652 | + * total size stored in record size |
| 18653 | + * |
| 18654 | + * This code has not been tested with unicode yet. |
| 18655 | + */ |
| 18656 | + |
| 18657 | + |
| 18658 | +#include "yaffs_nameval.h" |
| 18659 | + |
| 18660 | +#include "yportenv.h" |
| 18661 | + |
| 18662 | +static int nval_find(const char *xb, int xb_size, const YCHAR *name, |
| 18663 | + int *exist_size) |
| 18664 | +{ |
| 18665 | + int pos=0; |
| 18666 | + int size; |
| 18667 | + |
| 18668 | + memcpy(&size,xb,sizeof(int)); |
| 18669 | + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){ |
| 18670 | + if(yaffs_strncmp((YCHAR *)(xb+pos+sizeof(int)),name,size) == 0){ |
| 18671 | + if(exist_size) |
| 18672 | + *exist_size = size; |
| 18673 | + return pos; |
| 18674 | + } |
| 18675 | + pos += size; |
| 18676 | + if(pos < xb_size -sizeof(int)) |
| 18677 | + memcpy(&size,xb + pos,sizeof(int)); |
| 18678 | + else |
| 18679 | + size = 0; |
| 18680 | + } |
| 18681 | + if(exist_size) |
| 18682 | + *exist_size = 0; |
| 18683 | + return -1; |
| 18684 | +} |
| 18685 | + |
| 18686 | +static int nval_used(const char *xb, int xb_size) |
| 18687 | +{ |
| 18688 | + int pos=0; |
| 18689 | + int size; |
| 18690 | + |
| 18691 | + memcpy(&size,xb + pos,sizeof(int)); |
| 18692 | + while(size > 0 && (size < xb_size) && (pos + size < xb_size)){ |
| 18693 | + pos += size; |
| 18694 | + if(pos < xb_size -sizeof(int)) |
| 18695 | + memcpy(&size,xb + pos,sizeof(int)); |
| 18696 | + else |
| 18697 | + size = 0; |
| 18698 | + } |
| 18699 | + return pos; |
| 18700 | +} |
| 18701 | + |
| 18702 | +int nval_del(char *xb, int xb_size, const YCHAR *name) |
| 18703 | +{ |
| 18704 | + int pos = nval_find(xb, xb_size, name, NULL); |
| 18705 | + int size; |
| 18706 | + |
| 18707 | + if(pos >= 0 && pos < xb_size){ |
| 18708 | + /* Find size, shift rest over this record, then zero out the rest of buffer */ |
| 18709 | + memcpy(&size,xb+pos,sizeof(int)); |
| 18710 | + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); |
| 18711 | + memset(xb + (xb_size - size),0,size); |
| 18712 | + return 0; |
| 18713 | + } else |
| 18714 | + return -ENODATA; |
| 18715 | +} |
| 18716 | + |
| 18717 | +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags) |
| 18718 | +{ |
| 18719 | + int pos; |
| 18720 | + int namelen = yaffs_strnlen(name,xb_size); |
| 18721 | + int reclen; |
| 18722 | + int size_exist = 0; |
| 18723 | + int space; |
| 18724 | + int start; |
| 18725 | + |
| 18726 | + pos = nval_find(xb,xb_size,name, &size_exist); |
| 18727 | + |
| 18728 | + if(flags & XATTR_CREATE && pos >= 0) |
| 18729 | + return -EEXIST; |
| 18730 | + if(flags & XATTR_REPLACE && pos < 0) |
| 18731 | + return -ENODATA; |
| 18732 | + |
| 18733 | + start = nval_used(xb,xb_size); |
| 18734 | + space = xb_size - start + size_exist; |
| 18735 | + |
| 18736 | + reclen = (sizeof(int) + namelen + 1 + bsize); |
| 18737 | + |
| 18738 | + if(reclen > space) |
| 18739 | + return -ENOSPC; |
| 18740 | + |
| 18741 | + if(pos >= 0){ |
| 18742 | + nval_del(xb,xb_size,name); |
| 18743 | + start = nval_used(xb, xb_size); |
| 18744 | + } |
| 18745 | + |
| 18746 | + pos = start; |
| 18747 | + |
| 18748 | + memcpy(xb + pos,&reclen,sizeof(int)); |
| 18749 | + pos +=sizeof(int); |
| 18750 | + yaffs_strncpy((YCHAR *)(xb + pos), name, reclen); |
| 18751 | + pos+= (namelen+1); |
| 18752 | + memcpy(xb + pos,buf,bsize); |
| 18753 | + return 0; |
| 18754 | +} |
| 18755 | + |
| 18756 | +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize) |
| 18757 | +{ |
| 18758 | + int pos = nval_find(xb,xb_size,name,NULL); |
| 18759 | + int size; |
| 18760 | + |
| 18761 | + if(pos >= 0 && pos< xb_size){ |
| 18762 | + |
| 18763 | + memcpy(&size,xb +pos,sizeof(int)); |
| 18764 | + pos+=sizeof(int); /* advance past record length */ |
| 18765 | + size -= sizeof(int); |
| 18766 | + |
| 18767 | + /* Advance over name string */ |
| 18768 | + while(xb[pos] && size > 0 && pos < xb_size){ |
| 18769 | + pos++; |
| 18770 | + size--; |
| 18771 | + } |
| 18772 | + /*Advance over NUL */ |
| 18773 | + pos++; |
| 18774 | + size--; |
| 18775 | + |
| 18776 | + if(size <= bsize){ |
| 18777 | + memcpy(buf,xb + pos,size); |
| 18778 | + return size; |
| 18779 | + } |
| 18780 | + |
| 18781 | + } |
| 18782 | + if(pos >= 0) |
| 18783 | + return -ERANGE; |
| 18784 | + else |
| 18785 | + return -ENODATA; |
| 18786 | +} |
| 18787 | + |
| 18788 | +int nval_list(const char *xb, int xb_size, char *buf, int bsize) |
| 18789 | +{ |
| 18790 | + int pos = 0; |
| 18791 | + int size; |
| 18792 | + int name_len; |
| 18793 | + int ncopied = 0; |
| 18794 | + int filled = 0; |
| 18795 | + |
| 18796 | + memcpy(&size,xb + pos,sizeof(int)); |
| 18797 | + while(size > sizeof(int) && size <= xb_size && (pos + size) < xb_size && !filled){ |
| 18798 | + pos+= sizeof(int); |
| 18799 | + size-=sizeof(int); |
| 18800 | + name_len = yaffs_strnlen((YCHAR *)(xb + pos), size); |
| 18801 | + if(ncopied + name_len + 1 < bsize){ |
| 18802 | + memcpy(buf,xb+pos,name_len * sizeof(YCHAR)); |
| 18803 | + buf+= name_len; |
| 18804 | + *buf = '\0'; |
| 18805 | + buf++; |
| 18806 | + if(sizeof(YCHAR) > 1){ |
| 18807 | + *buf = '\0'; |
| 18808 | + buf++; |
| 18809 | + } |
| 18810 | + ncopied += (name_len+1); |
| 18811 | + } else |
| 18812 | + filled = 1; |
| 18813 | + pos+=size; |
| 18814 | + if(pos < xb_size -sizeof(int)) |
| 18815 | + memcpy(&size,xb + pos,sizeof(int)); |
| 18816 | + else |
| 18817 | + size = 0; |
| 18818 | + } |
| 18819 | + return ncopied; |
| 18820 | +} |
| 18821 | + |
| 18822 | + |
| 18823 | +int nval_hasvalues(const char *xb, int xb_size) |
| 18824 | +{ |
| 18825 | + return nval_used(xb, xb_size) > 0; |
| 18826 | +} |
| 18827 | --- /dev/null |
| 18828 | +++ b/fs/yaffs2/yaffs_nameval.h |
| 18829 | @@ -0,0 +1,25 @@ |
| 18830 | +/* |
| 18831 | + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 18832 | + * |
| 18833 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 18834 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 18835 | + * |
| 18836 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 18837 | + * |
| 18838 | + * This program is free software; you can redistribute it and/or modify |
| 18839 | + * it under the terms of the GNU Lesser General Public License version 2.1 as |
| 18840 | + * published by the Free Software Foundation. |
| 18841 | + * |
| 18842 | + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| 18843 | + */ |
| 18844 | +#ifndef __NAMEVAL_H__ |
| 18845 | +#define __NAMEVAL_H__ |
| 18846 | + |
| 18847 | +#include "yportenv.h" |
| 18848 | + |
| 18849 | +int nval_del(char *xb, int xb_size, const YCHAR *name); |
| 18850 | +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, int bsize, int flags); |
| 18851 | +int nval_get(const char *xb, int xb_size, const YCHAR *name, char *buf, int bsize); |
| 18852 | +int nval_list(const char *xb, int xb_size, char *buf, int bsize); |
| 18853 | +int nval_hasvalues(const char *xb, int xb_size); |
| 18854 | +#endif |
| 18855 | --- a/fs/yaffs2/yaffs_nand.c |
| 18856 | +++ b/fs/yaffs2/yaffs_nand.c |
| 18857 | @@ -1,7 +1,7 @@ |
| 18858 | /* |
| 18859 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 18860 | * |
| 18861 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 18862 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 18863 | * for Toby Churchill Ltd and Brightstar Engineering |
| 18864 | * |
| 18865 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 18866 | @@ -11,124 +11,129 @@ |
| 18867 | * published by the Free Software Foundation. |
| 18868 | */ |
| 18869 | |
| 18870 | -const char *yaffs_nand_c_version = |
| 18871 | - "$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $"; |
| 18872 | - |
| 18873 | #include "yaffs_nand.h" |
| 18874 | #include "yaffs_tagscompat.h" |
| 18875 | #include "yaffs_tagsvalidity.h" |
| 18876 | |
| 18877 | #include "yaffs_getblockinfo.h" |
| 18878 | |
| 18879 | -int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, |
| 18880 | +int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk, |
| 18881 | __u8 *buffer, |
| 18882 | - yaffs_ExtendedTags *tags) |
| 18883 | + yaffs_ext_tags *tags) |
| 18884 | { |
| 18885 | int result; |
| 18886 | - yaffs_ExtendedTags localTags; |
| 18887 | + yaffs_ext_tags localTags; |
| 18888 | + |
| 18889 | + int realignedChunkInNAND = nand_chunk - dev->chunk_offset; |
| 18890 | |
| 18891 | - int realignedChunkInNAND = chunkInNAND - dev->chunkOffset; |
| 18892 | + dev->n_page_reads++; |
| 18893 | |
| 18894 | /* If there are no tags provided, use local tags to get prioritised gc working */ |
| 18895 | if (!tags) |
| 18896 | tags = &localTags; |
| 18897 | |
| 18898 | - if (dev->readChunkWithTagsFromNAND) |
| 18899 | - result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, |
| 18900 | + if (dev->param.read_chunk_tags_fn) |
| 18901 | + result = dev->param.read_chunk_tags_fn(dev, realignedChunkInNAND, buffer, |
| 18902 | tags); |
| 18903 | else |
| 18904 | - result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev, |
| 18905 | + result = yaffs_tags_compat_rd(dev, |
| 18906 | realignedChunkInNAND, |
| 18907 | buffer, |
| 18908 | tags); |
| 18909 | if (tags && |
| 18910 | - tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) { |
| 18911 | + tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) { |
| 18912 | |
| 18913 | - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock); |
| 18914 | - yaffs_HandleChunkError(dev, bi); |
| 18915 | + yaffs_block_info_t *bi; |
| 18916 | + bi = yaffs_get_block_info(dev, nand_chunk/dev->param.chunks_per_block); |
| 18917 | + yaffs_handle_chunk_error(dev, bi); |
| 18918 | } |
| 18919 | |
| 18920 | return result; |
| 18921 | } |
| 18922 | |
| 18923 | -int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev, |
| 18924 | - int chunkInNAND, |
| 18925 | +int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev, |
| 18926 | + int nand_chunk, |
| 18927 | const __u8 *buffer, |
| 18928 | - yaffs_ExtendedTags *tags) |
| 18929 | + yaffs_ext_tags *tags) |
| 18930 | { |
| 18931 | - chunkInNAND -= dev->chunkOffset; |
| 18932 | + |
| 18933 | + dev->n_page_writes++; |
| 18934 | + |
| 18935 | + nand_chunk -= dev->chunk_offset; |
| 18936 | |
| 18937 | |
| 18938 | if (tags) { |
| 18939 | - tags->sequenceNumber = dev->sequenceNumber; |
| 18940 | - tags->chunkUsed = 1; |
| 18941 | - if (!yaffs_ValidateTags(tags)) { |
| 18942 | + tags->seq_number = dev->seq_number; |
| 18943 | + tags->chunk_used = 1; |
| 18944 | + if (!yaffs_validate_tags(tags)) { |
| 18945 | T(YAFFS_TRACE_ERROR, |
| 18946 | (TSTR("Writing uninitialised tags" TENDSTR))); |
| 18947 | YBUG(); |
| 18948 | } |
| 18949 | T(YAFFS_TRACE_WRITE, |
| 18950 | - (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND, |
| 18951 | - tags->objectId, tags->chunkId)); |
| 18952 | + (TSTR("Writing chunk %d tags %d %d" TENDSTR), nand_chunk, |
| 18953 | + tags->obj_id, tags->chunk_id)); |
| 18954 | } else { |
| 18955 | T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR))); |
| 18956 | YBUG(); |
| 18957 | } |
| 18958 | |
| 18959 | - if (dev->writeChunkWithTagsToNAND) |
| 18960 | - return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer, |
| 18961 | + if (dev->param.write_chunk_tags_fn) |
| 18962 | + return dev->param.write_chunk_tags_fn(dev, nand_chunk, buffer, |
| 18963 | tags); |
| 18964 | else |
| 18965 | - return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev, |
| 18966 | - chunkInNAND, |
| 18967 | + return yaffs_tags_compat_wr(dev, |
| 18968 | + nand_chunk, |
| 18969 | buffer, |
| 18970 | tags); |
| 18971 | } |
| 18972 | |
| 18973 | -int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo) |
| 18974 | +int yaffs_mark_bad(yaffs_dev_t *dev, int block_no) |
| 18975 | { |
| 18976 | - blockNo -= dev->blockOffset; |
| 18977 | + block_no -= dev->block_offset; |
| 18978 | + |
| 18979 | |
| 18980 | -; |
| 18981 | - if (dev->markNANDBlockBad) |
| 18982 | - return dev->markNANDBlockBad(dev, blockNo); |
| 18983 | + if (dev->param.bad_block_fn) |
| 18984 | + return dev->param.bad_block_fn(dev, block_no); |
| 18985 | else |
| 18986 | - return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo); |
| 18987 | + return yaffs_tags_compat_mark_bad(dev, block_no); |
| 18988 | } |
| 18989 | |
| 18990 | -int yaffs_QueryInitialBlockState(yaffs_Device *dev, |
| 18991 | - int blockNo, |
| 18992 | - yaffs_BlockState *state, |
| 18993 | - __u32 *sequenceNumber) |
| 18994 | +int yaffs_query_init_block_state(yaffs_dev_t *dev, |
| 18995 | + int block_no, |
| 18996 | + yaffs_block_state_t *state, |
| 18997 | + __u32 *seq_number) |
| 18998 | { |
| 18999 | - blockNo -= dev->blockOffset; |
| 19000 | + block_no -= dev->block_offset; |
| 19001 | |
| 19002 | - if (dev->queryNANDBlock) |
| 19003 | - return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber); |
| 19004 | + if (dev->param.query_block_fn) |
| 19005 | + return dev->param.query_block_fn(dev, block_no, state, seq_number); |
| 19006 | else |
| 19007 | - return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo, |
| 19008 | + return yaffs_tags_compat_query_block(dev, block_no, |
| 19009 | state, |
| 19010 | - sequenceNumber); |
| 19011 | + seq_number); |
| 19012 | } |
| 19013 | |
| 19014 | |
| 19015 | -int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, |
| 19016 | - int blockInNAND) |
| 19017 | +int yaffs_erase_block(struct yaffs_dev_s *dev, |
| 19018 | + int flash_block) |
| 19019 | { |
| 19020 | int result; |
| 19021 | |
| 19022 | - blockInNAND -= dev->blockOffset; |
| 19023 | + flash_block -= dev->block_offset; |
| 19024 | |
| 19025 | + dev->n_erasures++; |
| 19026 | |
| 19027 | - dev->nBlockErasures++; |
| 19028 | - result = dev->eraseBlockInNAND(dev, blockInNAND); |
| 19029 | + result = dev->param.erase_fn(dev, flash_block); |
| 19030 | |
| 19031 | return result; |
| 19032 | } |
| 19033 | |
| 19034 | -int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev) |
| 19035 | +int yaffs_init_nand(struct yaffs_dev_s *dev) |
| 19036 | { |
| 19037 | - return dev->initialiseNAND(dev); |
| 19038 | + if(dev->param.initialise_flash_fn) |
| 19039 | + return dev->param.initialise_flash_fn(dev); |
| 19040 | + return YAFFS_OK; |
| 19041 | } |
| 19042 | |
| 19043 | |
| 19044 | --- a/fs/yaffs2/yaffs_nandemul2k.h |
| 19045 | +++ b/fs/yaffs2/yaffs_nandemul2k.h |
| 19046 | @@ -1,7 +1,7 @@ |
| 19047 | /* |
| 19048 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 19049 | * |
| 19050 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 19051 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 19052 | * for Toby Churchill Ltd and Brightstar Engineering |
| 19053 | * |
| 19054 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 19055 | @@ -20,18 +20,18 @@ |
| 19056 | |
| 19057 | #include "yaffs_guts.h" |
| 19058 | |
| 19059 | -int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, |
| 19060 | - int chunkInNAND, const __u8 *data, |
| 19061 | - const yaffs_ExtendedTags *tags); |
| 19062 | -int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev, |
| 19063 | - int chunkInNAND, __u8 *data, |
| 19064 | - yaffs_ExtendedTags *tags); |
| 19065 | -int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); |
| 19066 | -int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, |
| 19067 | - yaffs_BlockState *state, __u32 *sequenceNumber); |
| 19068 | -int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, |
| 19069 | - int blockInNAND); |
| 19070 | -int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev); |
| 19071 | +int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_dev_s *dev, |
| 19072 | + int nand_chunk, const __u8 *data, |
| 19073 | + const yaffs_ext_tags *tags); |
| 19074 | +int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_dev_s *dev, |
| 19075 | + int nand_chunk, __u8 *data, |
| 19076 | + yaffs_ext_tags *tags); |
| 19077 | +int nandemul2k_MarkNANDBlockBad(struct yaffs_dev_s *dev, int block_no); |
| 19078 | +int nandemul2k_QueryNANDBlock(struct yaffs_dev_s *dev, int block_no, |
| 19079 | + yaffs_block_state_t *state, __u32 *seq_number); |
| 19080 | +int nandemul2k_EraseBlockInNAND(struct yaffs_dev_s *dev, |
| 19081 | + int flash_block); |
| 19082 | +int nandemul2k_InitialiseNAND(struct yaffs_dev_s *dev); |
| 19083 | int nandemul2k_GetBytesPerChunk(void); |
| 19084 | int nandemul2k_GetChunksPerBlock(void); |
| 19085 | int nandemul2k_GetNumberOfBlocks(void); |
| 19086 | --- a/fs/yaffs2/yaffs_nand.h |
| 19087 | +++ b/fs/yaffs2/yaffs_nand.h |
| 19088 | @@ -1,7 +1,7 @@ |
| 19089 | /* |
| 19090 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 19091 | * |
| 19092 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 19093 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 19094 | * for Toby Churchill Ltd and Brightstar Engineering |
| 19095 | * |
| 19096 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 19097 | @@ -19,26 +19,26 @@ |
| 19098 | |
| 19099 | |
| 19100 | |
| 19101 | -int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND, |
| 19102 | +int yaffs_rd_chunk_tags_nand(yaffs_dev_t *dev, int nand_chunk, |
| 19103 | __u8 *buffer, |
| 19104 | - yaffs_ExtendedTags *tags); |
| 19105 | + yaffs_ext_tags *tags); |
| 19106 | |
| 19107 | -int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev, |
| 19108 | - int chunkInNAND, |
| 19109 | +int yaffs_wr_chunk_tags_nand(yaffs_dev_t *dev, |
| 19110 | + int nand_chunk, |
| 19111 | const __u8 *buffer, |
| 19112 | - yaffs_ExtendedTags *tags); |
| 19113 | + yaffs_ext_tags *tags); |
| 19114 | |
| 19115 | -int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo); |
| 19116 | +int yaffs_mark_bad(yaffs_dev_t *dev, int block_no); |
| 19117 | |
| 19118 | -int yaffs_QueryInitialBlockState(yaffs_Device *dev, |
| 19119 | - int blockNo, |
| 19120 | - yaffs_BlockState *state, |
| 19121 | - unsigned *sequenceNumber); |
| 19122 | +int yaffs_query_init_block_state(yaffs_dev_t *dev, |
| 19123 | + int block_no, |
| 19124 | + yaffs_block_state_t *state, |
| 19125 | + unsigned *seq_number); |
| 19126 | |
| 19127 | -int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, |
| 19128 | - int blockInNAND); |
| 19129 | +int yaffs_erase_block(struct yaffs_dev_s *dev, |
| 19130 | + int flash_block); |
| 19131 | |
| 19132 | -int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev); |
| 19133 | +int yaffs_init_nand(struct yaffs_dev_s *dev); |
| 19134 | |
| 19135 | #endif |
| 19136 | |
| 19137 | --- a/fs/yaffs2/yaffs_packedtags1.c |
| 19138 | +++ b/fs/yaffs2/yaffs_packedtags1.c |
| 19139 | @@ -1,7 +1,7 @@ |
| 19140 | /* |
| 19141 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 19142 | * |
| 19143 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 19144 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 19145 | * for Toby Churchill Ltd and Brightstar Engineering |
| 19146 | * |
| 19147 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 19148 | @@ -14,37 +14,37 @@ |
| 19149 | #include "yaffs_packedtags1.h" |
| 19150 | #include "yportenv.h" |
| 19151 | |
| 19152 | -void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t) |
| 19153 | +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t) |
| 19154 | { |
| 19155 | - pt->chunkId = t->chunkId; |
| 19156 | - pt->serialNumber = t->serialNumber; |
| 19157 | - pt->byteCount = t->byteCount; |
| 19158 | - pt->objectId = t->objectId; |
| 19159 | + pt->chunk_id = t->chunk_id; |
| 19160 | + pt->serial_number = t->serial_number; |
| 19161 | + pt->n_bytes = t->n_bytes; |
| 19162 | + pt->obj_id = t->obj_id; |
| 19163 | pt->ecc = 0; |
| 19164 | - pt->deleted = (t->chunkDeleted) ? 0 : 1; |
| 19165 | + pt->deleted = (t->is_deleted) ? 0 : 1; |
| 19166 | pt->unusedStuff = 0; |
| 19167 | pt->shouldBeFF = 0xFFFFFFFF; |
| 19168 | |
| 19169 | } |
| 19170 | |
| 19171 | -void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt) |
| 19172 | +void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt) |
| 19173 | { |
| 19174 | static const __u8 allFF[] = |
| 19175 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
| 19176 | 0xff }; |
| 19177 | |
| 19178 | if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) { |
| 19179 | - t->blockBad = 0; |
| 19180 | + t->block_bad = 0; |
| 19181 | if (pt->shouldBeFF != 0xFFFFFFFF) |
| 19182 | - t->blockBad = 1; |
| 19183 | - t->chunkUsed = 1; |
| 19184 | - t->objectId = pt->objectId; |
| 19185 | - t->chunkId = pt->chunkId; |
| 19186 | - t->byteCount = pt->byteCount; |
| 19187 | - t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; |
| 19188 | - t->chunkDeleted = (pt->deleted) ? 0 : 1; |
| 19189 | - t->serialNumber = pt->serialNumber; |
| 19190 | + t->block_bad = 1; |
| 19191 | + t->chunk_used = 1; |
| 19192 | + t->obj_id = pt->obj_id; |
| 19193 | + t->chunk_id = pt->chunk_id; |
| 19194 | + t->n_bytes = pt->n_bytes; |
| 19195 | + t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR; |
| 19196 | + t->is_deleted = (pt->deleted) ? 0 : 1; |
| 19197 | + t->serial_number = pt->serial_number; |
| 19198 | } else { |
| 19199 | - memset(t, 0, sizeof(yaffs_ExtendedTags)); |
| 19200 | + memset(t, 0, sizeof(yaffs_ext_tags)); |
| 19201 | } |
| 19202 | } |
| 19203 | --- a/fs/yaffs2/yaffs_packedtags1.h |
| 19204 | +++ b/fs/yaffs2/yaffs_packedtags1.h |
| 19205 | @@ -1,7 +1,7 @@ |
| 19206 | /* |
| 19207 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 19208 | * |
| 19209 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 19210 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 19211 | * for Toby Churchill Ltd and Brightstar Engineering |
| 19212 | * |
| 19213 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 19214 | @@ -21,10 +21,10 @@ |
| 19215 | #include "yaffs_guts.h" |
| 19216 | |
| 19217 | typedef struct { |
| 19218 | - unsigned chunkId:20; |
| 19219 | - unsigned serialNumber:2; |
| 19220 | - unsigned byteCount:10; |
| 19221 | - unsigned objectId:18; |
| 19222 | + unsigned chunk_id:20; |
| 19223 | + unsigned serial_number:2; |
| 19224 | + unsigned n_bytes:10; |
| 19225 | + unsigned obj_id:18; |
| 19226 | unsigned ecc:12; |
| 19227 | unsigned deleted:1; |
| 19228 | unsigned unusedStuff:1; |
| 19229 | @@ -32,6 +32,6 @@ typedef struct { |
| 19230 | |
| 19231 | } yaffs_PackedTags1; |
| 19232 | |
| 19233 | -void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t); |
| 19234 | -void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt); |
| 19235 | +void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ext_tags *t); |
| 19236 | +void yaffs_unpack_tags1(yaffs_ext_tags *t, const yaffs_PackedTags1 *pt); |
| 19237 | #endif |
| 19238 | --- a/fs/yaffs2/yaffs_packedtags2.c |
| 19239 | +++ b/fs/yaffs2/yaffs_packedtags2.c |
| 19240 | @@ -1,7 +1,7 @@ |
| 19241 | /* |
| 19242 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 19243 | * |
| 19244 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 19245 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 19246 | * for Toby Churchill Ltd and Brightstar Engineering |
| 19247 | * |
| 19248 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 19249 | @@ -13,6 +13,7 @@ |
| 19250 | |
| 19251 | #include "yaffs_packedtags2.h" |
| 19252 | #include "yportenv.h" |
| 19253 | +#include "yaffs_trace.h" |
| 19254 | #include "yaffs_tagsvalidity.h" |
| 19255 | |
| 19256 | /* This code packs a set of extended tags into a binary structure for |
| 19257 | @@ -24,7 +25,7 @@ |
| 19258 | * This is defined by having the EXTRA_HEADER_INFO_FLAG set. |
| 19259 | */ |
| 19260 | |
| 19261 | -/* Extra flags applied to chunkId */ |
| 19262 | +/* Extra flags applied to chunk_id */ |
| 19263 | |
| 19264 | #define EXTRA_HEADER_INFO_FLAG 0x80000000 |
| 19265 | #define EXTRA_SHRINK_FLAG 0x40000000 |
| 19266 | @@ -42,53 +43,53 @@ static void yaffs_DumpPackedTags2TagsPar |
| 19267 | { |
| 19268 | T(YAFFS_TRACE_MTD, |
| 19269 | (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), |
| 19270 | - ptt->objectId, ptt->chunkId, ptt->byteCount, |
| 19271 | - ptt->sequenceNumber)); |
| 19272 | + ptt->obj_id, ptt->chunk_id, ptt->n_bytes, |
| 19273 | + ptt->seq_number)); |
| 19274 | } |
| 19275 | static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt) |
| 19276 | { |
| 19277 | yaffs_DumpPackedTags2TagsPart(&pt->t); |
| 19278 | } |
| 19279 | |
| 19280 | -static void yaffs_DumpTags2(const yaffs_ExtendedTags *t) |
| 19281 | +static void yaffs_DumpTags2(const yaffs_ext_tags *t) |
| 19282 | { |
| 19283 | T(YAFFS_TRACE_MTD, |
| 19284 | (TSTR |
| 19285 | ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d" |
| 19286 | - TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, |
| 19287 | - t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, |
| 19288 | - t->sequenceNumber)); |
| 19289 | + TENDSTR), t->ecc_result, t->block_bad, t->chunk_used, t->obj_id, |
| 19290 | + t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number, |
| 19291 | + t->seq_number)); |
| 19292 | |
| 19293 | } |
| 19294 | |
| 19295 | void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt, |
| 19296 | - const yaffs_ExtendedTags *t) |
| 19297 | + const yaffs_ext_tags *t) |
| 19298 | { |
| 19299 | - ptt->chunkId = t->chunkId; |
| 19300 | - ptt->sequenceNumber = t->sequenceNumber; |
| 19301 | - ptt->byteCount = t->byteCount; |
| 19302 | - ptt->objectId = t->objectId; |
| 19303 | + ptt->chunk_id = t->chunk_id; |
| 19304 | + ptt->seq_number = t->seq_number; |
| 19305 | + ptt->n_bytes = t->n_bytes; |
| 19306 | + ptt->obj_id = t->obj_id; |
| 19307 | |
| 19308 | - if (t->chunkId == 0 && t->extraHeaderInfoAvailable) { |
| 19309 | + if (t->chunk_id == 0 && t->extra_available) { |
| 19310 | /* Store the extra header info instead */ |
| 19311 | - /* We save the parent object in the chunkId */ |
| 19312 | - ptt->chunkId = EXTRA_HEADER_INFO_FLAG |
| 19313 | - | t->extraParentObjectId; |
| 19314 | - if (t->extraIsShrinkHeader) |
| 19315 | - ptt->chunkId |= EXTRA_SHRINK_FLAG; |
| 19316 | - if (t->extraShadows) |
| 19317 | - ptt->chunkId |= EXTRA_SHADOWS_FLAG; |
| 19318 | - |
| 19319 | - ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK; |
| 19320 | - ptt->objectId |= |
| 19321 | - (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT); |
| 19322 | - |
| 19323 | - if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) |
| 19324 | - ptt->byteCount = t->extraEquivalentObjectId; |
| 19325 | - else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) |
| 19326 | - ptt->byteCount = t->extraFileLength; |
| 19327 | + /* We save the parent object in the chunk_id */ |
| 19328 | + ptt->chunk_id = EXTRA_HEADER_INFO_FLAG |
| 19329 | + | t->extra_parent_id; |
| 19330 | + if (t->extra_is_shrink) |
| 19331 | + ptt->chunk_id |= EXTRA_SHRINK_FLAG; |
| 19332 | + if (t->extra_shadows) |
| 19333 | + ptt->chunk_id |= EXTRA_SHADOWS_FLAG; |
| 19334 | + |
| 19335 | + ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; |
| 19336 | + ptt->obj_id |= |
| 19337 | + (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT); |
| 19338 | + |
| 19339 | + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) |
| 19340 | + ptt->n_bytes = t->extra_equiv_id; |
| 19341 | + else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE) |
| 19342 | + ptt->n_bytes = t->extra_length; |
| 19343 | else |
| 19344 | - ptt->byteCount = 0; |
| 19345 | + ptt->n_bytes = 0; |
| 19346 | } |
| 19347 | |
| 19348 | yaffs_DumpPackedTags2TagsPart(ptt); |
| 19349 | @@ -96,59 +97,56 @@ void yaffs_PackTags2TagsPart(yaffs_Packe |
| 19350 | } |
| 19351 | |
| 19352 | |
| 19353 | -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t) |
| 19354 | +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC) |
| 19355 | { |
| 19356 | yaffs_PackTags2TagsPart(&pt->t, t); |
| 19357 | |
| 19358 | -#ifndef YAFFS_IGNORE_TAGS_ECC |
| 19359 | - { |
| 19360 | - yaffs_ECCCalculateOther((unsigned char *)&pt->t, |
| 19361 | + if(tagsECC) |
| 19362 | + yaffs_ecc_calc_other((unsigned char *)&pt->t, |
| 19363 | sizeof(yaffs_PackedTags2TagsPart), |
| 19364 | &pt->ecc); |
| 19365 | - } |
| 19366 | -#endif |
| 19367 | } |
| 19368 | |
| 19369 | |
| 19370 | -void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, |
| 19371 | +void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t, |
| 19372 | yaffs_PackedTags2TagsPart *ptt) |
| 19373 | { |
| 19374 | |
| 19375 | - memset(t, 0, sizeof(yaffs_ExtendedTags)); |
| 19376 | + memset(t, 0, sizeof(yaffs_ext_tags)); |
| 19377 | |
| 19378 | - yaffs_InitialiseTags(t); |
| 19379 | + yaffs_init_tags(t); |
| 19380 | |
| 19381 | - if (ptt->sequenceNumber != 0xFFFFFFFF) { |
| 19382 | - t->blockBad = 0; |
| 19383 | - t->chunkUsed = 1; |
| 19384 | - t->objectId = ptt->objectId; |
| 19385 | - t->chunkId = ptt->chunkId; |
| 19386 | - t->byteCount = ptt->byteCount; |
| 19387 | - t->chunkDeleted = 0; |
| 19388 | - t->serialNumber = 0; |
| 19389 | - t->sequenceNumber = ptt->sequenceNumber; |
| 19390 | + if (ptt->seq_number != 0xFFFFFFFF) { |
| 19391 | + t->block_bad = 0; |
| 19392 | + t->chunk_used = 1; |
| 19393 | + t->obj_id = ptt->obj_id; |
| 19394 | + t->chunk_id = ptt->chunk_id; |
| 19395 | + t->n_bytes = ptt->n_bytes; |
| 19396 | + t->is_deleted = 0; |
| 19397 | + t->serial_number = 0; |
| 19398 | + t->seq_number = ptt->seq_number; |
| 19399 | |
| 19400 | /* Do extra header info stuff */ |
| 19401 | |
| 19402 | - if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) { |
| 19403 | - t->chunkId = 0; |
| 19404 | - t->byteCount = 0; |
| 19405 | - |
| 19406 | - t->extraHeaderInfoAvailable = 1; |
| 19407 | - t->extraParentObjectId = |
| 19408 | - ptt->chunkId & (~(ALL_EXTRA_FLAGS)); |
| 19409 | - t->extraIsShrinkHeader = |
| 19410 | - (ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0; |
| 19411 | - t->extraShadows = |
| 19412 | - (ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0; |
| 19413 | - t->extraObjectType = |
| 19414 | - ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT; |
| 19415 | - t->objectId &= ~EXTRA_OBJECT_TYPE_MASK; |
| 19416 | + if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) { |
| 19417 | + t->chunk_id = 0; |
| 19418 | + t->n_bytes = 0; |
| 19419 | + |
| 19420 | + t->extra_available = 1; |
| 19421 | + t->extra_parent_id = |
| 19422 | + ptt->chunk_id & (~(ALL_EXTRA_FLAGS)); |
| 19423 | + t->extra_is_shrink = |
| 19424 | + (ptt->chunk_id & EXTRA_SHRINK_FLAG) ? 1 : 0; |
| 19425 | + t->extra_shadows = |
| 19426 | + (ptt->chunk_id & EXTRA_SHADOWS_FLAG) ? 1 : 0; |
| 19427 | + t->extra_obj_type = |
| 19428 | + ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT; |
| 19429 | + t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; |
| 19430 | |
| 19431 | - if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) |
| 19432 | - t->extraEquivalentObjectId = ptt->byteCount; |
| 19433 | + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) |
| 19434 | + t->extra_equiv_id = ptt->n_bytes; |
| 19435 | else |
| 19436 | - t->extraFileLength = ptt->byteCount; |
| 19437 | + t->extra_length = ptt->n_bytes; |
| 19438 | } |
| 19439 | } |
| 19440 | |
| 19441 | @@ -158,49 +156,43 @@ void yaffs_UnpackTags2TagsPart(yaffs_Ext |
| 19442 | } |
| 19443 | |
| 19444 | |
| 19445 | -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt) |
| 19446 | +void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC) |
| 19447 | { |
| 19448 | |
| 19449 | - yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR; |
| 19450 | + yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR; |
| 19451 | |
| 19452 | - if (pt->t.sequenceNumber != 0xFFFFFFFF) { |
| 19453 | - /* Page is in use */ |
| 19454 | -#ifndef YAFFS_IGNORE_TAGS_ECC |
| 19455 | - { |
| 19456 | - yaffs_ECCOther ecc; |
| 19457 | - int result; |
| 19458 | - yaffs_ECCCalculateOther((unsigned char *)&pt->t, |
| 19459 | - sizeof |
| 19460 | - (yaffs_PackedTags2TagsPart), |
| 19461 | - &ecc); |
| 19462 | - result = |
| 19463 | - yaffs_ECCCorrectOther((unsigned char *)&pt->t, |
| 19464 | - sizeof |
| 19465 | - (yaffs_PackedTags2TagsPart), |
| 19466 | - &pt->ecc, &ecc); |
| 19467 | - switch (result) { |
| 19468 | + if (pt->t.seq_number != 0xFFFFFFFF && |
| 19469 | + tagsECC){ |
| 19470 | + /* Chunk is in use and we need to do ECC */ |
| 19471 | + |
| 19472 | + yaffs_ECCOther ecc; |
| 19473 | + int result; |
| 19474 | + yaffs_ecc_calc_other((unsigned char *)&pt->t, |
| 19475 | + sizeof(yaffs_PackedTags2TagsPart), |
| 19476 | + &ecc); |
| 19477 | + result = yaffs_ecc_correct_other((unsigned char *)&pt->t, |
| 19478 | + sizeof(yaffs_PackedTags2TagsPart), |
| 19479 | + &pt->ecc, &ecc); |
| 19480 | + switch (result) { |
| 19481 | case 0: |
| 19482 | - eccResult = YAFFS_ECC_RESULT_NO_ERROR; |
| 19483 | + ecc_result = YAFFS_ECC_RESULT_NO_ERROR; |
| 19484 | break; |
| 19485 | case 1: |
| 19486 | - eccResult = YAFFS_ECC_RESULT_FIXED; |
| 19487 | + ecc_result = YAFFS_ECC_RESULT_FIXED; |
| 19488 | break; |
| 19489 | case -1: |
| 19490 | - eccResult = YAFFS_ECC_RESULT_UNFIXED; |
| 19491 | + ecc_result = YAFFS_ECC_RESULT_UNFIXED; |
| 19492 | break; |
| 19493 | default: |
| 19494 | - eccResult = YAFFS_ECC_RESULT_UNKNOWN; |
| 19495 | - } |
| 19496 | + ecc_result = YAFFS_ECC_RESULT_UNKNOWN; |
| 19497 | } |
| 19498 | -#endif |
| 19499 | } |
| 19500 | |
| 19501 | - yaffs_UnpackTags2TagsPart(t, &pt->t); |
| 19502 | + yaffs_unpack_tags2tags_part(t, &pt->t); |
| 19503 | |
| 19504 | - t->eccResult = eccResult; |
| 19505 | + t->ecc_result = ecc_result; |
| 19506 | |
| 19507 | yaffs_DumpPackedTags2(pt); |
| 19508 | yaffs_DumpTags2(t); |
| 19509 | - |
| 19510 | } |
| 19511 | |
| 19512 | --- a/fs/yaffs2/yaffs_packedtags2.h |
| 19513 | +++ b/fs/yaffs2/yaffs_packedtags2.h |
| 19514 | @@ -1,7 +1,7 @@ |
| 19515 | /* |
| 19516 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 19517 | * |
| 19518 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 19519 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 19520 | * for Toby Churchill Ltd and Brightstar Engineering |
| 19521 | * |
| 19522 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 19523 | @@ -22,10 +22,10 @@ |
| 19524 | #include "yaffs_ecc.h" |
| 19525 | |
| 19526 | typedef struct { |
| 19527 | - unsigned sequenceNumber; |
| 19528 | - unsigned objectId; |
| 19529 | - unsigned chunkId; |
| 19530 | - unsigned byteCount; |
| 19531 | + unsigned seq_number; |
| 19532 | + unsigned obj_id; |
| 19533 | + unsigned chunk_id; |
| 19534 | + unsigned n_bytes; |
| 19535 | } yaffs_PackedTags2TagsPart; |
| 19536 | |
| 19537 | typedef struct { |
| 19538 | @@ -34,10 +34,10 @@ typedef struct { |
| 19539 | } yaffs_PackedTags2; |
| 19540 | |
| 19541 | /* Full packed tags with ECC, used for oob tags */ |
| 19542 | -void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t); |
| 19543 | -void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt); |
| 19544 | +void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ext_tags *t, int tagsECC); |
| 19545 | +void yaffs_unpack_tags2(yaffs_ext_tags *t, yaffs_PackedTags2 *pt, int tagsECC); |
| 19546 | |
| 19547 | /* Only the tags part (no ECC for use with inband tags */ |
| 19548 | -void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t); |
| 19549 | -void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, yaffs_PackedTags2TagsPart *pt); |
| 19550 | +void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ext_tags *t); |
| 19551 | +void yaffs_unpack_tags2tags_part(yaffs_ext_tags *t, yaffs_PackedTags2TagsPart *pt); |
| 19552 | #endif |
| 19553 | --- a/fs/yaffs2/yaffs_qsort.h |
| 19554 | +++ b/fs/yaffs2/yaffs_qsort.h |
| 19555 | @@ -1,7 +1,7 @@ |
| 19556 | /* |
| 19557 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 19558 | * |
| 19559 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 19560 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 19561 | * for Toby Churchill Ltd and Brightstar Engineering |
| 19562 | * |
| 19563 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 19564 | @@ -17,7 +17,18 @@ |
| 19565 | #ifndef __YAFFS_QSORT_H__ |
| 19566 | #define __YAFFS_QSORT_H__ |
| 19567 | |
| 19568 | +#ifdef __KERNEL__ |
| 19569 | +#include <linux/sort.h> |
| 19570 | + |
| 19571 | +extern void yaffs_qsort(void *const base, size_t total_elems, size_t size, |
| 19572 | + int (*cmp)(const void *, const void *)){ |
| 19573 | + sort(base, total_elems, size, cmp, NULL); |
| 19574 | +} |
| 19575 | + |
| 19576 | +#else |
| 19577 | + |
| 19578 | extern void yaffs_qsort(void *const base, size_t total_elems, size_t size, |
| 19579 | int (*cmp)(const void *, const void *)); |
| 19580 | |
| 19581 | #endif |
| 19582 | +#endif |
| 19583 | --- a/fs/yaffs2/yaffs_tagscompat.c |
| 19584 | +++ b/fs/yaffs2/yaffs_tagscompat.c |
| 19585 | @@ -1,7 +1,7 @@ |
| 19586 | /* |
| 19587 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 19588 | * |
| 19589 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 19590 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 19591 | * for Toby Churchill Ltd and Brightstar Engineering |
| 19592 | * |
| 19593 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 19594 | @@ -15,19 +15,20 @@ |
| 19595 | #include "yaffs_tagscompat.h" |
| 19596 | #include "yaffs_ecc.h" |
| 19597 | #include "yaffs_getblockinfo.h" |
| 19598 | +#include "yaffs_trace.h" |
| 19599 | |
| 19600 | -static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND); |
| 19601 | +static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk); |
| 19602 | #ifdef NOTYET |
| 19603 | -static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND); |
| 19604 | -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, |
| 19605 | +static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk); |
| 19606 | +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk, |
| 19607 | const __u8 *data, |
| 19608 | - const yaffs_Spare *spare); |
| 19609 | -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, |
| 19610 | - const yaffs_Spare *spare); |
| 19611 | -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND); |
| 19612 | + const yaffs_spare *spare); |
| 19613 | +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk, |
| 19614 | + const yaffs_spare *spare); |
| 19615 | +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk); |
| 19616 | #endif |
| 19617 | |
| 19618 | -static const char yaffs_countBitsTable[256] = { |
| 19619 | +static const char yaffs_count_bits_table[256] = { |
| 19620 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, |
| 19621 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
| 19622 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, |
| 19623 | @@ -46,26 +47,26 @@ static const char yaffs_countBitsTable[2 |
| 19624 | 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 |
| 19625 | }; |
| 19626 | |
| 19627 | -int yaffs_CountBits(__u8 x) |
| 19628 | +int yaffs_count_bits(__u8 x) |
| 19629 | { |
| 19630 | int retVal; |
| 19631 | - retVal = yaffs_countBitsTable[x]; |
| 19632 | + retVal = yaffs_count_bits_table[x]; |
| 19633 | return retVal; |
| 19634 | } |
| 19635 | |
| 19636 | /********** Tags ECC calculations *********/ |
| 19637 | |
| 19638 | -void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) |
| 19639 | +void yaffs_calc_ecc(const __u8 *data, yaffs_spare *spare) |
| 19640 | { |
| 19641 | - yaffs_ECCCalculate(data, spare->ecc1); |
| 19642 | - yaffs_ECCCalculate(&data[256], spare->ecc2); |
| 19643 | + yaffs_ecc_cacl(data, spare->ecc1); |
| 19644 | + yaffs_ecc_cacl(&data[256], spare->ecc2); |
| 19645 | } |
| 19646 | |
| 19647 | -void yaffs_CalcTagsECC(yaffs_Tags *tags) |
| 19648 | +void yaffs_calc_tags_ecc(yaffs_tags_t *tags) |
| 19649 | { |
| 19650 | /* Calculate an ecc */ |
| 19651 | |
| 19652 | - unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes; |
| 19653 | + unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes; |
| 19654 | unsigned i, j; |
| 19655 | unsigned ecc = 0; |
| 19656 | unsigned bit = 0; |
| 19657 | @@ -84,24 +85,24 @@ void yaffs_CalcTagsECC(yaffs_Tags *tags) |
| 19658 | |
| 19659 | } |
| 19660 | |
| 19661 | -int yaffs_CheckECCOnTags(yaffs_Tags *tags) |
| 19662 | +int yaffs_check_tags_ecc(yaffs_tags_t *tags) |
| 19663 | { |
| 19664 | unsigned ecc = tags->ecc; |
| 19665 | |
| 19666 | - yaffs_CalcTagsECC(tags); |
| 19667 | + yaffs_calc_tags_ecc(tags); |
| 19668 | |
| 19669 | ecc ^= tags->ecc; |
| 19670 | |
| 19671 | if (ecc && ecc <= 64) { |
| 19672 | /* TODO: Handle the failure better. Retire? */ |
| 19673 | - unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes; |
| 19674 | + unsigned char *b = ((yaffs_tags_union_t *) tags)->as_bytes; |
| 19675 | |
| 19676 | ecc--; |
| 19677 | |
| 19678 | b[ecc / 8] ^= (1 << (ecc & 7)); |
| 19679 | |
| 19680 | /* Now recvalc the ecc */ |
| 19681 | - yaffs_CalcTagsECC(tags); |
| 19682 | + yaffs_calc_tags_ecc(tags); |
| 19683 | |
| 19684 | return 1; /* recovered error */ |
| 19685 | } else if (ecc) { |
| 19686 | @@ -115,76 +116,73 @@ int yaffs_CheckECCOnTags(yaffs_Tags *tag |
| 19687 | |
| 19688 | /********** Tags **********/ |
| 19689 | |
| 19690 | -static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, |
| 19691 | - yaffs_Tags *tagsPtr) |
| 19692 | +static void yaffs_load_tags_to_spare(yaffs_spare *sparePtr, |
| 19693 | + yaffs_tags_t *tagsPtr) |
| 19694 | { |
| 19695 | - yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr; |
| 19696 | + yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr; |
| 19697 | |
| 19698 | - yaffs_CalcTagsECC(tagsPtr); |
| 19699 | + yaffs_calc_tags_ecc(tagsPtr); |
| 19700 | |
| 19701 | - sparePtr->tagByte0 = tu->asBytes[0]; |
| 19702 | - sparePtr->tagByte1 = tu->asBytes[1]; |
| 19703 | - sparePtr->tagByte2 = tu->asBytes[2]; |
| 19704 | - sparePtr->tagByte3 = tu->asBytes[3]; |
| 19705 | - sparePtr->tagByte4 = tu->asBytes[4]; |
| 19706 | - sparePtr->tagByte5 = tu->asBytes[5]; |
| 19707 | - sparePtr->tagByte6 = tu->asBytes[6]; |
| 19708 | - sparePtr->tagByte7 = tu->asBytes[7]; |
| 19709 | + sparePtr->tb0 = tu->as_bytes[0]; |
| 19710 | + sparePtr->tb1 = tu->as_bytes[1]; |
| 19711 | + sparePtr->tb2 = tu->as_bytes[2]; |
| 19712 | + sparePtr->tb3 = tu->as_bytes[3]; |
| 19713 | + sparePtr->tb4 = tu->as_bytes[4]; |
| 19714 | + sparePtr->tb5 = tu->as_bytes[5]; |
| 19715 | + sparePtr->tb6 = tu->as_bytes[6]; |
| 19716 | + sparePtr->tb7 = tu->as_bytes[7]; |
| 19717 | } |
| 19718 | |
| 19719 | -static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr, |
| 19720 | - yaffs_Tags *tagsPtr) |
| 19721 | +static void yaffs_get_tags_from_spare(yaffs_dev_t *dev, yaffs_spare *sparePtr, |
| 19722 | + yaffs_tags_t *tagsPtr) |
| 19723 | { |
| 19724 | - yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr; |
| 19725 | + yaffs_tags_union_t *tu = (yaffs_tags_union_t *) tagsPtr; |
| 19726 | int result; |
| 19727 | |
| 19728 | - tu->asBytes[0] = sparePtr->tagByte0; |
| 19729 | - tu->asBytes[1] = sparePtr->tagByte1; |
| 19730 | - tu->asBytes[2] = sparePtr->tagByte2; |
| 19731 | - tu->asBytes[3] = sparePtr->tagByte3; |
| 19732 | - tu->asBytes[4] = sparePtr->tagByte4; |
| 19733 | - tu->asBytes[5] = sparePtr->tagByte5; |
| 19734 | - tu->asBytes[6] = sparePtr->tagByte6; |
| 19735 | - tu->asBytes[7] = sparePtr->tagByte7; |
| 19736 | + tu->as_bytes[0] = sparePtr->tb0; |
| 19737 | + tu->as_bytes[1] = sparePtr->tb1; |
| 19738 | + tu->as_bytes[2] = sparePtr->tb2; |
| 19739 | + tu->as_bytes[3] = sparePtr->tb3; |
| 19740 | + tu->as_bytes[4] = sparePtr->tb4; |
| 19741 | + tu->as_bytes[5] = sparePtr->tb5; |
| 19742 | + tu->as_bytes[6] = sparePtr->tb6; |
| 19743 | + tu->as_bytes[7] = sparePtr->tb7; |
| 19744 | |
| 19745 | - result = yaffs_CheckECCOnTags(tagsPtr); |
| 19746 | + result = yaffs_check_tags_ecc(tagsPtr); |
| 19747 | if (result > 0) |
| 19748 | - dev->tagsEccFixed++; |
| 19749 | + dev->n_tags_ecc_fixed++; |
| 19750 | else if (result < 0) |
| 19751 | - dev->tagsEccUnfixed++; |
| 19752 | + dev->n_tags_ecc_unfixed++; |
| 19753 | } |
| 19754 | |
| 19755 | -static void yaffs_SpareInitialise(yaffs_Spare *spare) |
| 19756 | +static void yaffs_spare_init(yaffs_spare *spare) |
| 19757 | { |
| 19758 | - memset(spare, 0xFF, sizeof(yaffs_Spare)); |
| 19759 | + memset(spare, 0xFF, sizeof(yaffs_spare)); |
| 19760 | } |
| 19761 | |
| 19762 | -static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev, |
| 19763 | - int chunkInNAND, const __u8 *data, |
| 19764 | - yaffs_Spare *spare) |
| 19765 | +static int yaffs_wr_nand(struct yaffs_dev_s *dev, |
| 19766 | + int nand_chunk, const __u8 *data, |
| 19767 | + yaffs_spare *spare) |
| 19768 | { |
| 19769 | - if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) { |
| 19770 | + if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) { |
| 19771 | T(YAFFS_TRACE_ERROR, |
| 19772 | (TSTR("**>> yaffs chunk %d is not valid" TENDSTR), |
| 19773 | - chunkInNAND)); |
| 19774 | + nand_chunk)); |
| 19775 | return YAFFS_FAIL; |
| 19776 | } |
| 19777 | |
| 19778 | - dev->nPageWrites++; |
| 19779 | - return dev->writeChunkToNAND(dev, chunkInNAND, data, spare); |
| 19780 | + return dev->param.write_chunk_fn(dev, nand_chunk, data, spare); |
| 19781 | } |
| 19782 | |
| 19783 | -static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, |
| 19784 | - int chunkInNAND, |
| 19785 | +static int yaffs_rd_chunk_nand(struct yaffs_dev_s *dev, |
| 19786 | + int nand_chunk, |
| 19787 | __u8 *data, |
| 19788 | - yaffs_Spare *spare, |
| 19789 | - yaffs_ECCResult *eccResult, |
| 19790 | + yaffs_spare *spare, |
| 19791 | + yaffs_ecc_result *ecc_result, |
| 19792 | int doErrorCorrection) |
| 19793 | { |
| 19794 | int retVal; |
| 19795 | - yaffs_Spare localSpare; |
| 19796 | - |
| 19797 | - dev->nPageReads++; |
| 19798 | + yaffs_spare localSpare; |
| 19799 | |
| 19800 | if (!spare && data) { |
| 19801 | /* If we don't have a real spare, then we use a local one. */ |
| 19802 | @@ -192,107 +190,107 @@ static int yaffs_ReadChunkFromNAND(struc |
| 19803 | spare = &localSpare; |
| 19804 | } |
| 19805 | |
| 19806 | - if (!dev->useNANDECC) { |
| 19807 | - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare); |
| 19808 | + if (!dev->param.use_nand_ecc) { |
| 19809 | + retVal = dev->param.read_chunk_fn(dev, nand_chunk, data, spare); |
| 19810 | if (data && doErrorCorrection) { |
| 19811 | /* Do ECC correction */ |
| 19812 | /* Todo handle any errors */ |
| 19813 | - int eccResult1, eccResult2; |
| 19814 | + int ecc_result1, ecc_result2; |
| 19815 | __u8 calcEcc[3]; |
| 19816 | |
| 19817 | - yaffs_ECCCalculate(data, calcEcc); |
| 19818 | - eccResult1 = |
| 19819 | - yaffs_ECCCorrect(data, spare->ecc1, calcEcc); |
| 19820 | - yaffs_ECCCalculate(&data[256], calcEcc); |
| 19821 | - eccResult2 = |
| 19822 | - yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc); |
| 19823 | + yaffs_ecc_cacl(data, calcEcc); |
| 19824 | + ecc_result1 = |
| 19825 | + yaffs_ecc_correct(data, spare->ecc1, calcEcc); |
| 19826 | + yaffs_ecc_cacl(&data[256], calcEcc); |
| 19827 | + ecc_result2 = |
| 19828 | + yaffs_ecc_correct(&data[256], spare->ecc2, calcEcc); |
| 19829 | |
| 19830 | - if (eccResult1 > 0) { |
| 19831 | + if (ecc_result1 > 0) { |
| 19832 | T(YAFFS_TRACE_ERROR, |
| 19833 | (TSTR |
| 19834 | ("**>>yaffs ecc error fix performed on chunk %d:0" |
| 19835 | - TENDSTR), chunkInNAND)); |
| 19836 | - dev->eccFixed++; |
| 19837 | - } else if (eccResult1 < 0) { |
| 19838 | + TENDSTR), nand_chunk)); |
| 19839 | + dev->n_ecc_fixed++; |
| 19840 | + } else if (ecc_result1 < 0) { |
| 19841 | T(YAFFS_TRACE_ERROR, |
| 19842 | (TSTR |
| 19843 | ("**>>yaffs ecc error unfixed on chunk %d:0" |
| 19844 | - TENDSTR), chunkInNAND)); |
| 19845 | - dev->eccUnfixed++; |
| 19846 | + TENDSTR), nand_chunk)); |
| 19847 | + dev->n_ecc_unfixed++; |
| 19848 | } |
| 19849 | |
| 19850 | - if (eccResult2 > 0) { |
| 19851 | + if (ecc_result2 > 0) { |
| 19852 | T(YAFFS_TRACE_ERROR, |
| 19853 | (TSTR |
| 19854 | ("**>>yaffs ecc error fix performed on chunk %d:1" |
| 19855 | - TENDSTR), chunkInNAND)); |
| 19856 | - dev->eccFixed++; |
| 19857 | - } else if (eccResult2 < 0) { |
| 19858 | + TENDSTR), nand_chunk)); |
| 19859 | + dev->n_ecc_fixed++; |
| 19860 | + } else if (ecc_result2 < 0) { |
| 19861 | T(YAFFS_TRACE_ERROR, |
| 19862 | (TSTR |
| 19863 | ("**>>yaffs ecc error unfixed on chunk %d:1" |
| 19864 | - TENDSTR), chunkInNAND)); |
| 19865 | - dev->eccUnfixed++; |
| 19866 | + TENDSTR), nand_chunk)); |
| 19867 | + dev->n_ecc_unfixed++; |
| 19868 | } |
| 19869 | |
| 19870 | - if (eccResult1 || eccResult2) { |
| 19871 | + if (ecc_result1 || ecc_result2) { |
| 19872 | /* We had a data problem on this page */ |
| 19873 | - yaffs_HandleReadDataError(dev, chunkInNAND); |
| 19874 | + yaffs_handle_rd_data_error(dev, nand_chunk); |
| 19875 | } |
| 19876 | |
| 19877 | - if (eccResult1 < 0 || eccResult2 < 0) |
| 19878 | - *eccResult = YAFFS_ECC_RESULT_UNFIXED; |
| 19879 | - else if (eccResult1 > 0 || eccResult2 > 0) |
| 19880 | - *eccResult = YAFFS_ECC_RESULT_FIXED; |
| 19881 | + if (ecc_result1 < 0 || ecc_result2 < 0) |
| 19882 | + *ecc_result = YAFFS_ECC_RESULT_UNFIXED; |
| 19883 | + else if (ecc_result1 > 0 || ecc_result2 > 0) |
| 19884 | + *ecc_result = YAFFS_ECC_RESULT_FIXED; |
| 19885 | else |
| 19886 | - *eccResult = YAFFS_ECC_RESULT_NO_ERROR; |
| 19887 | + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; |
| 19888 | } |
| 19889 | } else { |
| 19890 | /* Must allocate enough memory for spare+2*sizeof(int) */ |
| 19891 | /* for ecc results from device. */ |
| 19892 | - struct yaffs_NANDSpare nspare; |
| 19893 | + struct yaffs_nand_spare nspare; |
| 19894 | |
| 19895 | memset(&nspare, 0, sizeof(nspare)); |
| 19896 | |
| 19897 | - retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, |
| 19898 | - (yaffs_Spare *) &nspare); |
| 19899 | - memcpy(spare, &nspare, sizeof(yaffs_Spare)); |
| 19900 | + retVal = dev->param.read_chunk_fn(dev, nand_chunk, data, |
| 19901 | + (yaffs_spare *) &nspare); |
| 19902 | + memcpy(spare, &nspare, sizeof(yaffs_spare)); |
| 19903 | if (data && doErrorCorrection) { |
| 19904 | if (nspare.eccres1 > 0) { |
| 19905 | T(YAFFS_TRACE_ERROR, |
| 19906 | (TSTR |
| 19907 | ("**>>mtd ecc error fix performed on chunk %d:0" |
| 19908 | - TENDSTR), chunkInNAND)); |
| 19909 | + TENDSTR), nand_chunk)); |
| 19910 | } else if (nspare.eccres1 < 0) { |
| 19911 | T(YAFFS_TRACE_ERROR, |
| 19912 | (TSTR |
| 19913 | ("**>>mtd ecc error unfixed on chunk %d:0" |
| 19914 | - TENDSTR), chunkInNAND)); |
| 19915 | + TENDSTR), nand_chunk)); |
| 19916 | } |
| 19917 | |
| 19918 | if (nspare.eccres2 > 0) { |
| 19919 | T(YAFFS_TRACE_ERROR, |
| 19920 | (TSTR |
| 19921 | ("**>>mtd ecc error fix performed on chunk %d:1" |
| 19922 | - TENDSTR), chunkInNAND)); |
| 19923 | + TENDSTR), nand_chunk)); |
| 19924 | } else if (nspare.eccres2 < 0) { |
| 19925 | T(YAFFS_TRACE_ERROR, |
| 19926 | (TSTR |
| 19927 | ("**>>mtd ecc error unfixed on chunk %d:1" |
| 19928 | - TENDSTR), chunkInNAND)); |
| 19929 | + TENDSTR), nand_chunk)); |
| 19930 | } |
| 19931 | |
| 19932 | if (nspare.eccres1 || nspare.eccres2) { |
| 19933 | /* We had a data problem on this page */ |
| 19934 | - yaffs_HandleReadDataError(dev, chunkInNAND); |
| 19935 | + yaffs_handle_rd_data_error(dev, nand_chunk); |
| 19936 | } |
| 19937 | |
| 19938 | if (nspare.eccres1 < 0 || nspare.eccres2 < 0) |
| 19939 | - *eccResult = YAFFS_ECC_RESULT_UNFIXED; |
| 19940 | + *ecc_result = YAFFS_ECC_RESULT_UNFIXED; |
| 19941 | else if (nspare.eccres1 > 0 || nspare.eccres2 > 0) |
| 19942 | - *eccResult = YAFFS_ECC_RESULT_FIXED; |
| 19943 | + *ecc_result = YAFFS_ECC_RESULT_FIXED; |
| 19944 | else |
| 19945 | - *eccResult = YAFFS_ECC_RESULT_NO_ERROR; |
| 19946 | + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; |
| 19947 | |
| 19948 | } |
| 19949 | } |
| 19950 | @@ -300,17 +298,17 @@ static int yaffs_ReadChunkFromNAND(struc |
| 19951 | } |
| 19952 | |
| 19953 | #ifdef NOTYET |
| 19954 | -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, |
| 19955 | - int chunkInNAND) |
| 19956 | +static int yaffs_check_chunk_erased(struct yaffs_dev_s *dev, |
| 19957 | + int nand_chunk) |
| 19958 | { |
| 19959 | static int init; |
| 19960 | static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK]; |
| 19961 | static __u8 data[YAFFS_BYTES_PER_CHUNK]; |
| 19962 | /* Might as well always allocate the larger size for */ |
| 19963 | - /* dev->useNANDECC == true; */ |
| 19964 | - static __u8 spare[sizeof(struct yaffs_NANDSpare)]; |
| 19965 | + /* dev->param.use_nand_ecc == true; */ |
| 19966 | + static __u8 spare[sizeof(struct yaffs_nand_spare)]; |
| 19967 | |
| 19968 | - dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare); |
| 19969 | + dev->param.read_chunk_fn(dev, nand_chunk, data, (yaffs_spare *) spare); |
| 19970 | |
| 19971 | if (!init) { |
| 19972 | memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK); |
| 19973 | @@ -331,14 +329,14 @@ static int yaffs_CheckChunkErased(struct |
| 19974 | * Functions for robustisizing |
| 19975 | */ |
| 19976 | |
| 19977 | -static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND) |
| 19978 | +static void yaffs_handle_rd_data_error(yaffs_dev_t *dev, int nand_chunk) |
| 19979 | { |
| 19980 | - int blockInNAND = chunkInNAND / dev->nChunksPerBlock; |
| 19981 | + int flash_block = nand_chunk / dev->param.chunks_per_block; |
| 19982 | |
| 19983 | /* Mark the block for retirement */ |
| 19984 | - yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1; |
| 19985 | + yaffs_get_block_info(dev, flash_block + dev->block_offset)->needs_retiring = 1; |
| 19986 | T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, |
| 19987 | - (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND)); |
| 19988 | + (TSTR("**>>Block %d marked for retirement" TENDSTR), flash_block)); |
| 19989 | |
| 19990 | /* TODO: |
| 19991 | * Just do a garbage collection on the affected block |
| 19992 | @@ -348,44 +346,44 @@ static void yaffs_HandleReadDataError(ya |
| 19993 | } |
| 19994 | |
| 19995 | #ifdef NOTYET |
| 19996 | -static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND) |
| 19997 | +static void yaffs_check_written_block(yaffs_dev_t *dev, int nand_chunk) |
| 19998 | { |
| 19999 | } |
| 20000 | |
| 20001 | -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND, |
| 20002 | +static void yaffs_handle_chunk_wr_ok(yaffs_dev_t *dev, int nand_chunk, |
| 20003 | const __u8 *data, |
| 20004 | - const yaffs_Spare *spare) |
| 20005 | + const yaffs_spare *spare) |
| 20006 | { |
| 20007 | } |
| 20008 | |
| 20009 | -static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND, |
| 20010 | - const yaffs_Spare *spare) |
| 20011 | +static void yaffs_handle_chunk_update(yaffs_dev_t *dev, int nand_chunk, |
| 20012 | + const yaffs_spare *spare) |
| 20013 | { |
| 20014 | } |
| 20015 | |
| 20016 | -static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND) |
| 20017 | +static void yaffs_handle_chunk_wr_error(yaffs_dev_t *dev, int nand_chunk) |
| 20018 | { |
| 20019 | - int blockInNAND = chunkInNAND / dev->nChunksPerBlock; |
| 20020 | + int flash_block = nand_chunk / dev->param.chunks_per_block; |
| 20021 | |
| 20022 | /* Mark the block for retirement */ |
| 20023 | - yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; |
| 20024 | + yaffs_get_block_info(dev, flash_block)->needs_retiring = 1; |
| 20025 | /* Delete the chunk */ |
| 20026 | - yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); |
| 20027 | + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); |
| 20028 | } |
| 20029 | |
| 20030 | -static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1, |
| 20031 | - const yaffs_Spare *s0, const yaffs_Spare *s1) |
| 20032 | +static int yaffs_verify_cmp(const __u8 *d0, const __u8 *d1, |
| 20033 | + const yaffs_spare *s0, const yaffs_spare *s1) |
| 20034 | { |
| 20035 | |
| 20036 | if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 || |
| 20037 | - s0->tagByte0 != s1->tagByte0 || |
| 20038 | - s0->tagByte1 != s1->tagByte1 || |
| 20039 | - s0->tagByte2 != s1->tagByte2 || |
| 20040 | - s0->tagByte3 != s1->tagByte3 || |
| 20041 | - s0->tagByte4 != s1->tagByte4 || |
| 20042 | - s0->tagByte5 != s1->tagByte5 || |
| 20043 | - s0->tagByte6 != s1->tagByte6 || |
| 20044 | - s0->tagByte7 != s1->tagByte7 || |
| 20045 | + s0->tb0 != s1->tb0 || |
| 20046 | + s0->tb1 != s1->tb1 || |
| 20047 | + s0->tb2 != s1->tb2 || |
| 20048 | + s0->tb3 != s1->tb3 || |
| 20049 | + s0->tb4 != s1->tb4 || |
| 20050 | + s0->tb5 != s1->tb5 || |
| 20051 | + s0->tb6 != s1->tb6 || |
| 20052 | + s0->tb7 != s1->tb7 || |
| 20053 | s0->ecc1[0] != s1->ecc1[0] || |
| 20054 | s0->ecc1[1] != s1->ecc1[1] || |
| 20055 | s0->ecc1[2] != s1->ecc1[2] || |
| 20056 | @@ -398,53 +396,53 @@ static int yaffs_VerifyCompare(const __u |
| 20057 | } |
| 20058 | #endif /* NOTYET */ |
| 20059 | |
| 20060 | -int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, |
| 20061 | - int chunkInNAND, |
| 20062 | +int yaffs_tags_compat_wr(yaffs_dev_t *dev, |
| 20063 | + int nand_chunk, |
| 20064 | const __u8 *data, |
| 20065 | - const yaffs_ExtendedTags *eTags) |
| 20066 | + const yaffs_ext_tags *eTags) |
| 20067 | { |
| 20068 | - yaffs_Spare spare; |
| 20069 | - yaffs_Tags tags; |
| 20070 | + yaffs_spare spare; |
| 20071 | + yaffs_tags_t tags; |
| 20072 | |
| 20073 | - yaffs_SpareInitialise(&spare); |
| 20074 | + yaffs_spare_init(&spare); |
| 20075 | |
| 20076 | - if (eTags->chunkDeleted) |
| 20077 | - spare.pageStatus = 0; |
| 20078 | + if (eTags->is_deleted) |
| 20079 | + spare.page_status = 0; |
| 20080 | else { |
| 20081 | - tags.objectId = eTags->objectId; |
| 20082 | - tags.chunkId = eTags->chunkId; |
| 20083 | + tags.obj_id = eTags->obj_id; |
| 20084 | + tags.chunk_id = eTags->chunk_id; |
| 20085 | |
| 20086 | - tags.byteCountLSB = eTags->byteCount & 0x3ff; |
| 20087 | + tags.n_bytes_lsb = eTags->n_bytes & 0x3ff; |
| 20088 | |
| 20089 | - if (dev->nDataBytesPerChunk >= 1024) |
| 20090 | - tags.byteCountMSB = (eTags->byteCount >> 10) & 3; |
| 20091 | + if (dev->data_bytes_per_chunk >= 1024) |
| 20092 | + tags.n_bytes_msb = (eTags->n_bytes >> 10) & 3; |
| 20093 | else |
| 20094 | - tags.byteCountMSB = 3; |
| 20095 | + tags.n_bytes_msb = 3; |
| 20096 | |
| 20097 | |
| 20098 | - tags.serialNumber = eTags->serialNumber; |
| 20099 | + tags.serial_number = eTags->serial_number; |
| 20100 | |
| 20101 | - if (!dev->useNANDECC && data) |
| 20102 | - yaffs_CalcECC(data, &spare); |
| 20103 | + if (!dev->param.use_nand_ecc && data) |
| 20104 | + yaffs_calc_ecc(data, &spare); |
| 20105 | |
| 20106 | - yaffs_LoadTagsIntoSpare(&spare, &tags); |
| 20107 | + yaffs_load_tags_to_spare(&spare, &tags); |
| 20108 | |
| 20109 | } |
| 20110 | |
| 20111 | - return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare); |
| 20112 | + return yaffs_wr_nand(dev, nand_chunk, data, &spare); |
| 20113 | } |
| 20114 | |
| 20115 | -int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev, |
| 20116 | - int chunkInNAND, |
| 20117 | +int yaffs_tags_compat_rd(yaffs_dev_t *dev, |
| 20118 | + int nand_chunk, |
| 20119 | __u8 *data, |
| 20120 | - yaffs_ExtendedTags *eTags) |
| 20121 | + yaffs_ext_tags *eTags) |
| 20122 | { |
| 20123 | |
| 20124 | - yaffs_Spare spare; |
| 20125 | - yaffs_Tags tags; |
| 20126 | - yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN; |
| 20127 | + yaffs_spare spare; |
| 20128 | + yaffs_tags_t tags; |
| 20129 | + yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN; |
| 20130 | |
| 20131 | - static yaffs_Spare spareFF; |
| 20132 | + static yaffs_spare spareFF; |
| 20133 | static int init; |
| 20134 | |
| 20135 | if (!init) { |
| 20136 | @@ -452,33 +450,33 @@ int yaffs_TagsCompatabilityReadChunkWith |
| 20137 | init = 1; |
| 20138 | } |
| 20139 | |
| 20140 | - if (yaffs_ReadChunkFromNAND |
| 20141 | - (dev, chunkInNAND, data, &spare, &eccResult, 1)) { |
| 20142 | + if (yaffs_rd_chunk_nand |
| 20143 | + (dev, nand_chunk, data, &spare, &ecc_result, 1)) { |
| 20144 | /* eTags may be NULL */ |
| 20145 | if (eTags) { |
| 20146 | |
| 20147 | int deleted = |
| 20148 | - (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0; |
| 20149 | + (yaffs_count_bits(spare.page_status) < 7) ? 1 : 0; |
| 20150 | |
| 20151 | - eTags->chunkDeleted = deleted; |
| 20152 | - eTags->eccResult = eccResult; |
| 20153 | - eTags->blockBad = 0; /* We're reading it */ |
| 20154 | + eTags->is_deleted = deleted; |
| 20155 | + eTags->ecc_result = ecc_result; |
| 20156 | + eTags->block_bad = 0; /* We're reading it */ |
| 20157 | /* therefore it is not a bad block */ |
| 20158 | - eTags->chunkUsed = |
| 20159 | + eTags->chunk_used = |
| 20160 | (memcmp(&spareFF, &spare, sizeof(spareFF)) != |
| 20161 | 0) ? 1 : 0; |
| 20162 | |
| 20163 | - if (eTags->chunkUsed) { |
| 20164 | - yaffs_GetTagsFromSpare(dev, &spare, &tags); |
| 20165 | + if (eTags->chunk_used) { |
| 20166 | + yaffs_get_tags_from_spare(dev, &spare, &tags); |
| 20167 | |
| 20168 | - eTags->objectId = tags.objectId; |
| 20169 | - eTags->chunkId = tags.chunkId; |
| 20170 | - eTags->byteCount = tags.byteCountLSB; |
| 20171 | + eTags->obj_id = tags.obj_id; |
| 20172 | + eTags->chunk_id = tags.chunk_id; |
| 20173 | + eTags->n_bytes = tags.n_bytes_lsb; |
| 20174 | |
| 20175 | - if (dev->nDataBytesPerChunk >= 1024) |
| 20176 | - eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10); |
| 20177 | + if (dev->data_bytes_per_chunk >= 1024) |
| 20178 | + eTags->n_bytes |= (((unsigned) tags.n_bytes_msb) << 10); |
| 20179 | |
| 20180 | - eTags->serialNumber = tags.serialNumber; |
| 20181 | + eTags->serial_number = tags.serial_number; |
| 20182 | } |
| 20183 | } |
| 20184 | |
| 20185 | @@ -488,49 +486,49 @@ int yaffs_TagsCompatabilityReadChunkWith |
| 20186 | } |
| 20187 | } |
| 20188 | |
| 20189 | -int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, |
| 20190 | - int blockInNAND) |
| 20191 | +int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev, |
| 20192 | + int flash_block) |
| 20193 | { |
| 20194 | |
| 20195 | - yaffs_Spare spare; |
| 20196 | + yaffs_spare spare; |
| 20197 | |
| 20198 | - memset(&spare, 0xff, sizeof(yaffs_Spare)); |
| 20199 | + memset(&spare, 0xff, sizeof(yaffs_spare)); |
| 20200 | |
| 20201 | - spare.blockStatus = 'Y'; |
| 20202 | + spare.block_status = 'Y'; |
| 20203 | |
| 20204 | - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL, |
| 20205 | + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL, |
| 20206 | &spare); |
| 20207 | - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, |
| 20208 | + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1, |
| 20209 | NULL, &spare); |
| 20210 | |
| 20211 | return YAFFS_OK; |
| 20212 | |
| 20213 | } |
| 20214 | |
| 20215 | -int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, |
| 20216 | - int blockNo, |
| 20217 | - yaffs_BlockState *state, |
| 20218 | - __u32 *sequenceNumber) |
| 20219 | +int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev, |
| 20220 | + int block_no, |
| 20221 | + yaffs_block_state_t *state, |
| 20222 | + __u32 *seq_number) |
| 20223 | { |
| 20224 | |
| 20225 | - yaffs_Spare spare0, spare1; |
| 20226 | - static yaffs_Spare spareFF; |
| 20227 | + yaffs_spare spare0, spare1; |
| 20228 | + static yaffs_spare spareFF; |
| 20229 | static int init; |
| 20230 | - yaffs_ECCResult dummy; |
| 20231 | + yaffs_ecc_result dummy; |
| 20232 | |
| 20233 | if (!init) { |
| 20234 | memset(&spareFF, 0xFF, sizeof(spareFF)); |
| 20235 | init = 1; |
| 20236 | } |
| 20237 | |
| 20238 | - *sequenceNumber = 0; |
| 20239 | + *seq_number = 0; |
| 20240 | |
| 20241 | - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL, |
| 20242 | + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL, |
| 20243 | &spare0, &dummy, 1); |
| 20244 | - yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL, |
| 20245 | + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, NULL, |
| 20246 | &spare1, &dummy, 1); |
| 20247 | |
| 20248 | - if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7) |
| 20249 | + if (yaffs_count_bits(spare0.block_status & spare1.block_status) < 7) |
| 20250 | *state = YAFFS_BLOCK_STATE_DEAD; |
| 20251 | else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0) |
| 20252 | *state = YAFFS_BLOCK_STATE_EMPTY; |
| 20253 | --- a/fs/yaffs2/yaffs_tagscompat.h |
| 20254 | +++ b/fs/yaffs2/yaffs_tagscompat.h |
| 20255 | @@ -1,7 +1,7 @@ |
| 20256 | /* |
| 20257 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 20258 | * |
| 20259 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 20260 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 20261 | * for Toby Churchill Ltd and Brightstar Engineering |
| 20262 | * |
| 20263 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 20264 | @@ -17,23 +17,23 @@ |
| 20265 | #define __YAFFS_TAGSCOMPAT_H__ |
| 20266 | |
| 20267 | #include "yaffs_guts.h" |
| 20268 | -int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev, |
| 20269 | - int chunkInNAND, |
| 20270 | +int yaffs_tags_compat_wr(yaffs_dev_t *dev, |
| 20271 | + int nand_chunk, |
| 20272 | const __u8 *data, |
| 20273 | - const yaffs_ExtendedTags *tags); |
| 20274 | -int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev, |
| 20275 | - int chunkInNAND, |
| 20276 | + const yaffs_ext_tags *tags); |
| 20277 | +int yaffs_tags_compat_rd(yaffs_dev_t *dev, |
| 20278 | + int nand_chunk, |
| 20279 | __u8 *data, |
| 20280 | - yaffs_ExtendedTags *tags); |
| 20281 | -int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, |
| 20282 | - int blockNo); |
| 20283 | -int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, |
| 20284 | - int blockNo, |
| 20285 | - yaffs_BlockState *state, |
| 20286 | - __u32 *sequenceNumber); |
| 20287 | + yaffs_ext_tags *tags); |
| 20288 | +int yaffs_tags_compat_mark_bad(struct yaffs_dev_s *dev, |
| 20289 | + int block_no); |
| 20290 | +int yaffs_tags_compat_query_block(struct yaffs_dev_s *dev, |
| 20291 | + int block_no, |
| 20292 | + yaffs_block_state_t *state, |
| 20293 | + __u32 *seq_number); |
| 20294 | |
| 20295 | -void yaffs_CalcTagsECC(yaffs_Tags *tags); |
| 20296 | -int yaffs_CheckECCOnTags(yaffs_Tags *tags); |
| 20297 | -int yaffs_CountBits(__u8 byte); |
| 20298 | +void yaffs_calc_tags_ecc(yaffs_tags_t *tags); |
| 20299 | +int yaffs_check_tags_ecc(yaffs_tags_t *tags); |
| 20300 | +int yaffs_count_bits(__u8 byte); |
| 20301 | |
| 20302 | #endif |
| 20303 | --- a/fs/yaffs2/yaffs_tagsvalidity.c |
| 20304 | +++ b/fs/yaffs2/yaffs_tagsvalidity.c |
| 20305 | @@ -1,7 +1,7 @@ |
| 20306 | /* |
| 20307 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 20308 | * |
| 20309 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 20310 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 20311 | * for Toby Churchill Ltd and Brightstar Engineering |
| 20312 | * |
| 20313 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 20314 | @@ -13,16 +13,16 @@ |
| 20315 | |
| 20316 | #include "yaffs_tagsvalidity.h" |
| 20317 | |
| 20318 | -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags) |
| 20319 | +void yaffs_init_tags(yaffs_ext_tags *tags) |
| 20320 | { |
| 20321 | - memset(tags, 0, sizeof(yaffs_ExtendedTags)); |
| 20322 | - tags->validMarker0 = 0xAAAAAAAA; |
| 20323 | - tags->validMarker1 = 0x55555555; |
| 20324 | + memset(tags, 0, sizeof(yaffs_ext_tags)); |
| 20325 | + tags->validity1 = 0xAAAAAAAA; |
| 20326 | + tags->validty1 = 0x55555555; |
| 20327 | } |
| 20328 | |
| 20329 | -int yaffs_ValidateTags(yaffs_ExtendedTags *tags) |
| 20330 | +int yaffs_validate_tags(yaffs_ext_tags *tags) |
| 20331 | { |
| 20332 | - return (tags->validMarker0 == 0xAAAAAAAA && |
| 20333 | - tags->validMarker1 == 0x55555555); |
| 20334 | + return (tags->validity1 == 0xAAAAAAAA && |
| 20335 | + tags->validty1 == 0x55555555); |
| 20336 | |
| 20337 | } |
| 20338 | --- a/fs/yaffs2/yaffs_tagsvalidity.h |
| 20339 | +++ b/fs/yaffs2/yaffs_tagsvalidity.h |
| 20340 | @@ -1,7 +1,7 @@ |
| 20341 | /* |
| 20342 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 20343 | * |
| 20344 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 20345 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 20346 | * for Toby Churchill Ltd and Brightstar Engineering |
| 20347 | * |
| 20348 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 20349 | @@ -19,6 +19,6 @@ |
| 20350 | |
| 20351 | #include "yaffs_guts.h" |
| 20352 | |
| 20353 | -void yaffs_InitialiseTags(yaffs_ExtendedTags *tags); |
| 20354 | -int yaffs_ValidateTags(yaffs_ExtendedTags *tags); |
| 20355 | +void yaffs_init_tags(yaffs_ext_tags *tags); |
| 20356 | +int yaffs_validate_tags(yaffs_ext_tags *tags); |
| 20357 | #endif |
| 20358 | --- /dev/null |
| 20359 | +++ b/fs/yaffs2/yaffs_trace.h |
| 20360 | @@ -0,0 +1,60 @@ |
| 20361 | +/* |
| 20362 | + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 20363 | + * |
| 20364 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 20365 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 20366 | + * |
| 20367 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 20368 | + * |
| 20369 | + * This program is free software; you can redistribute it and/or modify |
| 20370 | + * it under the terms of the GNU Lesser General Public License version 2.1 as |
| 20371 | + * published by the Free Software Foundation. |
| 20372 | + * |
| 20373 | + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| 20374 | + */ |
| 20375 | + |
| 20376 | + |
| 20377 | +#ifndef __YTRACE_H__ |
| 20378 | +#define __YTRACE_H__ |
| 20379 | + |
| 20380 | +extern unsigned int yaffs_trace_mask; |
| 20381 | +extern unsigned int yaffs_wr_attempts; |
| 20382 | + |
| 20383 | +/* |
| 20384 | + * Tracing flags. |
| 20385 | + * The flags masked in YAFFS_TRACE_ALWAYS are always traced. |
| 20386 | + */ |
| 20387 | + |
| 20388 | +#define YAFFS_TRACE_OS 0x00000002 |
| 20389 | +#define YAFFS_TRACE_ALLOCATE 0x00000004 |
| 20390 | +#define YAFFS_TRACE_SCAN 0x00000008 |
| 20391 | +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 |
| 20392 | +#define YAFFS_TRACE_ERASE 0x00000020 |
| 20393 | +#define YAFFS_TRACE_GC 0x00000040 |
| 20394 | +#define YAFFS_TRACE_WRITE 0x00000080 |
| 20395 | +#define YAFFS_TRACE_TRACING 0x00000100 |
| 20396 | +#define YAFFS_TRACE_DELETION 0x00000200 |
| 20397 | +#define YAFFS_TRACE_BUFFERS 0x00000400 |
| 20398 | +#define YAFFS_TRACE_NANDACCESS 0x00000800 |
| 20399 | +#define YAFFS_TRACE_GC_DETAIL 0x00001000 |
| 20400 | +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 |
| 20401 | +#define YAFFS_TRACE_MTD 0x00004000 |
| 20402 | +#define YAFFS_TRACE_CHECKPOINT 0x00008000 |
| 20403 | + |
| 20404 | +#define YAFFS_TRACE_VERIFY 0x00010000 |
| 20405 | +#define YAFFS_TRACE_VERIFY_NAND 0x00020000 |
| 20406 | +#define YAFFS_TRACE_VERIFY_FULL 0x00040000 |
| 20407 | +#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 |
| 20408 | + |
| 20409 | +#define YAFFS_TRACE_SYNC 0x00100000 |
| 20410 | +#define YAFFS_TRACE_BACKGROUND 0x00200000 |
| 20411 | +#define YAFFS_TRACE_LOCK 0x00400000 |
| 20412 | + |
| 20413 | +#define YAFFS_TRACE_ERROR 0x40000000 |
| 20414 | +#define YAFFS_TRACE_BUG 0x80000000 |
| 20415 | +#define YAFFS_TRACE_ALWAYS 0xF0000000 |
| 20416 | + |
| 20417 | + |
| 20418 | +#define T(mask, p) do { if ((mask) & (yaffs_trace_mask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0) |
| 20419 | + |
| 20420 | +#endif |
| 20421 | --- /dev/null |
| 20422 | +++ b/fs/yaffs2/yaffs_verify.c |
| 20423 | @@ -0,0 +1,626 @@ |
| 20424 | +/* |
| 20425 | + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 20426 | + * |
| 20427 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 20428 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 20429 | + * |
| 20430 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 20431 | + * |
| 20432 | + * This program is free software; you can redistribute it and/or modify |
| 20433 | + * it under the terms of the GNU General Public License version 2 as |
| 20434 | + * published by the Free Software Foundation. |
| 20435 | + */ |
| 20436 | + |
| 20437 | + |
| 20438 | +#include "yaffs_verify.h" |
| 20439 | +#include "yaffs_trace.h" |
| 20440 | +#include "yaffs_bitmap.h" |
| 20441 | +#include "yaffs_getblockinfo.h" |
| 20442 | +#include "yaffs_nand.h" |
| 20443 | + |
| 20444 | +int yaffs_skip_verification(yaffs_dev_t *dev) |
| 20445 | +{ |
| 20446 | + dev=dev; |
| 20447 | + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); |
| 20448 | +} |
| 20449 | + |
| 20450 | +static int yaffs_skip_full_verification(yaffs_dev_t *dev) |
| 20451 | +{ |
| 20452 | + dev=dev; |
| 20453 | + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL)); |
| 20454 | +} |
| 20455 | + |
| 20456 | +static int yaffs_skip_nand_verification(yaffs_dev_t *dev) |
| 20457 | +{ |
| 20458 | + dev=dev; |
| 20459 | + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND)); |
| 20460 | +} |
| 20461 | + |
| 20462 | + |
| 20463 | +static const char *block_stateName[] = { |
| 20464 | +"Unknown", |
| 20465 | +"Needs scanning", |
| 20466 | +"Scanning", |
| 20467 | +"Empty", |
| 20468 | +"Allocating", |
| 20469 | +"Full", |
| 20470 | +"Dirty", |
| 20471 | +"Checkpoint", |
| 20472 | +"Collecting", |
| 20473 | +"Dead" |
| 20474 | +}; |
| 20475 | + |
| 20476 | + |
| 20477 | +void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n) |
| 20478 | +{ |
| 20479 | + int actuallyUsed; |
| 20480 | + int inUse; |
| 20481 | + |
| 20482 | + if (yaffs_skip_verification(dev)) |
| 20483 | + return; |
| 20484 | + |
| 20485 | + /* Report illegal runtime states */ |
| 20486 | + if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES) |
| 20487 | + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->block_state)); |
| 20488 | + |
| 20489 | + switch (bi->block_state) { |
| 20490 | + case YAFFS_BLOCK_STATE_UNKNOWN: |
| 20491 | + case YAFFS_BLOCK_STATE_SCANNING: |
| 20492 | + case YAFFS_BLOCK_STATE_NEEDS_SCANNING: |
| 20493 | + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR), |
| 20494 | + n, block_stateName[bi->block_state])); |
| 20495 | + } |
| 20496 | + |
| 20497 | + /* Check pages in use and soft deletions are legal */ |
| 20498 | + |
| 20499 | + actuallyUsed = bi->pages_in_use - bi->soft_del_pages; |
| 20500 | + |
| 20501 | + if (bi->pages_in_use < 0 || bi->pages_in_use > dev->param.chunks_per_block || |
| 20502 | + bi->soft_del_pages < 0 || bi->soft_del_pages > dev->param.chunks_per_block || |
| 20503 | + actuallyUsed < 0 || actuallyUsed > dev->param.chunks_per_block) |
| 20504 | + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pages_in_used %d soft_del_pages %d"TENDSTR), |
| 20505 | + n, bi->pages_in_use, bi->soft_del_pages)); |
| 20506 | + |
| 20507 | + |
| 20508 | + /* Check chunk bitmap legal */ |
| 20509 | + inUse = yaffs_count_chunk_bits(dev, n); |
| 20510 | + if (inUse != bi->pages_in_use) |
| 20511 | + T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pages_in_use %d counted chunk bits %d"TENDSTR), |
| 20512 | + n, bi->pages_in_use, inUse)); |
| 20513 | + |
| 20514 | +} |
| 20515 | + |
| 20516 | + |
| 20517 | + |
| 20518 | +void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n) |
| 20519 | +{ |
| 20520 | + yaffs_verify_blk(dev, bi, n); |
| 20521 | + |
| 20522 | + /* After collection the block should be in the erased state */ |
| 20523 | + |
| 20524 | + if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING && |
| 20525 | + bi->block_state != YAFFS_BLOCK_STATE_EMPTY) { |
| 20526 | + T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), |
| 20527 | + n, bi->block_state)); |
| 20528 | + } |
| 20529 | +} |
| 20530 | + |
| 20531 | +void yaffs_verify_blocks(yaffs_dev_t *dev) |
| 20532 | +{ |
| 20533 | + int i; |
| 20534 | + int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; |
| 20535 | + int nIllegalBlockStates = 0; |
| 20536 | + |
| 20537 | + if (yaffs_skip_verification(dev)) |
| 20538 | + return; |
| 20539 | + |
| 20540 | + memset(nBlocksPerState, 0, sizeof(nBlocksPerState)); |
| 20541 | + |
| 20542 | + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { |
| 20543 | + yaffs_block_info_t *bi = yaffs_get_block_info(dev, i); |
| 20544 | + yaffs_verify_blk(dev, bi, i); |
| 20545 | + |
| 20546 | + if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES) |
| 20547 | + nBlocksPerState[bi->block_state]++; |
| 20548 | + else |
| 20549 | + nIllegalBlockStates++; |
| 20550 | + } |
| 20551 | + |
| 20552 | + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); |
| 20553 | + T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR))); |
| 20554 | + |
| 20555 | + T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates)); |
| 20556 | + if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) |
| 20557 | + T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR))); |
| 20558 | + |
| 20559 | + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) |
| 20560 | + T(YAFFS_TRACE_VERIFY, |
| 20561 | + (TSTR("%s %d blocks"TENDSTR), |
| 20562 | + block_stateName[i], nBlocksPerState[i])); |
| 20563 | + |
| 20564 | + if (dev->blocks_in_checkpt != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) |
| 20565 | + T(YAFFS_TRACE_VERIFY, |
| 20566 | + (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), |
| 20567 | + dev->blocks_in_checkpt, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); |
| 20568 | + |
| 20569 | + if (dev->n_erased_blocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) |
| 20570 | + T(YAFFS_TRACE_VERIFY, |
| 20571 | + (TSTR("Erased block count wrong dev %d count %d"TENDSTR), |
| 20572 | + dev->n_erased_blocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); |
| 20573 | + |
| 20574 | + if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) |
| 20575 | + T(YAFFS_TRACE_VERIFY, |
| 20576 | + (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), |
| 20577 | + nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); |
| 20578 | + |
| 20579 | + T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); |
| 20580 | + |
| 20581 | +} |
| 20582 | + |
| 20583 | +/* |
| 20584 | + * Verify the object header. oh must be valid, but obj and tags may be NULL in which |
| 20585 | + * case those tests will not be performed. |
| 20586 | + */ |
| 20587 | +void yaffs_verify_oh(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck) |
| 20588 | +{ |
| 20589 | + if (obj && yaffs_skip_verification(obj->my_dev)) |
| 20590 | + return; |
| 20591 | + |
| 20592 | + if (!(tags && obj && oh)) { |
| 20593 | + T(YAFFS_TRACE_VERIFY, |
| 20594 | + (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR), |
| 20595 | + tags, obj, oh)); |
| 20596 | + return; |
| 20597 | + } |
| 20598 | + |
| 20599 | + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || |
| 20600 | + oh->type > YAFFS_OBJECT_TYPE_MAX) |
| 20601 | + T(YAFFS_TRACE_VERIFY, |
| 20602 | + (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), |
| 20603 | + tags->obj_id, oh->type)); |
| 20604 | + |
| 20605 | + if (tags->obj_id != obj->obj_id) |
| 20606 | + T(YAFFS_TRACE_VERIFY, |
| 20607 | + (TSTR("Obj %d header mismatch obj_id %d"TENDSTR), |
| 20608 | + tags->obj_id, obj->obj_id)); |
| 20609 | + |
| 20610 | + |
| 20611 | + /* |
| 20612 | + * Check that the object's parent ids match if parentCheck requested. |
| 20613 | + * |
| 20614 | + * Tests do not apply to the root object. |
| 20615 | + */ |
| 20616 | + |
| 20617 | + if (parentCheck && tags->obj_id > 1 && !obj->parent) |
| 20618 | + T(YAFFS_TRACE_VERIFY, |
| 20619 | + (TSTR("Obj %d header mismatch parent_id %d obj->parent is NULL"TENDSTR), |
| 20620 | + tags->obj_id, oh->parent_obj_id)); |
| 20621 | + |
| 20622 | + if (parentCheck && obj->parent && |
| 20623 | + oh->parent_obj_id != obj->parent->obj_id && |
| 20624 | + (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED || |
| 20625 | + obj->parent->obj_id != YAFFS_OBJECTID_DELETED)) |
| 20626 | + T(YAFFS_TRACE_VERIFY, |
| 20627 | + (TSTR("Obj %d header mismatch parent_id %d parent_obj_id %d"TENDSTR), |
| 20628 | + tags->obj_id, oh->parent_obj_id, obj->parent->obj_id)); |
| 20629 | + |
| 20630 | + if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */ |
| 20631 | + T(YAFFS_TRACE_VERIFY, |
| 20632 | + (TSTR("Obj %d header name is NULL"TENDSTR), |
| 20633 | + obj->obj_id)); |
| 20634 | + |
| 20635 | + if (tags->obj_id > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ |
| 20636 | + T(YAFFS_TRACE_VERIFY, |
| 20637 | + (TSTR("Obj %d header name is 0xFF"TENDSTR), |
| 20638 | + obj->obj_id)); |
| 20639 | +} |
| 20640 | + |
| 20641 | + |
| 20642 | +#if 0 |
| 20643 | +/* Not being used, but don't want to throw away yet */ |
| 20644 | +int yaffs_verify_tnode_worker(yaffs_obj_t *obj, yaffs_tnode_t *tn, |
| 20645 | + __u32 level, int chunk_offset) |
| 20646 | +{ |
| 20647 | + int i; |
| 20648 | + yaffs_dev_t *dev = obj->my_dev; |
| 20649 | + int ok = 1; |
| 20650 | + |
| 20651 | + if (tn) { |
| 20652 | + if (level > 0) { |
| 20653 | + |
| 20654 | + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { |
| 20655 | + if (tn->internal[i]) { |
| 20656 | + ok = yaffs_verify_tnode_worker(obj, |
| 20657 | + tn->internal[i], |
| 20658 | + level - 1, |
| 20659 | + (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i); |
| 20660 | + } |
| 20661 | + } |
| 20662 | + } else if (level == 0) { |
| 20663 | + yaffs_ext_tags tags; |
| 20664 | + __u32 obj_id = obj->obj_id; |
| 20665 | + |
| 20666 | + chunk_offset <<= YAFFS_TNODES_LEVEL0_BITS; |
| 20667 | + |
| 20668 | + for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) { |
| 20669 | + __u32 theChunk = yaffs_get_group_base(dev, tn, i); |
| 20670 | + |
| 20671 | + if (theChunk > 0) { |
| 20672 | + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.obj_id,tags.chunk_id,theChunk)); */ |
| 20673 | + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags); |
| 20674 | + if (tags.obj_id != obj_id || tags.chunk_id != chunk_offset) { |
| 20675 | + T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), |
| 20676 | + obj_id, chunk_offset, theChunk, |
| 20677 | + tags.obj_id, tags.chunk_id)); |
| 20678 | + } |
| 20679 | + } |
| 20680 | + chunk_offset++; |
| 20681 | + } |
| 20682 | + } |
| 20683 | + } |
| 20684 | + |
| 20685 | + return ok; |
| 20686 | + |
| 20687 | +} |
| 20688 | + |
| 20689 | +#endif |
| 20690 | + |
| 20691 | +void yaffs_verify_file(yaffs_obj_t *obj) |
| 20692 | +{ |
| 20693 | + int requiredTallness; |
| 20694 | + int actualTallness; |
| 20695 | + __u32 lastChunk; |
| 20696 | + __u32 x; |
| 20697 | + __u32 i; |
| 20698 | + yaffs_dev_t *dev; |
| 20699 | + yaffs_ext_tags tags; |
| 20700 | + yaffs_tnode_t *tn; |
| 20701 | + __u32 obj_id; |
| 20702 | + |
| 20703 | + if (!obj) |
| 20704 | + return; |
| 20705 | + |
| 20706 | + if (yaffs_skip_verification(obj->my_dev)) |
| 20707 | + return; |
| 20708 | + |
| 20709 | + dev = obj->my_dev; |
| 20710 | + obj_id = obj->obj_id; |
| 20711 | + |
| 20712 | + /* Check file size is consistent with tnode depth */ |
| 20713 | + lastChunk = obj->variant.file_variant.file_size / dev->data_bytes_per_chunk + 1; |
| 20714 | + x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; |
| 20715 | + requiredTallness = 0; |
| 20716 | + while (x > 0) { |
| 20717 | + x >>= YAFFS_TNODES_INTERNAL_BITS; |
| 20718 | + requiredTallness++; |
| 20719 | + } |
| 20720 | + |
| 20721 | + actualTallness = obj->variant.file_variant.top_level; |
| 20722 | + |
| 20723 | + /* Check that the chunks in the tnode tree are all correct. |
| 20724 | + * We do this by scanning through the tnode tree and |
| 20725 | + * checking the tags for every chunk match. |
| 20726 | + */ |
| 20727 | + |
| 20728 | + if (yaffs_skip_nand_verification(dev)) |
| 20729 | + return; |
| 20730 | + |
| 20731 | + for (i = 1; i <= lastChunk; i++) { |
| 20732 | + tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i); |
| 20733 | + |
| 20734 | + if (tn) { |
| 20735 | + __u32 theChunk = yaffs_get_group_base(dev, tn, i); |
| 20736 | + if (theChunk > 0) { |
| 20737 | + /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),obj_id,i,theChunk)); */ |
| 20738 | + yaffs_rd_chunk_tags_nand(dev, theChunk, NULL, &tags); |
| 20739 | + if (tags.obj_id != obj_id || tags.chunk_id != i) { |
| 20740 | + T(~0, (TSTR("Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), |
| 20741 | + obj_id, i, theChunk, |
| 20742 | + tags.obj_id, tags.chunk_id)); |
| 20743 | + } |
| 20744 | + } |
| 20745 | + } |
| 20746 | + } |
| 20747 | +} |
| 20748 | + |
| 20749 | + |
| 20750 | +void yaffs_verify_link(yaffs_obj_t *obj) |
| 20751 | +{ |
| 20752 | + if (obj && yaffs_skip_verification(obj->my_dev)) |
| 20753 | + return; |
| 20754 | + |
| 20755 | + /* Verify sane equivalent object */ |
| 20756 | +} |
| 20757 | + |
| 20758 | +void yaffs_verify_symlink(yaffs_obj_t *obj) |
| 20759 | +{ |
| 20760 | + if (obj && yaffs_skip_verification(obj->my_dev)) |
| 20761 | + return; |
| 20762 | + |
| 20763 | + /* Verify symlink string */ |
| 20764 | +} |
| 20765 | + |
| 20766 | +void yaffs_verify_special(yaffs_obj_t *obj) |
| 20767 | +{ |
| 20768 | + if (obj && yaffs_skip_verification(obj->my_dev)) |
| 20769 | + return; |
| 20770 | +} |
| 20771 | + |
| 20772 | +void yaffs_verify_obj(yaffs_obj_t *obj) |
| 20773 | +{ |
| 20774 | + yaffs_dev_t *dev; |
| 20775 | + |
| 20776 | + __u32 chunkMin; |
| 20777 | + __u32 chunkMax; |
| 20778 | + |
| 20779 | + __u32 chunk_idOk; |
| 20780 | + __u32 chunkInRange; |
| 20781 | + __u32 chunkShouldNotBeDeleted; |
| 20782 | + __u32 chunkValid; |
| 20783 | + |
| 20784 | + if (!obj) |
| 20785 | + return; |
| 20786 | + |
| 20787 | + if (obj->being_created) |
| 20788 | + return; |
| 20789 | + |
| 20790 | + dev = obj->my_dev; |
| 20791 | + |
| 20792 | + if (yaffs_skip_verification(dev)) |
| 20793 | + return; |
| 20794 | + |
| 20795 | + /* Check sane object header chunk */ |
| 20796 | + |
| 20797 | + chunkMin = dev->internal_start_block * dev->param.chunks_per_block; |
| 20798 | + chunkMax = (dev->internal_end_block+1) * dev->param.chunks_per_block - 1; |
| 20799 | + |
| 20800 | + chunkInRange = (((unsigned)(obj->hdr_chunk)) >= chunkMin && ((unsigned)(obj->hdr_chunk)) <= chunkMax); |
| 20801 | + chunk_idOk = chunkInRange || (obj->hdr_chunk == 0); |
| 20802 | + chunkValid = chunkInRange && |
| 20803 | + yaffs_check_chunk_bit(dev, |
| 20804 | + obj->hdr_chunk / dev->param.chunks_per_block, |
| 20805 | + obj->hdr_chunk % dev->param.chunks_per_block); |
| 20806 | + chunkShouldNotBeDeleted = chunkInRange && !chunkValid; |
| 20807 | + |
| 20808 | + if (!obj->fake && |
| 20809 | + (!chunk_idOk || chunkShouldNotBeDeleted)) { |
| 20810 | + T(YAFFS_TRACE_VERIFY, |
| 20811 | + (TSTR("Obj %d has chunk_id %d %s %s"TENDSTR), |
| 20812 | + obj->obj_id, obj->hdr_chunk, |
| 20813 | + chunk_idOk ? "" : ",out of range", |
| 20814 | + chunkShouldNotBeDeleted ? ",marked as deleted" : "")); |
| 20815 | + } |
| 20816 | + |
| 20817 | + if (chunkValid && !yaffs_skip_nand_verification(dev)) { |
| 20818 | + yaffs_ext_tags tags; |
| 20819 | + yaffs_obj_header *oh; |
| 20820 | + __u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__); |
| 20821 | + |
| 20822 | + oh = (yaffs_obj_header *)buffer; |
| 20823 | + |
| 20824 | + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, |
| 20825 | + &tags); |
| 20826 | + |
| 20827 | + yaffs_verify_oh(obj, oh, &tags, 1); |
| 20828 | + |
| 20829 | + yaffs_release_temp_buffer(dev, buffer, __LINE__); |
| 20830 | + } |
| 20831 | + |
| 20832 | + /* Verify it has a parent */ |
| 20833 | + if (obj && !obj->fake && |
| 20834 | + (!obj->parent || obj->parent->my_dev != dev)) { |
| 20835 | + T(YAFFS_TRACE_VERIFY, |
| 20836 | + (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), |
| 20837 | + obj->obj_id, obj->parent)); |
| 20838 | + } |
| 20839 | + |
| 20840 | + /* Verify parent is a directory */ |
| 20841 | + if (obj->parent && obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 20842 | + T(YAFFS_TRACE_VERIFY, |
| 20843 | + (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), |
| 20844 | + obj->obj_id, obj->parent->variant_type)); |
| 20845 | + } |
| 20846 | + |
| 20847 | + switch (obj->variant_type) { |
| 20848 | + case YAFFS_OBJECT_TYPE_FILE: |
| 20849 | + yaffs_verify_file(obj); |
| 20850 | + break; |
| 20851 | + case YAFFS_OBJECT_TYPE_SYMLINK: |
| 20852 | + yaffs_verify_symlink(obj); |
| 20853 | + break; |
| 20854 | + case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 20855 | + yaffs_verify_dir(obj); |
| 20856 | + break; |
| 20857 | + case YAFFS_OBJECT_TYPE_HARDLINK: |
| 20858 | + yaffs_verify_link(obj); |
| 20859 | + break; |
| 20860 | + case YAFFS_OBJECT_TYPE_SPECIAL: |
| 20861 | + yaffs_verify_special(obj); |
| 20862 | + break; |
| 20863 | + case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 20864 | + default: |
| 20865 | + T(YAFFS_TRACE_VERIFY, |
| 20866 | + (TSTR("Obj %d has illegaltype %d"TENDSTR), |
| 20867 | + obj->obj_id, obj->variant_type)); |
| 20868 | + break; |
| 20869 | + } |
| 20870 | +} |
| 20871 | + |
| 20872 | +void yaffs_verify_objects(yaffs_dev_t *dev) |
| 20873 | +{ |
| 20874 | + yaffs_obj_t *obj; |
| 20875 | + int i; |
| 20876 | + struct ylist_head *lh; |
| 20877 | + |
| 20878 | + if (yaffs_skip_verification(dev)) |
| 20879 | + return; |
| 20880 | + |
| 20881 | + /* Iterate through the objects in each hash entry */ |
| 20882 | + |
| 20883 | + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { |
| 20884 | + ylist_for_each(lh, &dev->obj_bucket[i].list) { |
| 20885 | + if (lh) { |
| 20886 | + obj = ylist_entry(lh, yaffs_obj_t, hash_link); |
| 20887 | + yaffs_verify_obj(obj); |
| 20888 | + } |
| 20889 | + } |
| 20890 | + } |
| 20891 | +} |
| 20892 | + |
| 20893 | + |
| 20894 | +void yaffs_verify_obj_in_dir(yaffs_obj_t *obj) |
| 20895 | +{ |
| 20896 | + struct ylist_head *lh; |
| 20897 | + yaffs_obj_t *listObj; |
| 20898 | + |
| 20899 | + int count = 0; |
| 20900 | + |
| 20901 | + if (!obj) { |
| 20902 | + T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR))); |
| 20903 | + YBUG(); |
| 20904 | + return; |
| 20905 | + } |
| 20906 | + |
| 20907 | + if (yaffs_skip_verification(obj->my_dev)) |
| 20908 | + return; |
| 20909 | + |
| 20910 | + if (!obj->parent) { |
| 20911 | + T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR))); |
| 20912 | + YBUG(); |
| 20913 | + return; |
| 20914 | + } |
| 20915 | + |
| 20916 | + if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 20917 | + T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR))); |
| 20918 | + YBUG(); |
| 20919 | + } |
| 20920 | + |
| 20921 | + /* Iterate through the objects in each hash entry */ |
| 20922 | + |
| 20923 | + ylist_for_each(lh, &obj->parent->variant.dir_variant.children) { |
| 20924 | + if (lh) { |
| 20925 | + listObj = ylist_entry(lh, yaffs_obj_t, siblings); |
| 20926 | + yaffs_verify_obj(listObj); |
| 20927 | + if (obj == listObj) |
| 20928 | + count++; |
| 20929 | + } |
| 20930 | + } |
| 20931 | + |
| 20932 | + if (count != 1) { |
| 20933 | + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count)); |
| 20934 | + YBUG(); |
| 20935 | + } |
| 20936 | +} |
| 20937 | + |
| 20938 | +void yaffs_verify_dir(yaffs_obj_t *directory) |
| 20939 | +{ |
| 20940 | + struct ylist_head *lh; |
| 20941 | + yaffs_obj_t *listObj; |
| 20942 | + |
| 20943 | + if (!directory) { |
| 20944 | + YBUG(); |
| 20945 | + return; |
| 20946 | + } |
| 20947 | + |
| 20948 | + if (yaffs_skip_full_verification(directory->my_dev)) |
| 20949 | + return; |
| 20950 | + |
| 20951 | + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 20952 | + T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variant_type)); |
| 20953 | + YBUG(); |
| 20954 | + } |
| 20955 | + |
| 20956 | + /* Iterate through the objects in each hash entry */ |
| 20957 | + |
| 20958 | + ylist_for_each(lh, &directory->variant.dir_variant.children) { |
| 20959 | + if (lh) { |
| 20960 | + listObj = ylist_entry(lh, yaffs_obj_t, siblings); |
| 20961 | + if (listObj->parent != directory) { |
| 20962 | + T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent)); |
| 20963 | + YBUG(); |
| 20964 | + } |
| 20965 | + yaffs_verify_obj_in_dir(listObj); |
| 20966 | + } |
| 20967 | + } |
| 20968 | +} |
| 20969 | + |
| 20970 | +static int yaffs_free_verification_failures; |
| 20971 | + |
| 20972 | +void yaffs_verify_free_chunks(yaffs_dev_t *dev) |
| 20973 | +{ |
| 20974 | + int counted; |
| 20975 | + int difference; |
| 20976 | + |
| 20977 | + if (yaffs_skip_verification(dev)) |
| 20978 | + return; |
| 20979 | + |
| 20980 | + counted = yaffs_count_free_chunks(dev); |
| 20981 | + |
| 20982 | + difference = dev->n_free_chunks - counted; |
| 20983 | + |
| 20984 | + if (difference) { |
| 20985 | + T(YAFFS_TRACE_ALWAYS, |
| 20986 | + (TSTR("Freechunks verification failure %d %d %d" TENDSTR), |
| 20987 | + dev->n_free_chunks, counted, difference)); |
| 20988 | + yaffs_free_verification_failures++; |
| 20989 | + } |
| 20990 | +} |
| 20991 | + |
| 20992 | +int yaffs_verify_file_sane(yaffs_obj_t *in) |
| 20993 | +{ |
| 20994 | +#if 0 |
| 20995 | + int chunk; |
| 20996 | + int n_chunks; |
| 20997 | + int fSize; |
| 20998 | + int failed = 0; |
| 20999 | + int obj_id; |
| 21000 | + yaffs_tnode_t *tn; |
| 21001 | + yaffs_tags_t localTags; |
| 21002 | + yaffs_tags_t *tags = &localTags; |
| 21003 | + int theChunk; |
| 21004 | + int is_deleted; |
| 21005 | + |
| 21006 | + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) |
| 21007 | + return YAFFS_FAIL; |
| 21008 | + |
| 21009 | + obj_id = in->obj_id; |
| 21010 | + fSize = in->variant.file_variant.file_size; |
| 21011 | + n_chunks = |
| 21012 | + (fSize + in->my_dev->data_bytes_per_chunk - 1) / in->my_dev->data_bytes_per_chunk; |
| 21013 | + |
| 21014 | + for (chunk = 1; chunk <= n_chunks; chunk++) { |
| 21015 | + tn = yaffs_find_tnode_0(in->my_dev, &in->variant.file_variant, |
| 21016 | + chunk); |
| 21017 | + |
| 21018 | + if (tn) { |
| 21019 | + |
| 21020 | + theChunk = yaffs_get_group_base(dev, tn, chunk); |
| 21021 | + |
| 21022 | + if (yaffs_check_chunk_bits |
| 21023 | + (dev, theChunk / dev->param.chunks_per_block, |
| 21024 | + theChunk % dev->param.chunks_per_block)) { |
| 21025 | + |
| 21026 | + yaffs_rd_chunk_tags_nand(in->my_dev, theChunk, |
| 21027 | + tags, |
| 21028 | + &is_deleted); |
| 21029 | + if (yaffs_tags_match |
| 21030 | + (tags, in->obj_id, chunk, is_deleted)) { |
| 21031 | + /* found it; */ |
| 21032 | + |
| 21033 | + } |
| 21034 | + } else { |
| 21035 | + |
| 21036 | + failed = 1; |
| 21037 | + } |
| 21038 | + |
| 21039 | + } else { |
| 21040 | + /* T(("No level 0 found for %d\n", chunk)); */ |
| 21041 | + } |
| 21042 | + } |
| 21043 | + |
| 21044 | + return failed ? YAFFS_FAIL : YAFFS_OK; |
| 21045 | +#else |
| 21046 | + in=in; |
| 21047 | + return YAFFS_OK; |
| 21048 | +#endif |
| 21049 | +} |
| 21050 | --- /dev/null |
| 21051 | +++ b/fs/yaffs2/yaffs_verify.h |
| 21052 | @@ -0,0 +1,39 @@ |
| 21053 | +/* |
| 21054 | + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 21055 | + * |
| 21056 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 21057 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 21058 | + * |
| 21059 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 21060 | + * |
| 21061 | + * This program is free software; you can redistribute it and/or modify |
| 21062 | + * it under the terms of the GNU General Public License version 2 as |
| 21063 | + * published by the Free Software Foundation. |
| 21064 | + */ |
| 21065 | + |
| 21066 | +#ifndef __YAFFS_VERIFY_H__ |
| 21067 | +#define __YAFFS_VERIFY_H__ |
| 21068 | + |
| 21069 | +#include "yaffs_guts.h" |
| 21070 | + |
| 21071 | +void yaffs_verify_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n); |
| 21072 | +void yaffs_verify_collected_blk(yaffs_dev_t *dev, yaffs_block_info_t *bi, int n); |
| 21073 | +void yaffs_verify_blocks(yaffs_dev_t *dev); |
| 21074 | + |
| 21075 | +void yaffs_verify_oh(yaffs_obj_t *obj, yaffs_obj_header *oh, yaffs_ext_tags *tags, int parentCheck); |
| 21076 | +void yaffs_verify_file(yaffs_obj_t *obj); |
| 21077 | +void yaffs_verify_link(yaffs_obj_t *obj); |
| 21078 | +void yaffs_verify_symlink(yaffs_obj_t *obj); |
| 21079 | +void yaffs_verify_special(yaffs_obj_t *obj); |
| 21080 | +void yaffs_verify_obj(yaffs_obj_t *obj); |
| 21081 | +void yaffs_verify_objects(yaffs_dev_t *dev); |
| 21082 | +void yaffs_verify_obj_in_dir(yaffs_obj_t *obj); |
| 21083 | +void yaffs_verify_dir(yaffs_obj_t *directory); |
| 21084 | +void yaffs_verify_free_chunks(yaffs_dev_t *dev); |
| 21085 | + |
| 21086 | +int yaffs_verify_file_sane(yaffs_obj_t *obj); |
| 21087 | + |
| 21088 | +int yaffs_skip_verification(yaffs_dev_t *dev); |
| 21089 | + |
| 21090 | +#endif |
| 21091 | + |
| 21092 | --- /dev/null |
| 21093 | +++ b/fs/yaffs2/yaffs_vfs_glue.c |
| 21094 | @@ -0,0 +1,3576 @@ |
| 21095 | +/* |
| 21096 | + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 21097 | + * |
| 21098 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 21099 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 21100 | + * |
| 21101 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 21102 | + * Acknowledgements: |
| 21103 | + * Luc van OostenRyck for numerous patches. |
| 21104 | + * Nick Bane for numerous patches. |
| 21105 | + * Nick Bane for 2.5/2.6 integration. |
| 21106 | + * Andras Toth for mknod rdev issue. |
| 21107 | + * Michael Fischer for finding the problem with inode inconsistency. |
| 21108 | + * Some code bodily lifted from JFFS |
| 21109 | + * |
| 21110 | + * This program is free software; you can redistribute it and/or modify |
| 21111 | + * it under the terms of the GNU General Public License version 2 as |
| 21112 | + * published by the Free Software Foundation. |
| 21113 | + */ |
| 21114 | + |
| 21115 | +/* |
| 21116 | + * |
| 21117 | + * This is the file system front-end to YAFFS that hooks it up to |
| 21118 | + * the VFS. |
| 21119 | + * |
| 21120 | + * Special notes: |
| 21121 | + * >> 2.4: sb->u.generic_sbp points to the yaffs_dev_t associated with |
| 21122 | + * this superblock |
| 21123 | + * >> 2.6: sb->s_fs_info points to the yaffs_dev_t associated with this |
| 21124 | + * superblock |
| 21125 | + * >> inode->u.generic_ip points to the associated yaffs_obj_t. |
| 21126 | + */ |
| 21127 | + |
| 21128 | +/* |
| 21129 | + * There are two variants of the VFS glue code. This variant should compile |
| 21130 | + * for any version of Linux. |
| 21131 | + */ |
| 21132 | +#include <linux/version.h> |
| 21133 | + |
| 21134 | +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)) |
| 21135 | +#define YAFFS_COMPILE_BACKGROUND |
| 21136 | +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6, 23)) |
| 21137 | +#define YAFFS_COMPILE_FREEZER |
| 21138 | +#endif |
| 21139 | +#endif |
| 21140 | + |
| 21141 | +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) |
| 21142 | +#define YAFFS_COMPILE_EXPORTFS |
| 21143 | +#endif |
| 21144 | + |
| 21145 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)) |
| 21146 | +#define YAFFS_USE_SETATTR_COPY |
| 21147 | +#define YAFFS_USE_TRUNCATE_SETSIZE |
| 21148 | +#endif |
| 21149 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)) |
| 21150 | +#define YAFFS_HAS_EVICT_INODE |
| 21151 | +#endif |
| 21152 | + |
| 21153 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)) |
| 21154 | +#define YAFFS_NEW_FOLLOW_LINK 1 |
| 21155 | +#else |
| 21156 | +#define YAFFS_NEW_FOLLOW_LINK 0 |
| 21157 | +#endif |
| 21158 | + |
| 21159 | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) |
| 21160 | +#include <linux/config.h> |
| 21161 | +#endif |
| 21162 | + |
| 21163 | +#include <linux/kernel.h> |
| 21164 | +#include <linux/module.h> |
| 21165 | +#include <linux/slab.h> |
| 21166 | +#include <linux/init.h> |
| 21167 | +#include <linux/fs.h> |
| 21168 | +#include <linux/proc_fs.h> |
| 21169 | +#include <linux/smp_lock.h> |
| 21170 | +#include <linux/pagemap.h> |
| 21171 | +#include <linux/mtd/mtd.h> |
| 21172 | +#include <linux/interrupt.h> |
| 21173 | +#include <linux/string.h> |
| 21174 | +#include <linux/ctype.h> |
| 21175 | + |
| 21176 | +#if (YAFFS_NEW_FOLLOW_LINK == 1) |
| 21177 | +#include <linux/namei.h> |
| 21178 | +#endif |
| 21179 | + |
| 21180 | +#ifdef YAFFS_COMPILE_EXPORTFS |
| 21181 | +#include <linux/exportfs.h> |
| 21182 | +#endif |
| 21183 | + |
| 21184 | +#ifdef YAFFS_COMPILE_BACKGROUND |
| 21185 | +#include <linux/kthread.h> |
| 21186 | +#include <linux/delay.h> |
| 21187 | +#endif |
| 21188 | +#ifdef YAFFS_COMPILE_FREEZER |
| 21189 | +#include <linux/freezer.h> |
| 21190 | +#endif |
| 21191 | + |
| 21192 | +#include <asm/div64.h> |
| 21193 | + |
| 21194 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 21195 | + |
| 21196 | +#include <linux/statfs.h> |
| 21197 | + |
| 21198 | +#define UnlockPage(p) unlock_page(p) |
| 21199 | +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) |
| 21200 | + |
| 21201 | +/* FIXME: use sb->s_id instead ? */ |
| 21202 | +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf) |
| 21203 | + |
| 21204 | +#else |
| 21205 | + |
| 21206 | +#include <linux/locks.h> |
| 21207 | +#define BDEVNAME_SIZE 0 |
| 21208 | +#define yaffs_devname(sb, buf) kdevname(sb->s_dev) |
| 21209 | + |
| 21210 | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)) |
| 21211 | +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ |
| 21212 | +#define __user |
| 21213 | +#endif |
| 21214 | + |
| 21215 | +#endif |
| 21216 | + |
| 21217 | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) |
| 21218 | +#define YPROC_ROOT (&proc_root) |
| 21219 | +#else |
| 21220 | +#define YPROC_ROOT NULL |
| 21221 | +#endif |
| 21222 | + |
| 21223 | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) |
| 21224 | +#define Y_INIT_TIMER(a) init_timer(a) |
| 21225 | +#else |
| 21226 | +#define Y_INIT_TIMER(a) init_timer_on_stack(a) |
| 21227 | +#endif |
| 21228 | + |
| 21229 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 21230 | +#define WRITE_SIZE_STR "writesize" |
| 21231 | +#define WRITE_SIZE(mtd) ((mtd)->writesize) |
| 21232 | +#else |
| 21233 | +#define WRITE_SIZE_STR "oobblock" |
| 21234 | +#define WRITE_SIZE(mtd) ((mtd)->oobblock) |
| 21235 | +#endif |
| 21236 | + |
| 21237 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)) |
| 21238 | +#define YAFFS_USE_WRITE_BEGIN_END 1 |
| 21239 | +#else |
| 21240 | +#define YAFFS_USE_WRITE_BEGIN_END 0 |
| 21241 | +#endif |
| 21242 | + |
| 21243 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)) |
| 21244 | +static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) |
| 21245 | +{ |
| 21246 | + uint64_t result = partition_size; |
| 21247 | + do_div(result, block_size); |
| 21248 | + return (uint32_t)result; |
| 21249 | +} |
| 21250 | +#else |
| 21251 | +#define YCALCBLOCKS(s, b) ((s)/(b)) |
| 21252 | +#endif |
| 21253 | + |
| 21254 | +#include <linux/uaccess.h> |
| 21255 | +#include <linux/mtd/mtd.h> |
| 21256 | + |
| 21257 | +#include "yportenv.h" |
| 21258 | +#include "yaffs_trace.h" |
| 21259 | +#include "yaffs_guts.h" |
| 21260 | + |
| 21261 | +#include "yaffs_linux.h" |
| 21262 | + |
| 21263 | +#include "yaffs_mtdif.h" |
| 21264 | +#include "yaffs_mtdif1.h" |
| 21265 | +#include "yaffs_mtdif2.h" |
| 21266 | + |
| 21267 | +unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS; |
| 21268 | +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; |
| 21269 | +unsigned int yaffs_auto_checkpoint = 1; |
| 21270 | +unsigned int yaffs_gc_control = 1; |
| 21271 | +unsigned int yaffs_bg_enable = 1; |
| 21272 | + |
| 21273 | +/* Module Parameters */ |
| 21274 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 21275 | +module_param(yaffs_trace_mask, uint, 0644); |
| 21276 | +module_param(yaffs_wr_attempts, uint, 0644); |
| 21277 | +module_param(yaffs_auto_checkpoint, uint, 0644); |
| 21278 | +module_param(yaffs_gc_control, uint, 0644); |
| 21279 | +module_param(yaffs_bg_enable, uint, 0644); |
| 21280 | +#else |
| 21281 | +MODULE_PARM(yaffs_trace_mask, "i"); |
| 21282 | +MODULE_PARM(yaffs_wr_attempts, "i"); |
| 21283 | +MODULE_PARM(yaffs_auto_checkpoint, "i"); |
| 21284 | +MODULE_PARM(yaffs_gc_control, "i"); |
| 21285 | +#endif |
| 21286 | + |
| 21287 | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) |
| 21288 | +/* use iget and read_inode */ |
| 21289 | +#define Y_IGET(sb, inum) iget((sb), (inum)) |
| 21290 | +static void yaffs_read_inode(struct inode *inode); |
| 21291 | + |
| 21292 | +#else |
| 21293 | +/* Call local equivalent */ |
| 21294 | +#define YAFFS_USE_OWN_IGET |
| 21295 | +#define Y_IGET(sb, inum) yaffs_iget((sb), (inum)) |
| 21296 | + |
| 21297 | +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino); |
| 21298 | +#endif |
| 21299 | + |
| 21300 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) |
| 21301 | +#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private) |
| 21302 | +#else |
| 21303 | +#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip) |
| 21304 | +#endif |
| 21305 | + |
| 21306 | +#define yaffs_InodeToObject(iptr) ((yaffs_obj_t *)(yaffs_InodeToObjectLV(iptr))) |
| 21307 | +#define yaffs_dentry_to_obj(dptr) yaffs_InodeToObject((dptr)->d_inode) |
| 21308 | + |
| 21309 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 21310 | +#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->s_fs_info) |
| 21311 | +#else |
| 21312 | +#define yaffs_SuperToDevice(sb) ((yaffs_dev_t *)sb->u.generic_sbp) |
| 21313 | +#endif |
| 21314 | + |
| 21315 | + |
| 21316 | +#define update_dir_time(dir) do {\ |
| 21317 | + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \ |
| 21318 | + } while(0) |
| 21319 | + |
| 21320 | +static void yaffs_put_super(struct super_block *sb); |
| 21321 | + |
| 21322 | +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, |
| 21323 | + loff_t *pos); |
| 21324 | +static ssize_t yaffs_hold_space(struct file *f); |
| 21325 | +static void yaffs_release_space(struct file *f); |
| 21326 | + |
| 21327 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 21328 | +static int yaffs_file_flush(struct file *file, fl_owner_t id); |
| 21329 | +#else |
| 21330 | +static int yaffs_file_flush(struct file *file); |
| 21331 | +#endif |
| 21332 | + |
| 21333 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) |
| 21334 | +static int yaffs_sync_object(struct file *file, int datasync); |
| 21335 | +#else |
| 21336 | +static int yaffs_sync_object(struct file *file, struct dentry *dentry, |
| 21337 | + int datasync); |
| 21338 | +#endif |
| 21339 | + |
| 21340 | +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir); |
| 21341 | + |
| 21342 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 21343 | +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, |
| 21344 | + struct nameidata *n); |
| 21345 | +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, |
| 21346 | + struct nameidata *n); |
| 21347 | +#else |
| 21348 | +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode); |
| 21349 | +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry); |
| 21350 | +#endif |
| 21351 | +static int yaffs_link(struct dentry *old_dentry, struct inode *dir, |
| 21352 | + struct dentry *dentry); |
| 21353 | +static int yaffs_unlink(struct inode *dir, struct dentry *dentry); |
| 21354 | +static int yaffs_symlink(struct inode *dir, struct dentry *dentry, |
| 21355 | + const char *symname); |
| 21356 | +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode); |
| 21357 | + |
| 21358 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 21359 | +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, |
| 21360 | + dev_t dev); |
| 21361 | +#else |
| 21362 | +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, |
| 21363 | + int dev); |
| 21364 | +#endif |
| 21365 | +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, |
| 21366 | + struct inode *new_dir, struct dentry *new_dentry); |
| 21367 | +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr); |
| 21368 | + |
| 21369 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 21370 | +static int yaffs_sync_fs(struct super_block *sb, int wait); |
| 21371 | +static void yaffs_write_super(struct super_block *sb); |
| 21372 | +#else |
| 21373 | +static int yaffs_sync_fs(struct super_block *sb); |
| 21374 | +static int yaffs_write_super(struct super_block *sb); |
| 21375 | +#endif |
| 21376 | + |
| 21377 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 21378 | +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf); |
| 21379 | +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 21380 | +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf); |
| 21381 | +#else |
| 21382 | +static int yaffs_statfs(struct super_block *sb, struct statfs *buf); |
| 21383 | +#endif |
| 21384 | + |
| 21385 | +#ifdef YAFFS_HAS_PUT_INODE |
| 21386 | +static void yaffs_put_inode(struct inode *inode); |
| 21387 | +#endif |
| 21388 | + |
| 21389 | +#ifdef YAFFS_HAS_EVICT_INODE |
| 21390 | +static void yaffs_evict_inode(struct inode *); |
| 21391 | +#else |
| 21392 | +static void yaffs_delete_inode(struct inode *); |
| 21393 | +static void yaffs_clear_inode(struct inode *); |
| 21394 | +#endif |
| 21395 | + |
| 21396 | +static int yaffs_readpage(struct file *file, struct page *page); |
| 21397 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 21398 | +static int yaffs_writepage(struct page *page, struct writeback_control *wbc); |
| 21399 | +#else |
| 21400 | +static int yaffs_writepage(struct page *page); |
| 21401 | +#endif |
| 21402 | + |
| 21403 | +#ifdef CONFIG_YAFFS_XATTR |
| 21404 | +int yaffs_setxattr(struct dentry *dentry, const char *name, |
| 21405 | + const void *value, size_t size, int flags); |
| 21406 | +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff, |
| 21407 | + size_t size); |
| 21408 | +int yaffs_removexattr(struct dentry *dentry, const char *name); |
| 21409 | +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size); |
| 21410 | +#endif |
| 21411 | + |
| 21412 | + |
| 21413 | +#if (YAFFS_USE_WRITE_BEGIN_END != 0) |
| 21414 | +static int yaffs_write_begin(struct file *filp, struct address_space *mapping, |
| 21415 | + loff_t pos, unsigned len, unsigned flags, |
| 21416 | + struct page **pagep, void **fsdata); |
| 21417 | +static int yaffs_write_end(struct file *filp, struct address_space *mapping, |
| 21418 | + loff_t pos, unsigned len, unsigned copied, |
| 21419 | + struct page *pg, void *fsdadata); |
| 21420 | +#else |
| 21421 | +static int yaffs_prepare_write(struct file *f, struct page *pg, |
| 21422 | + unsigned offset, unsigned to); |
| 21423 | +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, |
| 21424 | + unsigned to); |
| 21425 | + |
| 21426 | +#endif |
| 21427 | + |
| 21428 | +static int yaffs_readlink(struct dentry *dentry, char __user *buffer, |
| 21429 | + int buflen); |
| 21430 | +#if (YAFFS_NEW_FOLLOW_LINK == 1) |
| 21431 | +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias); |
| 21432 | +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); |
| 21433 | +#else |
| 21434 | +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd); |
| 21435 | +#endif |
| 21436 | + |
| 21437 | +static void yaffs_touch_super(yaffs_dev_t *dev); |
| 21438 | + |
| 21439 | +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin); |
| 21440 | + |
| 21441 | +static int yaffs_vfs_setattr(struct inode *, struct iattr *); |
| 21442 | + |
| 21443 | + |
| 21444 | +static struct address_space_operations yaffs_file_address_operations = { |
| 21445 | + .readpage = yaffs_readpage, |
| 21446 | + .writepage = yaffs_writepage, |
| 21447 | +#if (YAFFS_USE_WRITE_BEGIN_END > 0) |
| 21448 | + .write_begin = yaffs_write_begin, |
| 21449 | + .write_end = yaffs_write_end, |
| 21450 | +#else |
| 21451 | + .prepare_write = yaffs_prepare_write, |
| 21452 | + .commit_write = yaffs_commit_write, |
| 21453 | +#endif |
| 21454 | +}; |
| 21455 | + |
| 21456 | + |
| 21457 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) |
| 21458 | +static const struct file_operations yaffs_file_operations = { |
| 21459 | + .read = do_sync_read, |
| 21460 | + .write = do_sync_write, |
| 21461 | + .aio_read = generic_file_aio_read, |
| 21462 | + .aio_write = generic_file_aio_write, |
| 21463 | + .mmap = generic_file_mmap, |
| 21464 | + .flush = yaffs_file_flush, |
| 21465 | + .fsync = yaffs_sync_object, |
| 21466 | + .splice_read = generic_file_splice_read, |
| 21467 | + .splice_write = generic_file_splice_write, |
| 21468 | + .llseek = generic_file_llseek, |
| 21469 | +}; |
| 21470 | + |
| 21471 | +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)) |
| 21472 | + |
| 21473 | +static const struct file_operations yaffs_file_operations = { |
| 21474 | + .read = do_sync_read, |
| 21475 | + .write = do_sync_write, |
| 21476 | + .aio_read = generic_file_aio_read, |
| 21477 | + .aio_write = generic_file_aio_write, |
| 21478 | + .mmap = generic_file_mmap, |
| 21479 | + .flush = yaffs_file_flush, |
| 21480 | + .fsync = yaffs_sync_object, |
| 21481 | + .sendfile = generic_file_sendfile, |
| 21482 | +}; |
| 21483 | + |
| 21484 | +#else |
| 21485 | + |
| 21486 | +static const struct file_operations yaffs_file_operations = { |
| 21487 | + .read = generic_file_read, |
| 21488 | + .write = generic_file_write, |
| 21489 | + .mmap = generic_file_mmap, |
| 21490 | + .flush = yaffs_file_flush, |
| 21491 | + .fsync = yaffs_sync_object, |
| 21492 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 21493 | + .sendfile = generic_file_sendfile, |
| 21494 | +#endif |
| 21495 | +}; |
| 21496 | +#endif |
| 21497 | + |
| 21498 | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)) |
| 21499 | +static void zero_user_segment(struct page *page, unsigned start, unsigned end) |
| 21500 | +{ |
| 21501 | + void * kaddr = kmap_atomic(page, KM_USER0); |
| 21502 | + memset(kaddr + start, 0, end - start); |
| 21503 | + kunmap_atomic(kaddr, KM_USER0); |
| 21504 | + flush_dcache_page(page); |
| 21505 | +} |
| 21506 | +#endif |
| 21507 | + |
| 21508 | + |
| 21509 | +static const struct inode_operations yaffs_file_inode_operations = { |
| 21510 | + .setattr = yaffs_setattr, |
| 21511 | +#ifdef CONFIG_YAFFS_XATTR |
| 21512 | + .setxattr = yaffs_setxattr, |
| 21513 | + .getxattr = yaffs_getxattr, |
| 21514 | + .listxattr = yaffs_listxattr, |
| 21515 | + .removexattr = yaffs_removexattr, |
| 21516 | +#endif |
| 21517 | +}; |
| 21518 | + |
| 21519 | +static const struct inode_operations yaffs_symlink_inode_operations = { |
| 21520 | + .readlink = yaffs_readlink, |
| 21521 | + .follow_link = yaffs_follow_link, |
| 21522 | +#if (YAFFS_NEW_FOLLOW_LINK == 1) |
| 21523 | + .put_link = yaffs_put_link, |
| 21524 | +#endif |
| 21525 | + .setattr = yaffs_setattr, |
| 21526 | +#ifdef CONFIG_YAFFS_XATTR |
| 21527 | + .setxattr = yaffs_setxattr, |
| 21528 | + .getxattr = yaffs_getxattr, |
| 21529 | + .listxattr = yaffs_listxattr, |
| 21530 | + .removexattr = yaffs_removexattr, |
| 21531 | +#endif |
| 21532 | +}; |
| 21533 | + |
| 21534 | +static const struct inode_operations yaffs_dir_inode_operations = { |
| 21535 | + .create = yaffs_create, |
| 21536 | + .lookup = yaffs_lookup, |
| 21537 | + .link = yaffs_link, |
| 21538 | + .unlink = yaffs_unlink, |
| 21539 | + .symlink = yaffs_symlink, |
| 21540 | + .mkdir = yaffs_mkdir, |
| 21541 | + .rmdir = yaffs_unlink, |
| 21542 | + .mknod = yaffs_mknod, |
| 21543 | + .rename = yaffs_rename, |
| 21544 | + .setattr = yaffs_setattr, |
| 21545 | +#ifdef CONFIG_YAFFS_XATTR |
| 21546 | + .setxattr = yaffs_setxattr, |
| 21547 | + .getxattr = yaffs_getxattr, |
| 21548 | + .listxattr = yaffs_listxattr, |
| 21549 | + .removexattr = yaffs_removexattr, |
| 21550 | +#endif |
| 21551 | +}; |
| 21552 | + |
| 21553 | +static const struct file_operations yaffs_dir_operations = { |
| 21554 | + .read = generic_read_dir, |
| 21555 | + .readdir = yaffs_readdir, |
| 21556 | + .fsync = yaffs_sync_object, |
| 21557 | + .llseek = yaffs_dir_llseek, |
| 21558 | +}; |
| 21559 | + |
| 21560 | +static const struct super_operations yaffs_super_ops = { |
| 21561 | + .statfs = yaffs_statfs, |
| 21562 | + |
| 21563 | +#ifndef YAFFS_USE_OWN_IGET |
| 21564 | + .read_inode = yaffs_read_inode, |
| 21565 | +#endif |
| 21566 | +#ifdef YAFFS_HAS_PUT_INODE |
| 21567 | + .put_inode = yaffs_put_inode, |
| 21568 | +#endif |
| 21569 | + .put_super = yaffs_put_super, |
| 21570 | +#ifdef YAFFS_HAS_EVICT_INODE |
| 21571 | + .evict_inode = yaffs_evict_inode, |
| 21572 | +#else |
| 21573 | + .delete_inode = yaffs_delete_inode, |
| 21574 | + .clear_inode = yaffs_clear_inode, |
| 21575 | +#endif |
| 21576 | + .sync_fs = yaffs_sync_fs, |
| 21577 | + .write_super = yaffs_write_super, |
| 21578 | +}; |
| 21579 | + |
| 21580 | + |
| 21581 | +static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr) |
| 21582 | +{ |
| 21583 | +#ifdef YAFFS_USE_SETATTR_COPY |
| 21584 | + setattr_copy(inode,attr); |
| 21585 | + return 0; |
| 21586 | +#else |
| 21587 | + return inode_setattr(inode, attr); |
| 21588 | +#endif |
| 21589 | + |
| 21590 | +} |
| 21591 | + |
| 21592 | +static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize) |
| 21593 | +{ |
| 21594 | +#ifdef YAFFS_USE_TRUNCATE_SETSIZE |
| 21595 | + truncate_setsize(inode,newsize); |
| 21596 | + return 0; |
| 21597 | +#else |
| 21598 | + truncate_inode_pages(&inode->i_data,newsize); |
| 21599 | + return 0; |
| 21600 | +#endif |
| 21601 | + |
| 21602 | +} |
| 21603 | + |
| 21604 | +static unsigned yaffs_gc_control_callback(yaffs_dev_t *dev) |
| 21605 | +{ |
| 21606 | + return yaffs_gc_control; |
| 21607 | +} |
| 21608 | + |
| 21609 | +static void yaffs_gross_lock(yaffs_dev_t *dev) |
| 21610 | +{ |
| 21611 | + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current)); |
| 21612 | + down(&(yaffs_dev_to_lc(dev)->grossLock)); |
| 21613 | + T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current)); |
| 21614 | +} |
| 21615 | + |
| 21616 | +static void yaffs_gross_unlock(yaffs_dev_t *dev) |
| 21617 | +{ |
| 21618 | + T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current)); |
| 21619 | + up(&(yaffs_dev_to_lc(dev)->grossLock)); |
| 21620 | +} |
| 21621 | + |
| 21622 | +#ifdef YAFFS_COMPILE_EXPORTFS |
| 21623 | + |
| 21624 | +static struct inode * |
| 21625 | +yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation) |
| 21626 | +{ |
| 21627 | + return Y_IGET(sb, ino); |
| 21628 | +} |
| 21629 | + |
| 21630 | +static struct dentry * |
| 21631 | +yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) |
| 21632 | +{ |
| 21633 | + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ; |
| 21634 | +} |
| 21635 | + |
| 21636 | +static struct dentry * |
| 21637 | + yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) |
| 21638 | +{ |
| 21639 | + return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode); |
| 21640 | +} |
| 21641 | + |
| 21642 | +struct dentry *yaffs2_get_parent(struct dentry *dentry) |
| 21643 | +{ |
| 21644 | + |
| 21645 | + struct super_block *sb = dentry->d_inode->i_sb; |
| 21646 | + struct dentry *parent = ERR_PTR(-ENOENT); |
| 21647 | + struct inode *inode; |
| 21648 | + unsigned long parent_ino; |
| 21649 | + yaffs_obj_t *d_obj; |
| 21650 | + yaffs_obj_t *parent_obj; |
| 21651 | + |
| 21652 | + d_obj = yaffs_InodeToObject(dentry->d_inode); |
| 21653 | + |
| 21654 | + if (d_obj) { |
| 21655 | + parent_obj = d_obj->parent; |
| 21656 | + if (parent_obj) { |
| 21657 | + parent_ino = yaffs_get_obj_inode(parent_obj); |
| 21658 | + inode = Y_IGET(sb, parent_ino); |
| 21659 | + |
| 21660 | + if (IS_ERR(inode)) { |
| 21661 | + parent = ERR_CAST(inode); |
| 21662 | + } else { |
| 21663 | + parent = d_obtain_alias(inode); |
| 21664 | + if (!IS_ERR(parent)) { |
| 21665 | + parent = ERR_PTR(-ENOMEM); |
| 21666 | + iput(inode); |
| 21667 | + } |
| 21668 | + } |
| 21669 | + } |
| 21670 | + } |
| 21671 | + |
| 21672 | + return parent; |
| 21673 | +} |
| 21674 | + |
| 21675 | +/* Just declare a zero structure as a NULL value implies |
| 21676 | + * using the default functions of exportfs. |
| 21677 | + */ |
| 21678 | + |
| 21679 | +static struct export_operations yaffs_export_ops = |
| 21680 | +{ |
| 21681 | + .fh_to_dentry = yaffs2_fh_to_dentry, |
| 21682 | + .fh_to_parent = yaffs2_fh_to_parent, |
| 21683 | + .get_parent = yaffs2_get_parent, |
| 21684 | +} ; |
| 21685 | + |
| 21686 | +#endif |
| 21687 | + |
| 21688 | +/*-----------------------------------------------------------------*/ |
| 21689 | +/* Directory search context allows us to unlock access to yaffs during |
| 21690 | + * filldir without causing problems with the directory being modified. |
| 21691 | + * This is similar to the tried and tested mechanism used in yaffs direct. |
| 21692 | + * |
| 21693 | + * A search context iterates along a doubly linked list of siblings in the |
| 21694 | + * directory. If the iterating object is deleted then this would corrupt |
| 21695 | + * the list iteration, likely causing a crash. The search context avoids |
| 21696 | + * this by using the remove_obj_fn to move the search context to the |
| 21697 | + * next object before the object is deleted. |
| 21698 | + * |
| 21699 | + * Many readdirs (and thus seach conexts) may be alive simulateously so |
| 21700 | + * each yaffs_dev_t has a list of these. |
| 21701 | + * |
| 21702 | + * A seach context lives for the duration of a readdir. |
| 21703 | + * |
| 21704 | + * All these functions must be called while yaffs is locked. |
| 21705 | + */ |
| 21706 | + |
| 21707 | +struct yaffs_SearchContext { |
| 21708 | + yaffs_dev_t *dev; |
| 21709 | + yaffs_obj_t *dirObj; |
| 21710 | + yaffs_obj_t *nextReturn; |
| 21711 | + struct ylist_head others; |
| 21712 | +}; |
| 21713 | + |
| 21714 | +/* |
| 21715 | + * yaffs_NewSearch() creates a new search context, initialises it and |
| 21716 | + * adds it to the device's search context list. |
| 21717 | + * |
| 21718 | + * Called at start of readdir. |
| 21719 | + */ |
| 21720 | +static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_obj_t *dir) |
| 21721 | +{ |
| 21722 | + yaffs_dev_t *dev = dir->my_dev; |
| 21723 | + struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext)); |
| 21724 | + if(sc){ |
| 21725 | + sc->dirObj = dir; |
| 21726 | + sc->dev = dev; |
| 21727 | + if( ylist_empty(&sc->dirObj->variant.dir_variant.children)) |
| 21728 | + sc->nextReturn = NULL; |
| 21729 | + else |
| 21730 | + sc->nextReturn = ylist_entry( |
| 21731 | + dir->variant.dir_variant.children.next, |
| 21732 | + yaffs_obj_t,siblings); |
| 21733 | + YINIT_LIST_HEAD(&sc->others); |
| 21734 | + ylist_add(&sc->others,&(yaffs_dev_to_lc(dev)->searchContexts)); |
| 21735 | + } |
| 21736 | + return sc; |
| 21737 | +} |
| 21738 | + |
| 21739 | +/* |
| 21740 | + * yaffs_search_end() disposes of a search context and cleans up. |
| 21741 | + */ |
| 21742 | +static void yaffs_search_end(struct yaffs_SearchContext * sc) |
| 21743 | +{ |
| 21744 | + if(sc){ |
| 21745 | + ylist_del(&sc->others); |
| 21746 | + YFREE(sc); |
| 21747 | + } |
| 21748 | +} |
| 21749 | + |
| 21750 | +/* |
| 21751 | + * yaffs_search_advance() moves a search context to the next object. |
| 21752 | + * Called when the search iterates or when an object removal causes |
| 21753 | + * the search context to be moved to the next object. |
| 21754 | + */ |
| 21755 | +static void yaffs_search_advance(struct yaffs_SearchContext *sc) |
| 21756 | +{ |
| 21757 | + if(!sc) |
| 21758 | + return; |
| 21759 | + |
| 21760 | + if( sc->nextReturn == NULL || |
| 21761 | + ylist_empty(&sc->dirObj->variant.dir_variant.children)) |
| 21762 | + sc->nextReturn = NULL; |
| 21763 | + else { |
| 21764 | + struct ylist_head *next = sc->nextReturn->siblings.next; |
| 21765 | + |
| 21766 | + if( next == &sc->dirObj->variant.dir_variant.children) |
| 21767 | + sc->nextReturn = NULL; /* end of list */ |
| 21768 | + else |
| 21769 | + sc->nextReturn = ylist_entry(next,yaffs_obj_t,siblings); |
| 21770 | + } |
| 21771 | +} |
| 21772 | + |
| 21773 | +/* |
| 21774 | + * yaffs_remove_obj_callback() is called when an object is unlinked. |
| 21775 | + * We check open search contexts and advance any which are currently |
| 21776 | + * on the object being iterated. |
| 21777 | + */ |
| 21778 | +static void yaffs_remove_obj_callback(yaffs_obj_t *obj) |
| 21779 | +{ |
| 21780 | + |
| 21781 | + struct ylist_head *i; |
| 21782 | + struct yaffs_SearchContext *sc; |
| 21783 | + struct ylist_head *search_contexts = &(yaffs_dev_to_lc(obj->my_dev)->searchContexts); |
| 21784 | + |
| 21785 | + |
| 21786 | + /* Iterate through the directory search contexts. |
| 21787 | + * If any are currently on the object being removed, then advance |
| 21788 | + * the search context to the next object to prevent a hanging pointer. |
| 21789 | + */ |
| 21790 | + ylist_for_each(i, search_contexts) { |
| 21791 | + if (i) { |
| 21792 | + sc = ylist_entry(i, struct yaffs_SearchContext,others); |
| 21793 | + if(sc->nextReturn == obj) |
| 21794 | + yaffs_search_advance(sc); |
| 21795 | + } |
| 21796 | + } |
| 21797 | + |
| 21798 | +} |
| 21799 | + |
| 21800 | + |
| 21801 | +/*-----------------------------------------------------------------*/ |
| 21802 | + |
| 21803 | +static int yaffs_readlink(struct dentry *dentry, char __user *buffer, |
| 21804 | + int buflen) |
| 21805 | +{ |
| 21806 | + unsigned char *alias; |
| 21807 | + int ret; |
| 21808 | + |
| 21809 | + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev; |
| 21810 | + |
| 21811 | + yaffs_gross_lock(dev); |
| 21812 | + |
| 21813 | + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); |
| 21814 | + |
| 21815 | + yaffs_gross_unlock(dev); |
| 21816 | + |
| 21817 | + if (!alias) |
| 21818 | + return -ENOMEM; |
| 21819 | + |
| 21820 | + ret = vfs_readlink(dentry, buffer, buflen, alias); |
| 21821 | + kfree(alias); |
| 21822 | + return ret; |
| 21823 | +} |
| 21824 | + |
| 21825 | +#if (YAFFS_NEW_FOLLOW_LINK == 1) |
| 21826 | +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) |
| 21827 | +#else |
| 21828 | +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) |
| 21829 | +#endif |
| 21830 | +{ |
| 21831 | + unsigned char *alias; |
| 21832 | + int ret; |
| 21833 | + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev; |
| 21834 | + |
| 21835 | + yaffs_gross_lock(dev); |
| 21836 | + |
| 21837 | + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry)); |
| 21838 | + yaffs_gross_unlock(dev); |
| 21839 | + |
| 21840 | + if (!alias) { |
| 21841 | + ret = -ENOMEM; |
| 21842 | + goto out; |
| 21843 | + } |
| 21844 | + |
| 21845 | +#if (YAFFS_NEW_FOLLOW_LINK == 1) |
| 21846 | + nd_set_link(nd, alias); |
| 21847 | + ret = (int)alias; |
| 21848 | +out: |
| 21849 | + return ERR_PTR(ret); |
| 21850 | +#else |
| 21851 | + ret = vfs_follow_link(nd, alias); |
| 21852 | + kfree(alias); |
| 21853 | +out: |
| 21854 | + return ret; |
| 21855 | +#endif |
| 21856 | +} |
| 21857 | + |
| 21858 | +#if (YAFFS_NEW_FOLLOW_LINK == 1) |
| 21859 | +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) { |
| 21860 | + kfree(alias); |
| 21861 | +} |
| 21862 | +#endif |
| 21863 | + |
| 21864 | +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, |
| 21865 | + yaffs_obj_t *obj); |
| 21866 | + |
| 21867 | +/* |
| 21868 | + * Lookup is used to find objects in the fs |
| 21869 | + */ |
| 21870 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 21871 | + |
| 21872 | +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry, |
| 21873 | + struct nameidata *n) |
| 21874 | +#else |
| 21875 | +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) |
| 21876 | +#endif |
| 21877 | +{ |
| 21878 | + yaffs_obj_t *obj; |
| 21879 | + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */ |
| 21880 | + |
| 21881 | + yaffs_dev_t *dev = yaffs_InodeToObject(dir)->my_dev; |
| 21882 | + |
| 21883 | + if(current != yaffs_dev_to_lc(dev)->readdirProcess) |
| 21884 | + yaffs_gross_lock(dev); |
| 21885 | + |
| 21886 | + T(YAFFS_TRACE_OS, |
| 21887 | + (TSTR("yaffs_lookup for %d:%s\n"), |
| 21888 | + yaffs_InodeToObject(dir)->obj_id, dentry->d_name.name)); |
| 21889 | + |
| 21890 | + obj = yaffs_find_by_name(yaffs_InodeToObject(dir), |
| 21891 | + dentry->d_name.name); |
| 21892 | + |
| 21893 | + obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */ |
| 21894 | + |
| 21895 | + /* Can't hold gross lock when calling yaffs_get_inode() */ |
| 21896 | + if(current != yaffs_dev_to_lc(dev)->readdirProcess) |
| 21897 | + yaffs_gross_unlock(dev); |
| 21898 | + |
| 21899 | + if (obj) { |
| 21900 | + T(YAFFS_TRACE_OS, |
| 21901 | + (TSTR("yaffs_lookup found %d\n"), obj->obj_id)); |
| 21902 | + |
| 21903 | + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); |
| 21904 | + |
| 21905 | + if (inode) { |
| 21906 | + T(YAFFS_TRACE_OS, |
| 21907 | + (TSTR("yaffs_loookup dentry \n"))); |
| 21908 | +/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to |
| 21909 | + * d_add even if NULL inode */ |
| 21910 | +#if 0 |
| 21911 | + /*dget(dentry); // try to solve directory bug */ |
| 21912 | + d_add(dentry, inode); |
| 21913 | + |
| 21914 | + /* return dentry; */ |
| 21915 | + return NULL; |
| 21916 | +#endif |
| 21917 | + } |
| 21918 | + |
| 21919 | + } else { |
| 21920 | + T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n"))); |
| 21921 | + |
| 21922 | + } |
| 21923 | + |
| 21924 | +/* added NCB for 2.5/6 compatability - forces add even if inode is |
| 21925 | + * NULL which creates dentry hash */ |
| 21926 | + d_add(dentry, inode); |
| 21927 | + |
| 21928 | + return NULL; |
| 21929 | +} |
| 21930 | + |
| 21931 | + |
| 21932 | +#ifdef YAFFS_HAS_PUT_INODE |
| 21933 | + |
| 21934 | +/* For now put inode is just for debugging |
| 21935 | + * Put inode is called when the inode **structure** is put. |
| 21936 | + */ |
| 21937 | +static void yaffs_put_inode(struct inode *inode) |
| 21938 | +{ |
| 21939 | + T(YAFFS_TRACE_OS, |
| 21940 | + (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino, |
| 21941 | + atomic_read(&inode->i_count))); |
| 21942 | + |
| 21943 | +} |
| 21944 | +#endif |
| 21945 | + |
| 21946 | + |
| 21947 | +static void yaffs_unstitch_obj(struct inode *inode, yaffs_obj_t *obj) |
| 21948 | +{ |
| 21949 | + /* Clear the association between the inode and |
| 21950 | + * the yaffs_obj_t. |
| 21951 | + */ |
| 21952 | + obj->my_inode = NULL; |
| 21953 | + yaffs_InodeToObjectLV(inode) = NULL; |
| 21954 | + |
| 21955 | + /* If the object freeing was deferred, then the real |
| 21956 | + * free happens now. |
| 21957 | + * This should fix the inode inconsistency problem. |
| 21958 | + */ |
| 21959 | + yaffs_handle_defered_free(obj); |
| 21960 | +} |
| 21961 | + |
| 21962 | +#ifdef YAFFS_HAS_EVICT_INODE |
| 21963 | +/* yaffs_evict_inode combines into one operation what was previously done in |
| 21964 | + * yaffs_clear_inode() and yaffs_delete_inode() |
| 21965 | + * |
| 21966 | + */ |
| 21967 | +static void yaffs_evict_inode( struct inode *inode) |
| 21968 | +{ |
| 21969 | + yaffs_obj_t *obj; |
| 21970 | + yaffs_dev_t *dev; |
| 21971 | + int deleteme = 0; |
| 21972 | + |
| 21973 | + obj = yaffs_InodeToObject(inode); |
| 21974 | + |
| 21975 | + T(YAFFS_TRACE_OS, |
| 21976 | + (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino, |
| 21977 | + atomic_read(&inode->i_count), |
| 21978 | + obj ? "object exists" : "null object")); |
| 21979 | + |
| 21980 | + if (!inode->i_nlink && !is_bad_inode(inode)) |
| 21981 | + deleteme = 1; |
| 21982 | + truncate_inode_pages(&inode->i_data,0); |
| 21983 | + end_writeback(inode); |
| 21984 | + |
| 21985 | + if(deleteme && obj){ |
| 21986 | + dev = obj->my_dev; |
| 21987 | + yaffs_gross_lock(dev); |
| 21988 | + yaffs_del_obj(obj); |
| 21989 | + yaffs_gross_unlock(dev); |
| 21990 | + } |
| 21991 | + if (obj) { |
| 21992 | + dev = obj->my_dev; |
| 21993 | + yaffs_gross_lock(dev); |
| 21994 | + yaffs_unstitch_obj(inode,obj); |
| 21995 | + yaffs_gross_unlock(dev); |
| 21996 | + } |
| 21997 | + |
| 21998 | + |
| 21999 | +} |
| 22000 | +#else |
| 22001 | + |
| 22002 | +/* clear is called to tell the fs to release any per-inode data it holds. |
| 22003 | + * The object might still exist on disk and is just being thrown out of the cache |
| 22004 | + * or else the object has actually been deleted and we're being called via |
| 22005 | + * the chain |
| 22006 | + * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode() |
| 22007 | + */ |
| 22008 | + |
| 22009 | +static void yaffs_clear_inode(struct inode *inode) |
| 22010 | +{ |
| 22011 | + yaffs_obj_t *obj; |
| 22012 | + yaffs_dev_t *dev; |
| 22013 | + |
| 22014 | + obj = yaffs_InodeToObject(inode); |
| 22015 | + |
| 22016 | + T(YAFFS_TRACE_OS, |
| 22017 | + (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino, |
| 22018 | + atomic_read(&inode->i_count), |
| 22019 | + obj ? "object exists" : "null object")); |
| 22020 | + |
| 22021 | + if (obj) { |
| 22022 | + dev = obj->my_dev; |
| 22023 | + yaffs_gross_lock(dev); |
| 22024 | + yaffs_unstitch_obj(inode,obj); |
| 22025 | + yaffs_gross_unlock(dev); |
| 22026 | + } |
| 22027 | + |
| 22028 | +} |
| 22029 | + |
| 22030 | +/* delete is called when the link count is zero and the inode |
| 22031 | + * is put (ie. nobody wants to know about it anymore, time to |
| 22032 | + * delete the file). |
| 22033 | + * NB Must call clear_inode() |
| 22034 | + */ |
| 22035 | +static void yaffs_delete_inode(struct inode *inode) |
| 22036 | +{ |
| 22037 | + yaffs_obj_t *obj = yaffs_InodeToObject(inode); |
| 22038 | + yaffs_dev_t *dev; |
| 22039 | + |
| 22040 | + T(YAFFS_TRACE_OS, |
| 22041 | + (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino, |
| 22042 | + atomic_read(&inode->i_count), |
| 22043 | + obj ? "object exists" : "null object")); |
| 22044 | + |
| 22045 | + if (obj) { |
| 22046 | + dev = obj->my_dev; |
| 22047 | + yaffs_gross_lock(dev); |
| 22048 | + yaffs_del_obj(obj); |
| 22049 | + yaffs_gross_unlock(dev); |
| 22050 | + } |
| 22051 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) |
| 22052 | + truncate_inode_pages(&inode->i_data, 0); |
| 22053 | +#endif |
| 22054 | + clear_inode(inode); |
| 22055 | +} |
| 22056 | +#endif |
| 22057 | + |
| 22058 | + |
| 22059 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 22060 | +static int yaffs_file_flush(struct file *file, fl_owner_t id) |
| 22061 | +#else |
| 22062 | +static int yaffs_file_flush(struct file *file) |
| 22063 | +#endif |
| 22064 | +{ |
| 22065 | + yaffs_obj_t *obj = yaffs_dentry_to_obj(file->f_dentry); |
| 22066 | + |
| 22067 | + yaffs_dev_t *dev = obj->my_dev; |
| 22068 | + |
| 22069 | + T(YAFFS_TRACE_OS, |
| 22070 | + (TSTR("yaffs_file_flush object %d (%s)\n"), obj->obj_id, |
| 22071 | + obj->dirty ? "dirty" : "clean")); |
| 22072 | + |
| 22073 | + yaffs_gross_lock(dev); |
| 22074 | + |
| 22075 | + yaffs_flush_file(obj, 1, 0); |
| 22076 | + |
| 22077 | + yaffs_gross_unlock(dev); |
| 22078 | + |
| 22079 | + return 0; |
| 22080 | +} |
| 22081 | + |
| 22082 | +static int yaffs_readpage_nolock(struct file *f, struct page *pg) |
| 22083 | +{ |
| 22084 | + /* Lifted from jffs2 */ |
| 22085 | + |
| 22086 | + yaffs_obj_t *obj; |
| 22087 | + unsigned char *pg_buf; |
| 22088 | + int ret; |
| 22089 | + |
| 22090 | + yaffs_dev_t *dev; |
| 22091 | + |
| 22092 | + T(YAFFS_TRACE_OS, |
| 22093 | + (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"), |
| 22094 | + (unsigned)(pg->index << PAGE_CACHE_SHIFT), |
| 22095 | + (unsigned)PAGE_CACHE_SIZE)); |
| 22096 | + |
| 22097 | + obj = yaffs_dentry_to_obj(f->f_dentry); |
| 22098 | + |
| 22099 | + dev = obj->my_dev; |
| 22100 | + |
| 22101 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 22102 | + BUG_ON(!PageLocked(pg)); |
| 22103 | +#else |
| 22104 | + if (!PageLocked(pg)) |
| 22105 | + PAGE_BUG(pg); |
| 22106 | +#endif |
| 22107 | + |
| 22108 | + pg_buf = kmap(pg); |
| 22109 | + /* FIXME: Can kmap fail? */ |
| 22110 | + |
| 22111 | + yaffs_gross_lock(dev); |
| 22112 | + |
| 22113 | + ret = yaffs_file_rd(obj, pg_buf, |
| 22114 | + pg->index << PAGE_CACHE_SHIFT, |
| 22115 | + PAGE_CACHE_SIZE); |
| 22116 | + |
| 22117 | + yaffs_gross_unlock(dev); |
| 22118 | + |
| 22119 | + if (ret >= 0) |
| 22120 | + ret = 0; |
| 22121 | + |
| 22122 | + if (ret) { |
| 22123 | + ClearPageUptodate(pg); |
| 22124 | + SetPageError(pg); |
| 22125 | + } else { |
| 22126 | + SetPageUptodate(pg); |
| 22127 | + ClearPageError(pg); |
| 22128 | + } |
| 22129 | + |
| 22130 | + flush_dcache_page(pg); |
| 22131 | + kunmap(pg); |
| 22132 | + |
| 22133 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n"))); |
| 22134 | + return ret; |
| 22135 | +} |
| 22136 | + |
| 22137 | +static int yaffs_readpage_unlock(struct file *f, struct page *pg) |
| 22138 | +{ |
| 22139 | + int ret = yaffs_readpage_nolock(f, pg); |
| 22140 | + UnlockPage(pg); |
| 22141 | + return ret; |
| 22142 | +} |
| 22143 | + |
| 22144 | +static int yaffs_readpage(struct file *f, struct page *pg) |
| 22145 | +{ |
| 22146 | + int ret; |
| 22147 | + |
| 22148 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n"))); |
| 22149 | + ret=yaffs_readpage_unlock(f, pg); |
| 22150 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n"))); |
| 22151 | + return ret; |
| 22152 | +} |
| 22153 | + |
| 22154 | +/* writepage inspired by/stolen from smbfs */ |
| 22155 | + |
| 22156 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 22157 | +static int yaffs_writepage(struct page *page, struct writeback_control *wbc) |
| 22158 | +#else |
| 22159 | +static int yaffs_writepage(struct page *page) |
| 22160 | +#endif |
| 22161 | +{ |
| 22162 | + yaffs_dev_t *dev; |
| 22163 | + struct address_space *mapping = page->mapping; |
| 22164 | + struct inode *inode; |
| 22165 | + unsigned long end_index; |
| 22166 | + char *buffer; |
| 22167 | + yaffs_obj_t *obj; |
| 22168 | + int nWritten = 0; |
| 22169 | + unsigned n_bytes; |
| 22170 | + loff_t i_size; |
| 22171 | + |
| 22172 | + if (!mapping) |
| 22173 | + BUG(); |
| 22174 | + inode = mapping->host; |
| 22175 | + if (!inode) |
| 22176 | + BUG(); |
| 22177 | + i_size = i_size_read(inode); |
| 22178 | + |
| 22179 | + end_index = i_size >> PAGE_CACHE_SHIFT; |
| 22180 | + |
| 22181 | + if(page->index < end_index) |
| 22182 | + n_bytes = PAGE_CACHE_SIZE; |
| 22183 | + else { |
| 22184 | + n_bytes = i_size & (PAGE_CACHE_SIZE -1); |
| 22185 | + |
| 22186 | + if (page->index > end_index || !n_bytes) { |
| 22187 | + T(YAFFS_TRACE_OS, |
| 22188 | + (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"), |
| 22189 | + (unsigned)(page->index << PAGE_CACHE_SHIFT), |
| 22190 | + (unsigned)inode->i_size)); |
| 22191 | + T(YAFFS_TRACE_OS, |
| 22192 | + (TSTR(" -> don't care!!\n"))); |
| 22193 | + |
| 22194 | + zero_user_segment(page,0,PAGE_CACHE_SIZE); |
| 22195 | + set_page_writeback(page); |
| 22196 | + unlock_page(page); |
| 22197 | + end_page_writeback(page); |
| 22198 | + return 0; |
| 22199 | + } |
| 22200 | + } |
| 22201 | + |
| 22202 | + if(n_bytes != PAGE_CACHE_SIZE) |
| 22203 | + zero_user_segment(page,n_bytes,PAGE_CACHE_SIZE); |
| 22204 | + |
| 22205 | + get_page(page); |
| 22206 | + |
| 22207 | + buffer = kmap(page); |
| 22208 | + |
| 22209 | + obj = yaffs_InodeToObject(inode); |
| 22210 | + dev = obj->my_dev; |
| 22211 | + yaffs_gross_lock(dev); |
| 22212 | + |
| 22213 | + T(YAFFS_TRACE_OS, |
| 22214 | + (TSTR("yaffs_writepage at %08x, size %08x\n"), |
| 22215 | + (unsigned)(page->index << PAGE_CACHE_SHIFT), n_bytes)); |
| 22216 | + T(YAFFS_TRACE_OS, |
| 22217 | + (TSTR("writepag0: obj = %05x, ino = %05x\n"), |
| 22218 | + (int)obj->variant.file_variant.file_size, (int)inode->i_size)); |
| 22219 | + |
| 22220 | + nWritten = yaffs_wr_file(obj, buffer, |
| 22221 | + page->index << PAGE_CACHE_SHIFT, n_bytes, 0); |
| 22222 | + |
| 22223 | + yaffs_touch_super(dev); |
| 22224 | + |
| 22225 | + T(YAFFS_TRACE_OS, |
| 22226 | + (TSTR("writepag1: obj = %05x, ino = %05x\n"), |
| 22227 | + (int)obj->variant.file_variant.file_size, (int)inode->i_size)); |
| 22228 | + |
| 22229 | + yaffs_gross_unlock(dev); |
| 22230 | + |
| 22231 | + kunmap(page); |
| 22232 | + set_page_writeback(page); |
| 22233 | + unlock_page(page); |
| 22234 | + end_page_writeback(page); |
| 22235 | + put_page(page); |
| 22236 | + |
| 22237 | + return (nWritten == n_bytes) ? 0 : -ENOSPC; |
| 22238 | +} |
| 22239 | + |
| 22240 | + |
| 22241 | +#if (YAFFS_USE_WRITE_BEGIN_END > 0) |
| 22242 | +static int yaffs_write_begin(struct file *filp, struct address_space *mapping, |
| 22243 | + loff_t pos, unsigned len, unsigned flags, |
| 22244 | + struct page **pagep, void **fsdata) |
| 22245 | +{ |
| 22246 | + struct page *pg = NULL; |
| 22247 | + pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
| 22248 | + |
| 22249 | + int ret = 0; |
| 22250 | + int space_held = 0; |
| 22251 | + |
| 22252 | + /* Get a page */ |
| 22253 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) |
| 22254 | + pg = grab_cache_page_write_begin(mapping, index, flags); |
| 22255 | +#else |
| 22256 | + pg = __grab_cache_page(mapping, index); |
| 22257 | +#endif |
| 22258 | + |
| 22259 | + *pagep = pg; |
| 22260 | + if (!pg) { |
| 22261 | + ret = -ENOMEM; |
| 22262 | + goto out; |
| 22263 | + } |
| 22264 | + T(YAFFS_TRACE_OS, |
| 22265 | + (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"), |
| 22266 | + (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0)); |
| 22267 | + |
| 22268 | + /* Get fs space */ |
| 22269 | + space_held = yaffs_hold_space(filp); |
| 22270 | + |
| 22271 | + if (!space_held) { |
| 22272 | + ret = -ENOSPC; |
| 22273 | + goto out; |
| 22274 | + } |
| 22275 | + |
| 22276 | + /* Update page if required */ |
| 22277 | + |
| 22278 | + if (!Page_Uptodate(pg)) |
| 22279 | + ret = yaffs_readpage_nolock(filp, pg); |
| 22280 | + |
| 22281 | + if (ret) |
| 22282 | + goto out; |
| 22283 | + |
| 22284 | + /* Happy path return */ |
| 22285 | + T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n"))); |
| 22286 | + |
| 22287 | + return 0; |
| 22288 | + |
| 22289 | +out: |
| 22290 | + T(YAFFS_TRACE_OS, |
| 22291 | + (TSTR("end yaffs_write_begin fail returning %d\n"), ret)); |
| 22292 | + if (space_held) |
| 22293 | + yaffs_release_space(filp); |
| 22294 | + if (pg) { |
| 22295 | + unlock_page(pg); |
| 22296 | + page_cache_release(pg); |
| 22297 | + } |
| 22298 | + return ret; |
| 22299 | +} |
| 22300 | + |
| 22301 | +#else |
| 22302 | + |
| 22303 | +static int yaffs_prepare_write(struct file *f, struct page *pg, |
| 22304 | + unsigned offset, unsigned to) |
| 22305 | +{ |
| 22306 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n"))); |
| 22307 | + |
| 22308 | + if (!Page_Uptodate(pg)) |
| 22309 | + return yaffs_readpage_nolock(f, pg); |
| 22310 | + return 0; |
| 22311 | +} |
| 22312 | +#endif |
| 22313 | + |
| 22314 | +#if (YAFFS_USE_WRITE_BEGIN_END > 0) |
| 22315 | +static int yaffs_write_end(struct file *filp, struct address_space *mapping, |
| 22316 | + loff_t pos, unsigned len, unsigned copied, |
| 22317 | + struct page *pg, void *fsdadata) |
| 22318 | +{ |
| 22319 | + int ret = 0; |
| 22320 | + void *addr, *kva; |
| 22321 | + uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1); |
| 22322 | + |
| 22323 | + kva = kmap(pg); |
| 22324 | + addr = kva + offset_into_page; |
| 22325 | + |
| 22326 | + T(YAFFS_TRACE_OS, |
| 22327 | + ("yaffs_write_end addr %p pos %x n_bytes %d\n", |
| 22328 | + addr,(unsigned)pos, copied)); |
| 22329 | + |
| 22330 | + ret = yaffs_file_write(filp, addr, copied, &pos); |
| 22331 | + |
| 22332 | + if (ret != copied) { |
| 22333 | + T(YAFFS_TRACE_OS, |
| 22334 | + (TSTR("yaffs_write_end not same size ret %d copied %d\n"), |
| 22335 | + ret, copied)); |
| 22336 | + SetPageError(pg); |
| 22337 | + } else { |
| 22338 | + /* Nothing */ |
| 22339 | + } |
| 22340 | + |
| 22341 | + kunmap(pg); |
| 22342 | + |
| 22343 | + yaffs_release_space(filp); |
| 22344 | + unlock_page(pg); |
| 22345 | + page_cache_release(pg); |
| 22346 | + return ret; |
| 22347 | +} |
| 22348 | +#else |
| 22349 | + |
| 22350 | +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, |
| 22351 | + unsigned to) |
| 22352 | +{ |
| 22353 | + void *addr, *kva; |
| 22354 | + |
| 22355 | + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset; |
| 22356 | + int n_bytes = to - offset; |
| 22357 | + int nWritten; |
| 22358 | + |
| 22359 | + unsigned spos = pos; |
| 22360 | + unsigned saddr; |
| 22361 | + |
| 22362 | + kva = kmap(pg); |
| 22363 | + addr = kva + offset; |
| 22364 | + |
| 22365 | + saddr = (unsigned) addr; |
| 22366 | + |
| 22367 | + T(YAFFS_TRACE_OS, |
| 22368 | + (TSTR("yaffs_commit_write addr %x pos %x n_bytes %d\n"), |
| 22369 | + saddr, spos, n_bytes)); |
| 22370 | + |
| 22371 | + nWritten = yaffs_file_write(f, addr, n_bytes, &pos); |
| 22372 | + |
| 22373 | + if (nWritten != n_bytes) { |
| 22374 | + T(YAFFS_TRACE_OS, |
| 22375 | + (TSTR("yaffs_commit_write not same size nWritten %d n_bytes %d\n"), |
| 22376 | + nWritten, n_bytes)); |
| 22377 | + SetPageError(pg); |
| 22378 | + } else { |
| 22379 | + /* Nothing */ |
| 22380 | + } |
| 22381 | + |
| 22382 | + kunmap(pg); |
| 22383 | + |
| 22384 | + T(YAFFS_TRACE_OS, |
| 22385 | + (TSTR("yaffs_commit_write returning %d\n"), |
| 22386 | + nWritten == n_bytes ? 0 : nWritten)); |
| 22387 | + |
| 22388 | + return nWritten == n_bytes ? 0 : nWritten; |
| 22389 | +} |
| 22390 | +#endif |
| 22391 | + |
| 22392 | + |
| 22393 | +static void yaffs_fill_inode_from_obj(struct inode *inode, yaffs_obj_t *obj) |
| 22394 | +{ |
| 22395 | + if (inode && obj) { |
| 22396 | + |
| 22397 | + |
| 22398 | + /* Check mode against the variant type and attempt to repair if broken. */ |
| 22399 | + __u32 mode = obj->yst_mode; |
| 22400 | + switch (obj->variant_type) { |
| 22401 | + case YAFFS_OBJECT_TYPE_FILE: |
| 22402 | + if (!S_ISREG(mode)) { |
| 22403 | + obj->yst_mode &= ~S_IFMT; |
| 22404 | + obj->yst_mode |= S_IFREG; |
| 22405 | + } |
| 22406 | + |
| 22407 | + break; |
| 22408 | + case YAFFS_OBJECT_TYPE_SYMLINK: |
| 22409 | + if (!S_ISLNK(mode)) { |
| 22410 | + obj->yst_mode &= ~S_IFMT; |
| 22411 | + obj->yst_mode |= S_IFLNK; |
| 22412 | + } |
| 22413 | + |
| 22414 | + break; |
| 22415 | + case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 22416 | + if (!S_ISDIR(mode)) { |
| 22417 | + obj->yst_mode &= ~S_IFMT; |
| 22418 | + obj->yst_mode |= S_IFDIR; |
| 22419 | + } |
| 22420 | + |
| 22421 | + break; |
| 22422 | + case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 22423 | + case YAFFS_OBJECT_TYPE_HARDLINK: |
| 22424 | + case YAFFS_OBJECT_TYPE_SPECIAL: |
| 22425 | + default: |
| 22426 | + /* TODO? */ |
| 22427 | + break; |
| 22428 | + } |
| 22429 | + |
| 22430 | + inode->i_flags |= S_NOATIME; |
| 22431 | + |
| 22432 | + inode->i_ino = obj->obj_id; |
| 22433 | + inode->i_mode = obj->yst_mode; |
| 22434 | + inode->i_uid = obj->yst_uid; |
| 22435 | + inode->i_gid = obj->yst_gid; |
| 22436 | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) |
| 22437 | + inode->i_blksize = inode->i_sb->s_blocksize; |
| 22438 | +#endif |
| 22439 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 22440 | + |
| 22441 | + inode->i_rdev = old_decode_dev(obj->yst_rdev); |
| 22442 | + inode->i_atime.tv_sec = (time_t) (obj->yst_atime); |
| 22443 | + inode->i_atime.tv_nsec = 0; |
| 22444 | + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime; |
| 22445 | + inode->i_mtime.tv_nsec = 0; |
| 22446 | + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime; |
| 22447 | + inode->i_ctime.tv_nsec = 0; |
| 22448 | +#else |
| 22449 | + inode->i_rdev = obj->yst_rdev; |
| 22450 | + inode->i_atime = obj->yst_atime; |
| 22451 | + inode->i_mtime = obj->yst_mtime; |
| 22452 | + inode->i_ctime = obj->yst_ctime; |
| 22453 | +#endif |
| 22454 | + inode->i_size = yaffs_get_obj_length(obj); |
| 22455 | + inode->i_blocks = (inode->i_size + 511) >> 9; |
| 22456 | + |
| 22457 | + inode->i_nlink = yaffs_get_obj_link_count(obj); |
| 22458 | + |
| 22459 | + T(YAFFS_TRACE_OS, |
| 22460 | + (TSTR("yaffs_fill_inode mode %x uid %d gid %d size %d count %d\n"), |
| 22461 | + inode->i_mode, inode->i_uid, inode->i_gid, |
| 22462 | + (int)inode->i_size, atomic_read(&inode->i_count))); |
| 22463 | + |
| 22464 | + switch (obj->yst_mode & S_IFMT) { |
| 22465 | + default: /* fifo, device or socket */ |
| 22466 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 22467 | + init_special_inode(inode, obj->yst_mode, |
| 22468 | + old_decode_dev(obj->yst_rdev)); |
| 22469 | +#else |
| 22470 | + init_special_inode(inode, obj->yst_mode, |
| 22471 | + (dev_t) (obj->yst_rdev)); |
| 22472 | +#endif |
| 22473 | + break; |
| 22474 | + case S_IFREG: /* file */ |
| 22475 | + inode->i_op = &yaffs_file_inode_operations; |
| 22476 | + inode->i_fop = &yaffs_file_operations; |
| 22477 | + inode->i_mapping->a_ops = |
| 22478 | + &yaffs_file_address_operations; |
| 22479 | + break; |
| 22480 | + case S_IFDIR: /* directory */ |
| 22481 | + inode->i_op = &yaffs_dir_inode_operations; |
| 22482 | + inode->i_fop = &yaffs_dir_operations; |
| 22483 | + break; |
| 22484 | + case S_IFLNK: /* symlink */ |
| 22485 | + inode->i_op = &yaffs_symlink_inode_operations; |
| 22486 | + break; |
| 22487 | + } |
| 22488 | + |
| 22489 | + yaffs_InodeToObjectLV(inode) = obj; |
| 22490 | + |
| 22491 | + obj->my_inode = inode; |
| 22492 | + |
| 22493 | + } else { |
| 22494 | + T(YAFFS_TRACE_OS, |
| 22495 | + (TSTR("yaffs_FileInode invalid parameters\n"))); |
| 22496 | + } |
| 22497 | + |
| 22498 | +} |
| 22499 | + |
| 22500 | +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev, |
| 22501 | + yaffs_obj_t *obj) |
| 22502 | +{ |
| 22503 | + struct inode *inode; |
| 22504 | + |
| 22505 | + if (!sb) { |
| 22506 | + T(YAFFS_TRACE_OS, |
| 22507 | + (TSTR("yaffs_get_inode for NULL super_block!!\n"))); |
| 22508 | + return NULL; |
| 22509 | + |
| 22510 | + } |
| 22511 | + |
| 22512 | + if (!obj) { |
| 22513 | + T(YAFFS_TRACE_OS, |
| 22514 | + (TSTR("yaffs_get_inode for NULL object!!\n"))); |
| 22515 | + return NULL; |
| 22516 | + |
| 22517 | + } |
| 22518 | + |
| 22519 | + T(YAFFS_TRACE_OS, |
| 22520 | + (TSTR("yaffs_get_inode for object %d\n"), obj->obj_id)); |
| 22521 | + |
| 22522 | + inode = Y_IGET(sb, obj->obj_id); |
| 22523 | + if (IS_ERR(inode)) |
| 22524 | + return NULL; |
| 22525 | + |
| 22526 | + /* NB Side effect: iget calls back to yaffs_read_inode(). */ |
| 22527 | + /* iget also increments the inode's i_count */ |
| 22528 | + /* NB You can't be holding grossLock or deadlock will happen! */ |
| 22529 | + |
| 22530 | + return inode; |
| 22531 | +} |
| 22532 | + |
| 22533 | +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, |
| 22534 | + loff_t *pos) |
| 22535 | +{ |
| 22536 | + yaffs_obj_t *obj; |
| 22537 | + int nWritten, ipos; |
| 22538 | + struct inode *inode; |
| 22539 | + yaffs_dev_t *dev; |
| 22540 | + |
| 22541 | + obj = yaffs_dentry_to_obj(f->f_dentry); |
| 22542 | + |
| 22543 | + dev = obj->my_dev; |
| 22544 | + |
| 22545 | + yaffs_gross_lock(dev); |
| 22546 | + |
| 22547 | + inode = f->f_dentry->d_inode; |
| 22548 | + |
| 22549 | + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) |
| 22550 | + ipos = inode->i_size; |
| 22551 | + else |
| 22552 | + ipos = *pos; |
| 22553 | + |
| 22554 | + if (!obj) |
| 22555 | + T(YAFFS_TRACE_OS, |
| 22556 | + (TSTR("yaffs_file_write: hey obj is null!\n"))); |
| 22557 | + else |
| 22558 | + T(YAFFS_TRACE_OS, |
| 22559 | + (TSTR("yaffs_file_write about to write writing %u(%x) bytes" |
| 22560 | + "to object %d at %d(%x)\n"), |
| 22561 | + (unsigned) n, (unsigned) n, obj->obj_id, ipos,ipos)); |
| 22562 | + |
| 22563 | + nWritten = yaffs_wr_file(obj, buf, ipos, n, 0); |
| 22564 | + |
| 22565 | + yaffs_touch_super(dev); |
| 22566 | + |
| 22567 | + T(YAFFS_TRACE_OS, |
| 22568 | + (TSTR("yaffs_file_write: %d(%x) bytes written\n"), |
| 22569 | + (unsigned )n,(unsigned)n)); |
| 22570 | + |
| 22571 | + if (nWritten > 0) { |
| 22572 | + ipos += nWritten; |
| 22573 | + *pos = ipos; |
| 22574 | + if (ipos > inode->i_size) { |
| 22575 | + inode->i_size = ipos; |
| 22576 | + inode->i_blocks = (ipos + 511) >> 9; |
| 22577 | + |
| 22578 | + T(YAFFS_TRACE_OS, |
| 22579 | + (TSTR("yaffs_file_write size updated to %d bytes, " |
| 22580 | + "%d blocks\n"), |
| 22581 | + ipos, (int)(inode->i_blocks))); |
| 22582 | + } |
| 22583 | + |
| 22584 | + } |
| 22585 | + yaffs_gross_unlock(dev); |
| 22586 | + return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten; |
| 22587 | +} |
| 22588 | + |
| 22589 | +/* Space holding and freeing is done to ensure we have space available for write_begin/end */ |
| 22590 | +/* For now we just assume few parallel writes and check against a small number. */ |
| 22591 | +/* Todo: need to do this with a counter to handle parallel reads better */ |
| 22592 | + |
| 22593 | +static ssize_t yaffs_hold_space(struct file *f) |
| 22594 | +{ |
| 22595 | + yaffs_obj_t *obj; |
| 22596 | + yaffs_dev_t *dev; |
| 22597 | + |
| 22598 | + int n_free_chunks; |
| 22599 | + |
| 22600 | + |
| 22601 | + obj = yaffs_dentry_to_obj(f->f_dentry); |
| 22602 | + |
| 22603 | + dev = obj->my_dev; |
| 22604 | + |
| 22605 | + yaffs_gross_lock(dev); |
| 22606 | + |
| 22607 | + n_free_chunks = yaffs_get_n_free_chunks(dev); |
| 22608 | + |
| 22609 | + yaffs_gross_unlock(dev); |
| 22610 | + |
| 22611 | + return (n_free_chunks > 20) ? 1 : 0; |
| 22612 | +} |
| 22613 | + |
| 22614 | +static void yaffs_release_space(struct file *f) |
| 22615 | +{ |
| 22616 | + yaffs_obj_t *obj; |
| 22617 | + yaffs_dev_t *dev; |
| 22618 | + |
| 22619 | + |
| 22620 | + obj = yaffs_dentry_to_obj(f->f_dentry); |
| 22621 | + |
| 22622 | + dev = obj->my_dev; |
| 22623 | + |
| 22624 | + yaffs_gross_lock(dev); |
| 22625 | + |
| 22626 | + |
| 22627 | + yaffs_gross_unlock(dev); |
| 22628 | +} |
| 22629 | + |
| 22630 | + |
| 22631 | +static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin) |
| 22632 | +{ |
| 22633 | + long long retval; |
| 22634 | + |
| 22635 | + lock_kernel(); |
| 22636 | + |
| 22637 | + switch (origin){ |
| 22638 | + case 2: |
| 22639 | + offset += i_size_read(file->f_path.dentry->d_inode); |
| 22640 | + break; |
| 22641 | + case 1: |
| 22642 | + offset += file->f_pos; |
| 22643 | + } |
| 22644 | + retval = -EINVAL; |
| 22645 | + |
| 22646 | + if (offset >= 0){ |
| 22647 | + if (offset != file->f_pos) |
| 22648 | + file->f_pos = offset; |
| 22649 | + |
| 22650 | + retval = offset; |
| 22651 | + } |
| 22652 | + unlock_kernel(); |
| 22653 | + return retval; |
| 22654 | +} |
| 22655 | + |
| 22656 | + |
| 22657 | +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) |
| 22658 | +{ |
| 22659 | + yaffs_obj_t *obj; |
| 22660 | + yaffs_dev_t *dev; |
| 22661 | + struct yaffs_SearchContext *sc; |
| 22662 | + struct inode *inode = f->f_dentry->d_inode; |
| 22663 | + unsigned long offset, curoffs; |
| 22664 | + yaffs_obj_t *l; |
| 22665 | + int retVal = 0; |
| 22666 | + |
| 22667 | + char name[YAFFS_MAX_NAME_LENGTH + 1]; |
| 22668 | + |
| 22669 | + obj = yaffs_dentry_to_obj(f->f_dentry); |
| 22670 | + dev = obj->my_dev; |
| 22671 | + |
| 22672 | + yaffs_gross_lock(dev); |
| 22673 | + |
| 22674 | + yaffs_dev_to_lc(dev)->readdirProcess = current; |
| 22675 | + |
| 22676 | + offset = f->f_pos; |
| 22677 | + |
| 22678 | + sc = yaffs_NewSearch(obj); |
| 22679 | + if(!sc){ |
| 22680 | + retVal = -ENOMEM; |
| 22681 | + goto out; |
| 22682 | + } |
| 22683 | + |
| 22684 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset)); |
| 22685 | + |
| 22686 | + if (offset == 0) { |
| 22687 | + T(YAFFS_TRACE_OS, |
| 22688 | + (TSTR("yaffs_readdir: entry . ino %d \n"), |
| 22689 | + (int)inode->i_ino)); |
| 22690 | + yaffs_gross_unlock(dev); |
| 22691 | + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){ |
| 22692 | + yaffs_gross_lock(dev); |
| 22693 | + goto out; |
| 22694 | + } |
| 22695 | + yaffs_gross_lock(dev); |
| 22696 | + offset++; |
| 22697 | + f->f_pos++; |
| 22698 | + } |
| 22699 | + if (offset == 1) { |
| 22700 | + T(YAFFS_TRACE_OS, |
| 22701 | + (TSTR("yaffs_readdir: entry .. ino %d \n"), |
| 22702 | + (int)f->f_dentry->d_parent->d_inode->i_ino)); |
| 22703 | + yaffs_gross_unlock(dev); |
| 22704 | + if (filldir(dirent, "..", 2, offset, |
| 22705 | + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){ |
| 22706 | + yaffs_gross_lock(dev); |
| 22707 | + goto out; |
| 22708 | + } |
| 22709 | + yaffs_gross_lock(dev); |
| 22710 | + offset++; |
| 22711 | + f->f_pos++; |
| 22712 | + } |
| 22713 | + |
| 22714 | + curoffs = 1; |
| 22715 | + |
| 22716 | + /* If the directory has changed since the open or last call to |
| 22717 | + readdir, rewind to after the 2 canned entries. */ |
| 22718 | + if (f->f_version != inode->i_version) { |
| 22719 | + offset = 2; |
| 22720 | + f->f_pos = offset; |
| 22721 | + f->f_version = inode->i_version; |
| 22722 | + } |
| 22723 | + |
| 22724 | + while(sc->nextReturn){ |
| 22725 | + curoffs++; |
| 22726 | + l = sc->nextReturn; |
| 22727 | + if (curoffs >= offset) { |
| 22728 | + int this_inode = yaffs_get_obj_inode(l); |
| 22729 | + int this_type = yaffs_get_obj_type(l); |
| 22730 | + |
| 22731 | + yaffs_get_obj_name(l, name, |
| 22732 | + YAFFS_MAX_NAME_LENGTH + 1); |
| 22733 | + T(YAFFS_TRACE_OS, |
| 22734 | + (TSTR("yaffs_readdir: %s inode %d\n"), |
| 22735 | + name, yaffs_get_obj_inode(l))); |
| 22736 | + |
| 22737 | + yaffs_gross_unlock(dev); |
| 22738 | + |
| 22739 | + if (filldir(dirent, |
| 22740 | + name, |
| 22741 | + strlen(name), |
| 22742 | + offset, |
| 22743 | + this_inode, |
| 22744 | + this_type) < 0){ |
| 22745 | + yaffs_gross_lock(dev); |
| 22746 | + goto out; |
| 22747 | + } |
| 22748 | + |
| 22749 | + yaffs_gross_lock(dev); |
| 22750 | + |
| 22751 | + offset++; |
| 22752 | + f->f_pos++; |
| 22753 | + } |
| 22754 | + yaffs_search_advance(sc); |
| 22755 | + } |
| 22756 | + |
| 22757 | +out: |
| 22758 | + yaffs_search_end(sc); |
| 22759 | + yaffs_dev_to_lc(dev)->readdirProcess = NULL; |
| 22760 | + yaffs_gross_unlock(dev); |
| 22761 | + |
| 22762 | + return retVal; |
| 22763 | +} |
| 22764 | + |
| 22765 | + |
| 22766 | + |
| 22767 | +/* |
| 22768 | + * File creation. Allocate an inode, and we're done.. |
| 22769 | + */ |
| 22770 | + |
| 22771 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) |
| 22772 | +#define YCRED(x) x |
| 22773 | +#else |
| 22774 | +#define YCRED(x) (x->cred) |
| 22775 | +#endif |
| 22776 | + |
| 22777 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 22778 | +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, |
| 22779 | + dev_t rdev) |
| 22780 | +#else |
| 22781 | +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, |
| 22782 | + int rdev) |
| 22783 | +#endif |
| 22784 | +{ |
| 22785 | + struct inode *inode; |
| 22786 | + |
| 22787 | + yaffs_obj_t *obj = NULL; |
| 22788 | + yaffs_dev_t *dev; |
| 22789 | + |
| 22790 | + yaffs_obj_t *parent = yaffs_InodeToObject(dir); |
| 22791 | + |
| 22792 | + int error = -ENOSPC; |
| 22793 | + uid_t uid = YCRED(current)->fsuid; |
| 22794 | + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; |
| 22795 | + |
| 22796 | + if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) |
| 22797 | + mode |= S_ISGID; |
| 22798 | + |
| 22799 | + if (parent) { |
| 22800 | + T(YAFFS_TRACE_OS, |
| 22801 | + (TSTR("yaffs_mknod: parent object %d type %d\n"), |
| 22802 | + parent->obj_id, parent->variant_type)); |
| 22803 | + } else { |
| 22804 | + T(YAFFS_TRACE_OS, |
| 22805 | + (TSTR("yaffs_mknod: could not get parent object\n"))); |
| 22806 | + return -EPERM; |
| 22807 | + } |
| 22808 | + |
| 22809 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, " |
| 22810 | + "mode %x dev %x\n"), |
| 22811 | + dentry->d_name.name, mode, rdev)); |
| 22812 | + |
| 22813 | + dev = parent->my_dev; |
| 22814 | + |
| 22815 | + yaffs_gross_lock(dev); |
| 22816 | + |
| 22817 | + switch (mode & S_IFMT) { |
| 22818 | + default: |
| 22819 | + /* Special (socket, fifo, device...) */ |
| 22820 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n"))); |
| 22821 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 22822 | + obj = yaffs_create_special(parent, dentry->d_name.name, mode, uid, |
| 22823 | + gid, old_encode_dev(rdev)); |
| 22824 | +#else |
| 22825 | + obj = yaffs_create_special(parent, dentry->d_name.name, mode, uid, |
| 22826 | + gid, rdev); |
| 22827 | +#endif |
| 22828 | + break; |
| 22829 | + case S_IFREG: /* file */ |
| 22830 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n"))); |
| 22831 | + obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid, |
| 22832 | + gid); |
| 22833 | + break; |
| 22834 | + case S_IFDIR: /* directory */ |
| 22835 | + T(YAFFS_TRACE_OS, |
| 22836 | + (TSTR("yaffs_mknod: making directory\n"))); |
| 22837 | + obj = yaffs_create_dir(parent, dentry->d_name.name, mode, |
| 22838 | + uid, gid); |
| 22839 | + break; |
| 22840 | + case S_IFLNK: /* symlink */ |
| 22841 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n"))); |
| 22842 | + obj = NULL; /* Do we ever get here? */ |
| 22843 | + break; |
| 22844 | + } |
| 22845 | + |
| 22846 | + /* Can not call yaffs_get_inode() with gross lock held */ |
| 22847 | + yaffs_gross_unlock(dev); |
| 22848 | + |
| 22849 | + if (obj) { |
| 22850 | + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); |
| 22851 | + d_instantiate(dentry, inode); |
| 22852 | + update_dir_time(dir); |
| 22853 | + T(YAFFS_TRACE_OS, |
| 22854 | + (TSTR("yaffs_mknod created object %d count = %d\n"), |
| 22855 | + obj->obj_id, atomic_read(&inode->i_count))); |
| 22856 | + error = 0; |
| 22857 | + yaffs_fill_inode_from_obj(dir,parent); |
| 22858 | + } else { |
| 22859 | + T(YAFFS_TRACE_OS, |
| 22860 | + (TSTR("yaffs_mknod failed making object\n"))); |
| 22861 | + error = -ENOMEM; |
| 22862 | + } |
| 22863 | + |
| 22864 | + return error; |
| 22865 | +} |
| 22866 | + |
| 22867 | +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
| 22868 | +{ |
| 22869 | + int retVal; |
| 22870 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n"))); |
| 22871 | + retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0); |
| 22872 | + return retVal; |
| 22873 | +} |
| 22874 | + |
| 22875 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 22876 | +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode, |
| 22877 | + struct nameidata *n) |
| 22878 | +#else |
| 22879 | +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode) |
| 22880 | +#endif |
| 22881 | +{ |
| 22882 | + T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n"))); |
| 22883 | + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0); |
| 22884 | +} |
| 22885 | + |
| 22886 | +static int yaffs_unlink(struct inode *dir, struct dentry *dentry) |
| 22887 | +{ |
| 22888 | + int retVal; |
| 22889 | + |
| 22890 | + yaffs_dev_t *dev; |
| 22891 | + yaffs_obj_t *obj; |
| 22892 | + |
| 22893 | + T(YAFFS_TRACE_OS, |
| 22894 | + (TSTR("yaffs_unlink %d:%s\n"), |
| 22895 | + (int)(dir->i_ino), |
| 22896 | + dentry->d_name.name)); |
| 22897 | + obj = yaffs_InodeToObject(dir); |
| 22898 | + dev = obj->my_dev; |
| 22899 | + |
| 22900 | + yaffs_gross_lock(dev); |
| 22901 | + |
| 22902 | + retVal = yaffs_unlinker(obj, dentry->d_name.name); |
| 22903 | + |
| 22904 | + if (retVal == YAFFS_OK) { |
| 22905 | + dentry->d_inode->i_nlink--; |
| 22906 | + dir->i_version++; |
| 22907 | + yaffs_gross_unlock(dev); |
| 22908 | + mark_inode_dirty(dentry->d_inode); |
| 22909 | + update_dir_time(dir); |
| 22910 | + return 0; |
| 22911 | + } |
| 22912 | + yaffs_gross_unlock(dev); |
| 22913 | + return -ENOTEMPTY; |
| 22914 | +} |
| 22915 | + |
| 22916 | +/* |
| 22917 | + * Create a link... |
| 22918 | + */ |
| 22919 | +static int yaffs_link(struct dentry *old_dentry, struct inode *dir, |
| 22920 | + struct dentry *dentry) |
| 22921 | +{ |
| 22922 | + struct inode *inode = old_dentry->d_inode; |
| 22923 | + yaffs_obj_t *obj = NULL; |
| 22924 | + yaffs_obj_t *link = NULL; |
| 22925 | + yaffs_dev_t *dev; |
| 22926 | + |
| 22927 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n"))); |
| 22928 | + |
| 22929 | + obj = yaffs_InodeToObject(inode); |
| 22930 | + dev = obj->my_dev; |
| 22931 | + |
| 22932 | + yaffs_gross_lock(dev); |
| 22933 | + |
| 22934 | + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ |
| 22935 | + link = yaffs_link_obj(yaffs_InodeToObject(dir), dentry->d_name.name, |
| 22936 | + obj); |
| 22937 | + |
| 22938 | + if (link) { |
| 22939 | + old_dentry->d_inode->i_nlink = yaffs_get_obj_link_count(obj); |
| 22940 | + d_instantiate(dentry, old_dentry->d_inode); |
| 22941 | + atomic_inc(&old_dentry->d_inode->i_count); |
| 22942 | + T(YAFFS_TRACE_OS, |
| 22943 | + (TSTR("yaffs_link link count %d i_count %d\n"), |
| 22944 | + old_dentry->d_inode->i_nlink, |
| 22945 | + atomic_read(&old_dentry->d_inode->i_count))); |
| 22946 | + } |
| 22947 | + |
| 22948 | + yaffs_gross_unlock(dev); |
| 22949 | + |
| 22950 | + if (link){ |
| 22951 | + update_dir_time(dir); |
| 22952 | + return 0; |
| 22953 | + } |
| 22954 | + |
| 22955 | + return -EPERM; |
| 22956 | +} |
| 22957 | + |
| 22958 | +static int yaffs_symlink(struct inode *dir, struct dentry *dentry, |
| 22959 | + const char *symname) |
| 22960 | +{ |
| 22961 | + yaffs_obj_t *obj; |
| 22962 | + yaffs_dev_t *dev; |
| 22963 | + uid_t uid = YCRED(current)->fsuid; |
| 22964 | + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; |
| 22965 | + |
| 22966 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n"))); |
| 22967 | + |
| 22968 | + dev = yaffs_InodeToObject(dir)->my_dev; |
| 22969 | + yaffs_gross_lock(dev); |
| 22970 | + obj = yaffs_create_symlink(yaffs_InodeToObject(dir), dentry->d_name.name, |
| 22971 | + S_IFLNK | S_IRWXUGO, uid, gid, symname); |
| 22972 | + yaffs_gross_unlock(dev); |
| 22973 | + |
| 22974 | + if (obj) { |
| 22975 | + struct inode *inode; |
| 22976 | + |
| 22977 | + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); |
| 22978 | + d_instantiate(dentry, inode); |
| 22979 | + update_dir_time(dir); |
| 22980 | + T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n"))); |
| 22981 | + return 0; |
| 22982 | + } else { |
| 22983 | + T(YAFFS_TRACE_OS, (TSTR("symlink not created\n"))); |
| 22984 | + } |
| 22985 | + |
| 22986 | + return -ENOMEM; |
| 22987 | +} |
| 22988 | + |
| 22989 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) |
| 22990 | +static int yaffs_sync_object(struct file *file, int datasync) |
| 22991 | +#else |
| 22992 | +static int yaffs_sync_object(struct file *file, struct dentry *dentry, |
| 22993 | + int datasync) |
| 22994 | +#endif |
| 22995 | +{ |
| 22996 | + |
| 22997 | + yaffs_obj_t *obj; |
| 22998 | + yaffs_dev_t *dev; |
| 22999 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34)) |
| 23000 | + struct dentry *dentry = file->f_path.dentry; |
| 23001 | +#endif |
| 23002 | + |
| 23003 | + obj = yaffs_dentry_to_obj(dentry); |
| 23004 | + |
| 23005 | + dev = obj->my_dev; |
| 23006 | + |
| 23007 | + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, |
| 23008 | + (TSTR("yaffs_sync_object\n"))); |
| 23009 | + yaffs_gross_lock(dev); |
| 23010 | + yaffs_flush_file(obj, 1, datasync); |
| 23011 | + yaffs_gross_unlock(dev); |
| 23012 | + return 0; |
| 23013 | +} |
| 23014 | + |
| 23015 | +/* |
| 23016 | + * The VFS layer already does all the dentry stuff for rename. |
| 23017 | + * |
| 23018 | + * NB: POSIX says you can rename an object over an old object of the same name |
| 23019 | + */ |
| 23020 | +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, |
| 23021 | + struct inode *new_dir, struct dentry *new_dentry) |
| 23022 | +{ |
| 23023 | + yaffs_dev_t *dev; |
| 23024 | + int retVal = YAFFS_FAIL; |
| 23025 | + yaffs_obj_t *target; |
| 23026 | + |
| 23027 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n"))); |
| 23028 | + dev = yaffs_InodeToObject(old_dir)->my_dev; |
| 23029 | + |
| 23030 | + yaffs_gross_lock(dev); |
| 23031 | + |
| 23032 | + /* Check if the target is an existing directory that is not empty. */ |
| 23033 | + target = yaffs_find_by_name(yaffs_InodeToObject(new_dir), |
| 23034 | + new_dentry->d_name.name); |
| 23035 | + |
| 23036 | + |
| 23037 | + |
| 23038 | + if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY && |
| 23039 | + !ylist_empty(&target->variant.dir_variant.children)) { |
| 23040 | + |
| 23041 | + T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n"))); |
| 23042 | + |
| 23043 | + retVal = YAFFS_FAIL; |
| 23044 | + } else { |
| 23045 | + /* Now does unlinking internally using shadowing mechanism */ |
| 23046 | + T(YAFFS_TRACE_OS, (TSTR("calling yaffs_rename_obj\n"))); |
| 23047 | + |
| 23048 | + retVal = yaffs_rename_obj(yaffs_InodeToObject(old_dir), |
| 23049 | + old_dentry->d_name.name, |
| 23050 | + yaffs_InodeToObject(new_dir), |
| 23051 | + new_dentry->d_name.name); |
| 23052 | + } |
| 23053 | + yaffs_gross_unlock(dev); |
| 23054 | + |
| 23055 | + if (retVal == YAFFS_OK) { |
| 23056 | + if (target) { |
| 23057 | + new_dentry->d_inode->i_nlink--; |
| 23058 | + mark_inode_dirty(new_dentry->d_inode); |
| 23059 | + } |
| 23060 | + |
| 23061 | + update_dir_time(old_dir); |
| 23062 | + if(old_dir != new_dir) |
| 23063 | + update_dir_time(new_dir); |
| 23064 | + return 0; |
| 23065 | + } else { |
| 23066 | + return -ENOTEMPTY; |
| 23067 | + } |
| 23068 | +} |
| 23069 | + |
| 23070 | +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) |
| 23071 | +{ |
| 23072 | + struct inode *inode = dentry->d_inode; |
| 23073 | + int error = 0; |
| 23074 | + yaffs_dev_t *dev; |
| 23075 | + |
| 23076 | + T(YAFFS_TRACE_OS, |
| 23077 | + (TSTR("yaffs_setattr of object %d\n"), |
| 23078 | + yaffs_InodeToObject(inode)->obj_id)); |
| 23079 | + |
| 23080 | + /* Fail if a requested resize >= 2GB */ |
| 23081 | + if (attr->ia_valid & ATTR_SIZE && |
| 23082 | + (attr->ia_size >> 31)) |
| 23083 | + error = -EINVAL; |
| 23084 | + |
| 23085 | + if (error == 0) |
| 23086 | + error = inode_change_ok(inode, attr); |
| 23087 | + if (error == 0) { |
| 23088 | + int result; |
| 23089 | + if (!error){ |
| 23090 | + error = yaffs_vfs_setattr(inode, attr); |
| 23091 | + T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n"))); |
| 23092 | + if (attr->ia_valid & ATTR_SIZE){ |
| 23093 | + yaffs_vfs_setsize(inode,attr->ia_size); |
| 23094 | + inode->i_blocks = (inode->i_size + 511) >> 9; |
| 23095 | + } |
| 23096 | + } |
| 23097 | + dev = yaffs_InodeToObject(inode)->my_dev; |
| 23098 | + if (attr->ia_valid & ATTR_SIZE){ |
| 23099 | + T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"), |
| 23100 | + (int)(attr->ia_size),(int)(attr->ia_size))); |
| 23101 | + } |
| 23102 | + yaffs_gross_lock(dev); |
| 23103 | + result = yaffs_set_attribs(yaffs_InodeToObject(inode), attr); |
| 23104 | + if(result == YAFFS_OK) { |
| 23105 | + error = 0; |
| 23106 | + } else { |
| 23107 | + error = -EPERM; |
| 23108 | + } |
| 23109 | + yaffs_gross_unlock(dev); |
| 23110 | + |
| 23111 | + } |
| 23112 | + |
| 23113 | + T(YAFFS_TRACE_OS, |
| 23114 | + (TSTR("yaffs_setattr done returning %d\n"),error)); |
| 23115 | + |
| 23116 | + return error; |
| 23117 | +} |
| 23118 | + |
| 23119 | +#ifdef CONFIG_YAFFS_XATTR |
| 23120 | +int yaffs_setxattr(struct dentry *dentry, const char *name, |
| 23121 | + const void *value, size_t size, int flags) |
| 23122 | +{ |
| 23123 | + struct inode *inode = dentry->d_inode; |
| 23124 | + int error = 0; |
| 23125 | + yaffs_dev_t *dev; |
| 23126 | + yaffs_obj_t *obj = yaffs_InodeToObject(inode); |
| 23127 | + |
| 23128 | + T(YAFFS_TRACE_OS, |
| 23129 | + (TSTR("yaffs_setxattr of object %d\n"), |
| 23130 | + obj->obj_id)); |
| 23131 | + |
| 23132 | + |
| 23133 | + if (error == 0) { |
| 23134 | + int result; |
| 23135 | + dev = obj->my_dev; |
| 23136 | + yaffs_gross_lock(dev); |
| 23137 | + result = yaffs_set_xattrib(obj, name, value, size, flags); |
| 23138 | + if(result == YAFFS_OK) |
| 23139 | + error = 0; |
| 23140 | + else if(result < 0) |
| 23141 | + error = result; |
| 23142 | + yaffs_gross_unlock(dev); |
| 23143 | + |
| 23144 | + } |
| 23145 | + T(YAFFS_TRACE_OS, |
| 23146 | + (TSTR("yaffs_setxattr done returning %d\n"),error)); |
| 23147 | + |
| 23148 | + return error; |
| 23149 | +} |
| 23150 | + |
| 23151 | + |
| 23152 | +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff, |
| 23153 | + size_t size) |
| 23154 | +{ |
| 23155 | + struct inode *inode = dentry->d_inode; |
| 23156 | + int error = 0; |
| 23157 | + yaffs_dev_t *dev; |
| 23158 | + yaffs_obj_t *obj = yaffs_InodeToObject(inode); |
| 23159 | + |
| 23160 | + T(YAFFS_TRACE_OS, |
| 23161 | + (TSTR("yaffs_getxattr \"%s\" from object %d\n"), |
| 23162 | + name, obj->obj_id)); |
| 23163 | + |
| 23164 | + if (error == 0) { |
| 23165 | + dev = obj->my_dev; |
| 23166 | + yaffs_gross_lock(dev); |
| 23167 | + error = yaffs_get_xattrib(obj, name, buff, size); |
| 23168 | + yaffs_gross_unlock(dev); |
| 23169 | + |
| 23170 | + } |
| 23171 | + T(YAFFS_TRACE_OS, |
| 23172 | + (TSTR("yaffs_getxattr done returning %d\n"),error)); |
| 23173 | + |
| 23174 | + return error; |
| 23175 | +} |
| 23176 | + |
| 23177 | +int yaffs_removexattr(struct dentry *dentry, const char *name) |
| 23178 | +{ |
| 23179 | + struct inode *inode = dentry->d_inode; |
| 23180 | + int error = 0; |
| 23181 | + yaffs_dev_t *dev; |
| 23182 | + yaffs_obj_t *obj = yaffs_InodeToObject(inode); |
| 23183 | + |
| 23184 | + T(YAFFS_TRACE_OS, |
| 23185 | + (TSTR("yaffs_removexattr of object %d\n"), |
| 23186 | + obj->obj_id)); |
| 23187 | + |
| 23188 | + |
| 23189 | + if (error == 0) { |
| 23190 | + int result; |
| 23191 | + dev = obj->my_dev; |
| 23192 | + yaffs_gross_lock(dev); |
| 23193 | + result = yaffs_remove_xattrib(obj, name); |
| 23194 | + if(result == YAFFS_OK) |
| 23195 | + error = 0; |
| 23196 | + else if(result < 0) |
| 23197 | + error = result; |
| 23198 | + yaffs_gross_unlock(dev); |
| 23199 | + |
| 23200 | + } |
| 23201 | + T(YAFFS_TRACE_OS, |
| 23202 | + (TSTR("yaffs_removexattr done returning %d\n"),error)); |
| 23203 | + |
| 23204 | + return error; |
| 23205 | +} |
| 23206 | + |
| 23207 | +ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size) |
| 23208 | +{ |
| 23209 | + struct inode *inode = dentry->d_inode; |
| 23210 | + int error = 0; |
| 23211 | + yaffs_dev_t *dev; |
| 23212 | + yaffs_obj_t *obj = yaffs_InodeToObject(inode); |
| 23213 | + |
| 23214 | + T(YAFFS_TRACE_OS, |
| 23215 | + (TSTR("yaffs_listxattr of object %d\n"), |
| 23216 | + obj->obj_id)); |
| 23217 | + |
| 23218 | + |
| 23219 | + if (error == 0) { |
| 23220 | + dev = obj->my_dev; |
| 23221 | + yaffs_gross_lock(dev); |
| 23222 | + error = yaffs_list_xattrib(obj, buff, size); |
| 23223 | + yaffs_gross_unlock(dev); |
| 23224 | + |
| 23225 | + } |
| 23226 | + T(YAFFS_TRACE_OS, |
| 23227 | + (TSTR("yaffs_listxattr done returning %d\n"),error)); |
| 23228 | + |
| 23229 | + return error; |
| 23230 | +} |
| 23231 | + |
| 23232 | +#endif |
| 23233 | + |
| 23234 | + |
| 23235 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 23236 | +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) |
| 23237 | +{ |
| 23238 | + yaffs_dev_t *dev = yaffs_dentry_to_obj(dentry)->my_dev; |
| 23239 | + struct super_block *sb = dentry->d_sb; |
| 23240 | +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 23241 | +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf) |
| 23242 | +{ |
| 23243 | + yaffs_dev_t *dev = yaffs_SuperToDevice(sb); |
| 23244 | +#else |
| 23245 | +static int yaffs_statfs(struct super_block *sb, struct statfs *buf) |
| 23246 | +{ |
| 23247 | + yaffs_dev_t *dev = yaffs_SuperToDevice(sb); |
| 23248 | +#endif |
| 23249 | + |
| 23250 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n"))); |
| 23251 | + |
| 23252 | + yaffs_gross_lock(dev); |
| 23253 | + |
| 23254 | + buf->f_type = YAFFS_MAGIC; |
| 23255 | + buf->f_bsize = sb->s_blocksize; |
| 23256 | + buf->f_namelen = 255; |
| 23257 | + |
| 23258 | + if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) { |
| 23259 | + /* Do this if chunk size is not a power of 2 */ |
| 23260 | + |
| 23261 | + uint64_t bytesInDev; |
| 23262 | + uint64_t bytesFree; |
| 23263 | + |
| 23264 | + bytesInDev = ((uint64_t)((dev->param.end_block - dev->param.start_block + 1))) * |
| 23265 | + ((uint64_t)(dev->param.chunks_per_block * dev->data_bytes_per_chunk)); |
| 23266 | + |
| 23267 | + do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */ |
| 23268 | + buf->f_blocks = bytesInDev; |
| 23269 | + |
| 23270 | + bytesFree = ((uint64_t)(yaffs_get_n_free_chunks(dev))) * |
| 23271 | + ((uint64_t)(dev->data_bytes_per_chunk)); |
| 23272 | + |
| 23273 | + do_div(bytesFree, sb->s_blocksize); |
| 23274 | + |
| 23275 | + buf->f_bfree = bytesFree; |
| 23276 | + |
| 23277 | + } else if (sb->s_blocksize > dev->data_bytes_per_chunk) { |
| 23278 | + |
| 23279 | + buf->f_blocks = |
| 23280 | + (dev->param.end_block - dev->param.start_block + 1) * |
| 23281 | + dev->param.chunks_per_block / |
| 23282 | + (sb->s_blocksize / dev->data_bytes_per_chunk); |
| 23283 | + buf->f_bfree = |
| 23284 | + yaffs_get_n_free_chunks(dev) / |
| 23285 | + (sb->s_blocksize / dev->data_bytes_per_chunk); |
| 23286 | + } else { |
| 23287 | + buf->f_blocks = |
| 23288 | + (dev->param.end_block - dev->param.start_block + 1) * |
| 23289 | + dev->param.chunks_per_block * |
| 23290 | + (dev->data_bytes_per_chunk / sb->s_blocksize); |
| 23291 | + |
| 23292 | + buf->f_bfree = |
| 23293 | + yaffs_get_n_free_chunks(dev) * |
| 23294 | + (dev->data_bytes_per_chunk / sb->s_blocksize); |
| 23295 | + } |
| 23296 | + |
| 23297 | + buf->f_files = 0; |
| 23298 | + buf->f_ffree = 0; |
| 23299 | + buf->f_bavail = buf->f_bfree; |
| 23300 | + |
| 23301 | + yaffs_gross_unlock(dev); |
| 23302 | + return 0; |
| 23303 | +} |
| 23304 | + |
| 23305 | + |
| 23306 | + |
| 23307 | +static void yaffs_flush_inodes(struct super_block *sb) |
| 23308 | +{ |
| 23309 | + struct inode *iptr; |
| 23310 | + yaffs_obj_t *obj; |
| 23311 | + |
| 23312 | + list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){ |
| 23313 | + obj = yaffs_InodeToObject(iptr); |
| 23314 | + if(obj){ |
| 23315 | + T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"), |
| 23316 | + obj->obj_id)); |
| 23317 | + yaffs_flush_file(obj,1,0); |
| 23318 | + } |
| 23319 | + } |
| 23320 | +} |
| 23321 | + |
| 23322 | + |
| 23323 | +static void yaffs_flush_super(struct super_block *sb, int do_checkpoint) |
| 23324 | +{ |
| 23325 | + yaffs_dev_t *dev = yaffs_SuperToDevice(sb); |
| 23326 | + if(!dev) |
| 23327 | + return; |
| 23328 | + |
| 23329 | + yaffs_flush_inodes(sb); |
| 23330 | + yaffs_update_dirty_dirs(dev); |
| 23331 | + yaffs_flush_whole_cache(dev); |
| 23332 | + if(do_checkpoint) |
| 23333 | + yaffs_checkpoint_save(dev); |
| 23334 | +} |
| 23335 | + |
| 23336 | + |
| 23337 | +static unsigned yaffs_bg_gc_urgency(yaffs_dev_t *dev) |
| 23338 | +{ |
| 23339 | + unsigned erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block; |
| 23340 | + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev); |
| 23341 | + unsigned scatteredFree = 0; /* Free chunks not in an erased block */ |
| 23342 | + |
| 23343 | + if(erasedChunks < dev->n_free_chunks) |
| 23344 | + scatteredFree = (dev->n_free_chunks - erasedChunks); |
| 23345 | + |
| 23346 | + if(!context->bgRunning) |
| 23347 | + return 0; |
| 23348 | + else if(scatteredFree < (dev->param.chunks_per_block * 2)) |
| 23349 | + return 0; |
| 23350 | + else if(erasedChunks > dev->n_free_chunks/2) |
| 23351 | + return 0; |
| 23352 | + else if(erasedChunks > dev->n_free_chunks/4) |
| 23353 | + return 1; |
| 23354 | + else |
| 23355 | + return 2; |
| 23356 | +} |
| 23357 | + |
| 23358 | +static int yaffs_do_sync_fs(struct super_block *sb, |
| 23359 | + int request_checkpoint) |
| 23360 | +{ |
| 23361 | + |
| 23362 | + yaffs_dev_t *dev = yaffs_SuperToDevice(sb); |
| 23363 | + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4); |
| 23364 | + unsigned gc_urgent = yaffs_bg_gc_urgency(dev); |
| 23365 | + int do_checkpoint; |
| 23366 | + |
| 23367 | + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, |
| 23368 | + (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"), |
| 23369 | + gc_urgent, |
| 23370 | + sb->s_dirt ? "dirty" : "clean", |
| 23371 | + request_checkpoint ? "checkpoint requested" : "no checkpoint", |
| 23372 | + oneshot_checkpoint ? " one-shot" : "" )); |
| 23373 | + |
| 23374 | + yaffs_gross_lock(dev); |
| 23375 | + do_checkpoint = ((request_checkpoint && !gc_urgent) || |
| 23376 | + oneshot_checkpoint) && |
| 23377 | + !dev->is_checkpointed; |
| 23378 | + |
| 23379 | + if (sb->s_dirt || do_checkpoint) { |
| 23380 | + yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint); |
| 23381 | + sb->s_dirt = 0; |
| 23382 | + if(oneshot_checkpoint) |
| 23383 | + yaffs_auto_checkpoint &= ~4; |
| 23384 | + } |
| 23385 | + yaffs_gross_unlock(dev); |
| 23386 | + |
| 23387 | + return 0; |
| 23388 | +} |
| 23389 | + |
| 23390 | +/* |
| 23391 | + * yaffs background thread functions . |
| 23392 | + * yaffs_bg_thread_fn() the thread function |
| 23393 | + * yaffs_bg_start() launches the background thread. |
| 23394 | + * yaffs_bg_stop() cleans up the background thread. |
| 23395 | + * |
| 23396 | + * NB: |
| 23397 | + * The thread should only run after the yaffs is initialised |
| 23398 | + * The thread should be stopped before yaffs is unmounted. |
| 23399 | + * The thread should not do any writing while the fs is in read only. |
| 23400 | + */ |
| 23401 | + |
| 23402 | +#ifdef YAFFS_COMPILE_BACKGROUND |
| 23403 | + |
| 23404 | +void yaffs_background_waker(unsigned long data) |
| 23405 | +{ |
| 23406 | + wake_up_process((struct task_struct *)data); |
| 23407 | +} |
| 23408 | + |
| 23409 | +static int yaffs_bg_thread_fn(void *data) |
| 23410 | +{ |
| 23411 | + yaffs_dev_t *dev = (yaffs_dev_t *)data; |
| 23412 | + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev); |
| 23413 | + unsigned long now = jiffies; |
| 23414 | + unsigned long next_dir_update = now; |
| 23415 | + unsigned long next_gc = now; |
| 23416 | + unsigned long expires; |
| 23417 | + unsigned int urgency; |
| 23418 | + |
| 23419 | + int gcResult; |
| 23420 | + struct timer_list timer; |
| 23421 | + |
| 23422 | + T(YAFFS_TRACE_BACKGROUND, |
| 23423 | + (TSTR("yaffs_background starting for dev %p\n"), |
| 23424 | + (void *)dev)); |
| 23425 | + |
| 23426 | +#ifdef YAFFS_COMPILE_FREEZER |
| 23427 | + set_freezable(); |
| 23428 | +#endif |
| 23429 | + while(context->bgRunning){ |
| 23430 | + T(YAFFS_TRACE_BACKGROUND, |
| 23431 | + (TSTR("yaffs_background\n"))); |
| 23432 | + |
| 23433 | + if(kthread_should_stop()) |
| 23434 | + break; |
| 23435 | + |
| 23436 | +#ifdef YAFFS_COMPILE_FREEZER |
| 23437 | + if(try_to_freeze()) |
| 23438 | + continue; |
| 23439 | +#endif |
| 23440 | + yaffs_gross_lock(dev); |
| 23441 | + |
| 23442 | + now = jiffies; |
| 23443 | + |
| 23444 | + if(time_after(now, next_dir_update) && yaffs_bg_enable){ |
| 23445 | + yaffs_update_dirty_dirs(dev); |
| 23446 | + next_dir_update = now + HZ; |
| 23447 | + } |
| 23448 | + |
| 23449 | + if(time_after(now,next_gc) && yaffs_bg_enable){ |
| 23450 | + if(!dev->is_checkpointed){ |
| 23451 | + urgency = yaffs_bg_gc_urgency(dev); |
| 23452 | + gcResult = yaffs_bg_gc(dev, urgency); |
| 23453 | + if(urgency > 1) |
| 23454 | + next_gc = now + HZ/20+1; |
| 23455 | + else if(urgency > 0) |
| 23456 | + next_gc = now + HZ/10+1; |
| 23457 | + else |
| 23458 | + next_gc = now + HZ * 2; |
| 23459 | + } else /* |
| 23460 | + * gc not running so set to next_dir_update |
| 23461 | + * to cut down on wake ups |
| 23462 | + */ |
| 23463 | + next_gc = next_dir_update; |
| 23464 | + } |
| 23465 | + yaffs_gross_unlock(dev); |
| 23466 | +#if 1 |
| 23467 | + expires = next_dir_update; |
| 23468 | + if (time_before(next_gc,expires)) |
| 23469 | + expires = next_gc; |
| 23470 | + if(time_before(expires,now)) |
| 23471 | + expires = now + HZ; |
| 23472 | + |
| 23473 | + Y_INIT_TIMER(&timer); |
| 23474 | + timer.expires = expires+1; |
| 23475 | + timer.data = (unsigned long) current; |
| 23476 | + timer.function = yaffs_background_waker; |
| 23477 | + |
| 23478 | + set_current_state(TASK_INTERRUPTIBLE); |
| 23479 | + add_timer(&timer); |
| 23480 | + schedule(); |
| 23481 | + del_timer_sync(&timer); |
| 23482 | +#else |
| 23483 | + msleep(10); |
| 23484 | +#endif |
| 23485 | + } |
| 23486 | + |
| 23487 | + return 0; |
| 23488 | +} |
| 23489 | + |
| 23490 | +static int yaffs_bg_start(yaffs_dev_t *dev) |
| 23491 | +{ |
| 23492 | + int retval = 0; |
| 23493 | + struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev); |
| 23494 | + |
| 23495 | + if(dev->read_only) |
| 23496 | + return -1; |
| 23497 | + |
| 23498 | + context->bgRunning = 1; |
| 23499 | + |
| 23500 | + context->bgThread = kthread_run(yaffs_bg_thread_fn, |
| 23501 | + (void *)dev,"yaffs-bg-%d",context->mount_id); |
| 23502 | + |
| 23503 | + if(IS_ERR(context->bgThread)){ |
| 23504 | + retval = PTR_ERR(context->bgThread); |
| 23505 | + context->bgThread = NULL; |
| 23506 | + context->bgRunning = 0; |
| 23507 | + } |
| 23508 | + return retval; |
| 23509 | +} |
| 23510 | + |
| 23511 | +static void yaffs_bg_stop(yaffs_dev_t *dev) |
| 23512 | +{ |
| 23513 | + struct yaffs_LinuxContext *ctxt = yaffs_dev_to_lc(dev); |
| 23514 | + |
| 23515 | + ctxt->bgRunning = 0; |
| 23516 | + |
| 23517 | + if( ctxt->bgThread){ |
| 23518 | + kthread_stop(ctxt->bgThread); |
| 23519 | + ctxt->bgThread = NULL; |
| 23520 | + } |
| 23521 | +} |
| 23522 | +#else |
| 23523 | +static int yaffs_bg_thread_fn(void *data) |
| 23524 | +{ |
| 23525 | + return 0; |
| 23526 | +} |
| 23527 | + |
| 23528 | +static int yaffs_bg_start(yaffs_dev_t *dev) |
| 23529 | +{ |
| 23530 | + return 0; |
| 23531 | +} |
| 23532 | + |
| 23533 | +static void yaffs_bg_stop(yaffs_dev_t *dev) |
| 23534 | +{ |
| 23535 | +} |
| 23536 | +#endif |
| 23537 | + |
| 23538 | + |
| 23539 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 23540 | +static void yaffs_write_super(struct super_block *sb) |
| 23541 | +#else |
| 23542 | +static int yaffs_write_super(struct super_block *sb) |
| 23543 | +#endif |
| 23544 | +{ |
| 23545 | + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2); |
| 23546 | + |
| 23547 | + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND, |
| 23548 | + (TSTR("yaffs_write_super%s\n"), |
| 23549 | + request_checkpoint ? " checkpt" : "")); |
| 23550 | + |
| 23551 | + yaffs_do_sync_fs(sb, request_checkpoint); |
| 23552 | + |
| 23553 | +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) |
| 23554 | + return 0; |
| 23555 | +#endif |
| 23556 | +} |
| 23557 | + |
| 23558 | + |
| 23559 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 23560 | +static int yaffs_sync_fs(struct super_block *sb, int wait) |
| 23561 | +#else |
| 23562 | +static int yaffs_sync_fs(struct super_block *sb) |
| 23563 | +#endif |
| 23564 | +{ |
| 23565 | + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1); |
| 23566 | + |
| 23567 | + T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, |
| 23568 | + (TSTR("yaffs_sync_fs%s\n"), |
| 23569 | + request_checkpoint ? " checkpt" : "")); |
| 23570 | + |
| 23571 | + yaffs_do_sync_fs(sb, request_checkpoint); |
| 23572 | + |
| 23573 | + return 0; |
| 23574 | +} |
| 23575 | + |
| 23576 | +#ifdef YAFFS_USE_OWN_IGET |
| 23577 | + |
| 23578 | +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) |
| 23579 | +{ |
| 23580 | + struct inode *inode; |
| 23581 | + yaffs_obj_t *obj; |
| 23582 | + yaffs_dev_t *dev = yaffs_SuperToDevice(sb); |
| 23583 | + |
| 23584 | + T(YAFFS_TRACE_OS, |
| 23585 | + (TSTR("yaffs_iget for %lu\n"), ino)); |
| 23586 | + |
| 23587 | + inode = iget_locked(sb, ino); |
| 23588 | + if (!inode) |
| 23589 | + return ERR_PTR(-ENOMEM); |
| 23590 | + if (!(inode->i_state & I_NEW)) |
| 23591 | + return inode; |
| 23592 | + |
| 23593 | + /* NB This is called as a side effect of other functions, but |
| 23594 | + * we had to release the lock to prevent deadlocks, so |
| 23595 | + * need to lock again. |
| 23596 | + */ |
| 23597 | + |
| 23598 | + yaffs_gross_lock(dev); |
| 23599 | + |
| 23600 | + obj = yaffs_find_by_number(dev, inode->i_ino); |
| 23601 | + |
| 23602 | + yaffs_fill_inode_from_obj(inode, obj); |
| 23603 | + |
| 23604 | + yaffs_gross_unlock(dev); |
| 23605 | + |
| 23606 | + unlock_new_inode(inode); |
| 23607 | + return inode; |
| 23608 | +} |
| 23609 | + |
| 23610 | +#else |
| 23611 | + |
| 23612 | +static void yaffs_read_inode(struct inode *inode) |
| 23613 | +{ |
| 23614 | + /* NB This is called as a side effect of other functions, but |
| 23615 | + * we had to release the lock to prevent deadlocks, so |
| 23616 | + * need to lock again. |
| 23617 | + */ |
| 23618 | + |
| 23619 | + yaffs_obj_t *obj; |
| 23620 | + yaffs_dev_t *dev = yaffs_SuperToDevice(inode->i_sb); |
| 23621 | + |
| 23622 | + T(YAFFS_TRACE_OS, |
| 23623 | + (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino)); |
| 23624 | + |
| 23625 | + if(current != yaffs_dev_to_lc(dev)->readdirProcess) |
| 23626 | + yaffs_gross_lock(dev); |
| 23627 | + |
| 23628 | + obj = yaffs_find_by_number(dev, inode->i_ino); |
| 23629 | + |
| 23630 | + yaffs_fill_inode_from_obj(inode, obj); |
| 23631 | + |
| 23632 | + if(current != yaffs_dev_to_lc(dev)->readdirProcess) |
| 23633 | + yaffs_gross_unlock(dev); |
| 23634 | +} |
| 23635 | + |
| 23636 | +#endif |
| 23637 | + |
| 23638 | +static YLIST_HEAD(yaffs_context_list); |
| 23639 | +struct semaphore yaffs_context_lock; |
| 23640 | + |
| 23641 | +static void yaffs_put_super(struct super_block *sb) |
| 23642 | +{ |
| 23643 | + yaffs_dev_t *dev = yaffs_SuperToDevice(sb); |
| 23644 | + |
| 23645 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n"))); |
| 23646 | + |
| 23647 | + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, |
| 23648 | + (TSTR("Shutting down yaffs background thread\n"))); |
| 23649 | + yaffs_bg_stop(dev); |
| 23650 | + T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND, |
| 23651 | + (TSTR("yaffs background thread shut down\n"))); |
| 23652 | + |
| 23653 | + yaffs_gross_lock(dev); |
| 23654 | + |
| 23655 | + yaffs_flush_super(sb,1); |
| 23656 | + |
| 23657 | + if (yaffs_dev_to_lc(dev)->putSuperFunc) |
| 23658 | + yaffs_dev_to_lc(dev)->putSuperFunc(sb); |
| 23659 | + |
| 23660 | + |
| 23661 | + yaffs_deinitialise(dev); |
| 23662 | + |
| 23663 | + yaffs_gross_unlock(dev); |
| 23664 | + |
| 23665 | + down(&yaffs_context_lock); |
| 23666 | + ylist_del_init(&(yaffs_dev_to_lc(dev)->contextList)); |
| 23667 | + up(&yaffs_context_lock); |
| 23668 | + |
| 23669 | + if (yaffs_dev_to_lc(dev)->spareBuffer) { |
| 23670 | + YFREE(yaffs_dev_to_lc(dev)->spareBuffer); |
| 23671 | + yaffs_dev_to_lc(dev)->spareBuffer = NULL; |
| 23672 | + } |
| 23673 | + |
| 23674 | + kfree(dev); |
| 23675 | +} |
| 23676 | + |
| 23677 | + |
| 23678 | +static void yaffs_MTDPutSuper(struct super_block *sb) |
| 23679 | +{ |
| 23680 | + struct mtd_info *mtd = yaffs_dev_to_mtd(yaffs_SuperToDevice(sb)); |
| 23681 | + |
| 23682 | + if (mtd->sync) |
| 23683 | + mtd->sync(mtd); |
| 23684 | + |
| 23685 | + put_mtd_device(mtd); |
| 23686 | +} |
| 23687 | + |
| 23688 | + |
| 23689 | +static void yaffs_touch_super(yaffs_dev_t *dev) |
| 23690 | +{ |
| 23691 | + struct super_block *sb = yaffs_dev_to_lc(dev)->superBlock; |
| 23692 | + |
| 23693 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_touch_super() sb = %p\n"), sb)); |
| 23694 | + if (sb) |
| 23695 | + sb->s_dirt = 1; |
| 23696 | +} |
| 23697 | + |
| 23698 | +typedef struct { |
| 23699 | + int inband_tags; |
| 23700 | + int skip_checkpoint_read; |
| 23701 | + int skip_checkpoint_write; |
| 23702 | + int no_cache; |
| 23703 | + int tags_ecc_on; |
| 23704 | + int tags_ecc_overridden; |
| 23705 | + int lazy_loading_enabled; |
| 23706 | + int lazy_loading_overridden; |
| 23707 | + int empty_lost_and_found; |
| 23708 | + int empty_lost_and_found_overridden; |
| 23709 | +} yaffs_options; |
| 23710 | + |
| 23711 | +#define MAX_OPT_LEN 30 |
| 23712 | +static int yaffs_parse_options(yaffs_options *options, const char *options_str) |
| 23713 | +{ |
| 23714 | + char cur_opt[MAX_OPT_LEN + 1]; |
| 23715 | + int p; |
| 23716 | + int error = 0; |
| 23717 | + |
| 23718 | + /* Parse through the options which is a comma seperated list */ |
| 23719 | + |
| 23720 | + while (options_str && *options_str && !error) { |
| 23721 | + memset(cur_opt, 0, MAX_OPT_LEN + 1); |
| 23722 | + p = 0; |
| 23723 | + |
| 23724 | + while(*options_str == ',') |
| 23725 | + options_str++; |
| 23726 | + |
| 23727 | + while (*options_str && *options_str != ',') { |
| 23728 | + if (p < MAX_OPT_LEN) { |
| 23729 | + cur_opt[p] = *options_str; |
| 23730 | + p++; |
| 23731 | + } |
| 23732 | + options_str++; |
| 23733 | + } |
| 23734 | + |
| 23735 | + if (!strcmp(cur_opt, "inband-tags")) |
| 23736 | + options->inband_tags = 1; |
| 23737 | + else if (!strcmp(cur_opt, "tags-ecc-off")){ |
| 23738 | + options->tags_ecc_on = 0; |
| 23739 | + options->tags_ecc_overridden=1; |
| 23740 | + } else if (!strcmp(cur_opt, "tags-ecc-on")){ |
| 23741 | + options->tags_ecc_on = 1; |
| 23742 | + options->tags_ecc_overridden = 1; |
| 23743 | + } else if (!strcmp(cur_opt, "lazy-loading-off")){ |
| 23744 | + options->lazy_loading_enabled = 0; |
| 23745 | + options->lazy_loading_overridden=1; |
| 23746 | + } else if (!strcmp(cur_opt, "lazy-loading-on")){ |
| 23747 | + options->lazy_loading_enabled = 1; |
| 23748 | + options->lazy_loading_overridden = 1; |
| 23749 | + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){ |
| 23750 | + options->empty_lost_and_found = 0; |
| 23751 | + options->empty_lost_and_found_overridden=1; |
| 23752 | + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){ |
| 23753 | + options->empty_lost_and_found = 1; |
| 23754 | + options->empty_lost_and_found_overridden=1; |
| 23755 | + } else if (!strcmp(cur_opt, "no-cache")) |
| 23756 | + options->no_cache = 1; |
| 23757 | + else if (!strcmp(cur_opt, "no-checkpoint-read")) |
| 23758 | + options->skip_checkpoint_read = 1; |
| 23759 | + else if (!strcmp(cur_opt, "no-checkpoint-write")) |
| 23760 | + options->skip_checkpoint_write = 1; |
| 23761 | + else if (!strcmp(cur_opt, "no-checkpoint")) { |
| 23762 | + options->skip_checkpoint_read = 1; |
| 23763 | + options->skip_checkpoint_write = 1; |
| 23764 | + } else { |
| 23765 | + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n", |
| 23766 | + cur_opt); |
| 23767 | + error = 1; |
| 23768 | + } |
| 23769 | + } |
| 23770 | + |
| 23771 | + return error; |
| 23772 | +} |
| 23773 | + |
| 23774 | +static struct super_block *yaffs_internal_read_super(int yaffs_version, |
| 23775 | + struct super_block *sb, |
| 23776 | + void *data, int silent) |
| 23777 | +{ |
| 23778 | + int nBlocks; |
| 23779 | + struct inode *inode = NULL; |
| 23780 | + struct dentry *root; |
| 23781 | + yaffs_dev_t *dev = 0; |
| 23782 | + char devname_buf[BDEVNAME_SIZE + 1]; |
| 23783 | + struct mtd_info *mtd; |
| 23784 | + int err; |
| 23785 | + char *data_str = (char *)data; |
| 23786 | + struct yaffs_LinuxContext *context = NULL; |
| 23787 | + yaffs_param_t *param; |
| 23788 | + |
| 23789 | + int read_only = 0; |
| 23790 | + |
| 23791 | + yaffs_options options; |
| 23792 | + |
| 23793 | + unsigned mount_id; |
| 23794 | + int found; |
| 23795 | + struct yaffs_LinuxContext *context_iterator; |
| 23796 | + struct ylist_head *l; |
| 23797 | + |
| 23798 | + sb->s_magic = YAFFS_MAGIC; |
| 23799 | + sb->s_op = &yaffs_super_ops; |
| 23800 | + sb->s_flags |= MS_NOATIME; |
| 23801 | + |
| 23802 | + read_only =((sb->s_flags & MS_RDONLY) != 0); |
| 23803 | + |
| 23804 | + |
| 23805 | +#ifdef YAFFS_COMPILE_EXPORTFS |
| 23806 | + sb->s_export_op = &yaffs_export_ops; |
| 23807 | +#endif |
| 23808 | + |
| 23809 | + if (!sb) |
| 23810 | + printk(KERN_INFO "yaffs: sb is NULL\n"); |
| 23811 | + else if (!sb->s_dev) |
| 23812 | + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); |
| 23813 | + else if (!yaffs_devname(sb, devname_buf)) |
| 23814 | + printk(KERN_INFO "yaffs: devname is NULL\n"); |
| 23815 | + else |
| 23816 | + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n", |
| 23817 | + sb->s_dev, |
| 23818 | + yaffs_devname(sb, devname_buf), |
| 23819 | + read_only ? "ro" : "rw"); |
| 23820 | + |
| 23821 | + if (!data_str) |
| 23822 | + data_str = ""; |
| 23823 | + |
| 23824 | + printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str); |
| 23825 | + |
| 23826 | + memset(&options, 0, sizeof(options)); |
| 23827 | + |
| 23828 | + if (yaffs_parse_options(&options, data_str)) { |
| 23829 | + /* Option parsing failed */ |
| 23830 | + return NULL; |
| 23831 | + } |
| 23832 | + |
| 23833 | + |
| 23834 | + sb->s_blocksize = PAGE_CACHE_SIZE; |
| 23835 | + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
| 23836 | + |
| 23837 | + T(YAFFS_TRACE_OS, |
| 23838 | + (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffs_version)); |
| 23839 | + T(YAFFS_TRACE_OS, |
| 23840 | + (TSTR("yaffs_read_super: block size %d\n"), |
| 23841 | + (int)(sb->s_blocksize))); |
| 23842 | + |
| 23843 | + T(YAFFS_TRACE_ALWAYS, |
| 23844 | + (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"), |
| 23845 | + MAJOR(sb->s_dev), MINOR(sb->s_dev), |
| 23846 | + yaffs_devname(sb, devname_buf))); |
| 23847 | + |
| 23848 | + /* Check it's an mtd device..... */ |
| 23849 | + if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) |
| 23850 | + return NULL; /* This isn't an mtd device */ |
| 23851 | + |
| 23852 | + /* Get the device */ |
| 23853 | + mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); |
| 23854 | + if (!mtd) { |
| 23855 | + T(YAFFS_TRACE_ALWAYS, |
| 23856 | + (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"), |
| 23857 | + MINOR(sb->s_dev))); |
| 23858 | + return NULL; |
| 23859 | + } |
| 23860 | + /* Check it's NAND */ |
| 23861 | + if (mtd->type != MTD_NANDFLASH) { |
| 23862 | + T(YAFFS_TRACE_ALWAYS, |
| 23863 | + (TSTR("yaffs: MTD device is not NAND it's type %d\n"), |
| 23864 | + mtd->type)); |
| 23865 | + return NULL; |
| 23866 | + } |
| 23867 | + |
| 23868 | + T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase)); |
| 23869 | + T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read)); |
| 23870 | + T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write)); |
| 23871 | + T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob)); |
| 23872 | + T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob)); |
| 23873 | + T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad)); |
| 23874 | + T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad)); |
| 23875 | + T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd))); |
| 23876 | + T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize)); |
| 23877 | + T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize)); |
| 23878 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) |
| 23879 | + T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size)); |
| 23880 | +#else |
| 23881 | + T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size)); |
| 23882 | +#endif |
| 23883 | + |
| 23884 | +#ifdef CONFIG_YAFFS_AUTO_YAFFS2 |
| 23885 | + |
| 23886 | + if (yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) { |
| 23887 | + T(YAFFS_TRACE_ALWAYS, |
| 23888 | + (TSTR("yaffs: auto selecting yaffs2\n"))); |
| 23889 | + yaffs_version = 2; |
| 23890 | + } |
| 23891 | + |
| 23892 | + /* Added NCB 26/5/2006 for completeness */ |
| 23893 | + if (yaffs_version == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) { |
| 23894 | + T(YAFFS_TRACE_ALWAYS, |
| 23895 | + (TSTR("yaffs: auto selecting yaffs1\n"))); |
| 23896 | + yaffs_version = 1; |
| 23897 | + } |
| 23898 | + |
| 23899 | +#endif |
| 23900 | + |
| 23901 | + if (yaffs_version == 2) { |
| 23902 | + /* Check for version 2 style functions */ |
| 23903 | + if (!mtd->erase || |
| 23904 | + !mtd->block_isbad || |
| 23905 | + !mtd->block_markbad || |
| 23906 | + !mtd->read || |
| 23907 | + !mtd->write || |
| 23908 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 23909 | + !mtd->read_oob || !mtd->write_oob) { |
| 23910 | +#else |
| 23911 | + !mtd->write_ecc || |
| 23912 | + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { |
| 23913 | +#endif |
| 23914 | + T(YAFFS_TRACE_ALWAYS, |
| 23915 | + (TSTR("yaffs: MTD device does not support required " |
| 23916 | + "functions\n"))); |
| 23917 | + return NULL; |
| 23918 | + } |
| 23919 | + |
| 23920 | + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || |
| 23921 | + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) && |
| 23922 | + !options.inband_tags) { |
| 23923 | + T(YAFFS_TRACE_ALWAYS, |
| 23924 | + (TSTR("yaffs: MTD device does not have the " |
| 23925 | + "right page sizes\n"))); |
| 23926 | + return NULL; |
| 23927 | + } |
| 23928 | + } else { |
| 23929 | + /* Check for V1 style functions */ |
| 23930 | + if (!mtd->erase || |
| 23931 | + !mtd->read || |
| 23932 | + !mtd->write || |
| 23933 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 23934 | + !mtd->read_oob || !mtd->write_oob) { |
| 23935 | +#else |
| 23936 | + !mtd->write_ecc || |
| 23937 | + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { |
| 23938 | +#endif |
| 23939 | + T(YAFFS_TRACE_ALWAYS, |
| 23940 | + (TSTR("yaffs: MTD device does not support required " |
| 23941 | + "functions\n"))); |
| 23942 | + return NULL; |
| 23943 | + } |
| 23944 | + |
| 23945 | + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK || |
| 23946 | + mtd->oobsize != YAFFS_BYTES_PER_SPARE) { |
| 23947 | + T(YAFFS_TRACE_ALWAYS, |
| 23948 | + (TSTR("yaffs: MTD device does not support have the " |
| 23949 | + "right page sizes\n"))); |
| 23950 | + return NULL; |
| 23951 | + } |
| 23952 | + } |
| 23953 | + |
| 23954 | + /* OK, so if we got here, we have an MTD that's NAND and looks |
| 23955 | + * like it has the right capabilities |
| 23956 | + * Set the yaffs_dev_t up for mtd |
| 23957 | + */ |
| 23958 | + |
| 23959 | + if (!read_only && !(mtd->flags & MTD_WRITEABLE)){ |
| 23960 | + read_only = 1; |
| 23961 | + printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only"); |
| 23962 | + sb->s_flags |= MS_RDONLY; |
| 23963 | + } |
| 23964 | + |
| 23965 | + dev = kmalloc(sizeof(yaffs_dev_t), GFP_KERNEL); |
| 23966 | + context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL); |
| 23967 | + |
| 23968 | + if(!dev || !context ){ |
| 23969 | + if(dev) |
| 23970 | + kfree(dev); |
| 23971 | + if(context) |
| 23972 | + kfree(context); |
| 23973 | + dev = NULL; |
| 23974 | + context = NULL; |
| 23975 | + } |
| 23976 | + |
| 23977 | + if (!dev) { |
| 23978 | + /* Deep shit could not allocate device structure */ |
| 23979 | + T(YAFFS_TRACE_ALWAYS, |
| 23980 | + (TSTR("yaffs_read_super: Failed trying to allocate " |
| 23981 | + "yaffs_dev_t. \n"))); |
| 23982 | + return NULL; |
| 23983 | + } |
| 23984 | + memset(dev, 0, sizeof(yaffs_dev_t)); |
| 23985 | + param = &(dev->param); |
| 23986 | + |
| 23987 | + memset(context,0,sizeof(struct yaffs_LinuxContext)); |
| 23988 | + dev->os_context = context; |
| 23989 | + YINIT_LIST_HEAD(&(context->contextList)); |
| 23990 | + context->dev = dev; |
| 23991 | + context->superBlock = sb; |
| 23992 | + |
| 23993 | + dev->read_only = read_only; |
| 23994 | + |
| 23995 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 23996 | + sb->s_fs_info = dev; |
| 23997 | +#else |
| 23998 | + sb->u.generic_sbp = dev; |
| 23999 | +#endif |
| 24000 | + |
| 24001 | + dev->driver_context = mtd; |
| 24002 | + param->name = mtd->name; |
| 24003 | + |
| 24004 | + /* Set up the memory size parameters.... */ |
| 24005 | + |
| 24006 | + nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK)); |
| 24007 | + |
| 24008 | + param->start_block = 0; |
| 24009 | + param->end_block = nBlocks - 1; |
| 24010 | + param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK; |
| 24011 | + param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK; |
| 24012 | + param->n_reserved_blocks = 5; |
| 24013 | + param->n_caches = (options.no_cache) ? 0 : 10; |
| 24014 | + param->inband_tags = options.inband_tags; |
| 24015 | + |
| 24016 | +#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD |
| 24017 | + param->disable_lazy_load = 1; |
| 24018 | +#endif |
| 24019 | +#ifdef CONFIG_YAFFS_XATTR |
| 24020 | + param->enable_xattr = 1; |
| 24021 | +#endif |
| 24022 | + if(options.lazy_loading_overridden) |
| 24023 | + param->disable_lazy_load = !options.lazy_loading_enabled; |
| 24024 | + |
| 24025 | +#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC |
| 24026 | + param->no_tags_ecc = 1; |
| 24027 | +#endif |
| 24028 | + |
| 24029 | +#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND |
| 24030 | +#else |
| 24031 | + param->defered_dir_update = 1; |
| 24032 | +#endif |
| 24033 | + |
| 24034 | + if(options.tags_ecc_overridden) |
| 24035 | + param->no_tags_ecc = !options.tags_ecc_on; |
| 24036 | + |
| 24037 | +#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND |
| 24038 | + param->empty_lost_n_found = 1; |
| 24039 | +#endif |
| 24040 | + |
| 24041 | +#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING |
| 24042 | + param->refresh_period = 0; |
| 24043 | +#else |
| 24044 | + param->refresh_period = 500; |
| 24045 | +#endif |
| 24046 | + |
| 24047 | +#ifdef CONFIG_YAFFS__ALWAYS_CHECK_CHUNK_ERASED |
| 24048 | + param->always_check_erased = 1; |
| 24049 | +#endif |
| 24050 | + |
| 24051 | + if(options.empty_lost_and_found_overridden) |
| 24052 | + param->empty_lost_n_found = options.empty_lost_and_found; |
| 24053 | + |
| 24054 | + /* ... and the functions. */ |
| 24055 | + if (yaffs_version == 2) { |
| 24056 | + param->write_chunk_tags_fn = |
| 24057 | + nandmtd2_WriteChunkWithTagsToNAND; |
| 24058 | + param->read_chunk_tags_fn = |
| 24059 | + nandmtd2_ReadChunkWithTagsFromNAND; |
| 24060 | + param->bad_block_fn = nandmtd2_MarkNANDBlockBad; |
| 24061 | + param->query_block_fn = nandmtd2_QueryNANDBlock; |
| 24062 | + yaffs_dev_to_lc(dev)->spareBuffer = YMALLOC(mtd->oobsize); |
| 24063 | + param->is_yaffs2 = 1; |
| 24064 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 24065 | + param->total_bytes_per_chunk = mtd->writesize; |
| 24066 | + param->chunks_per_block = mtd->erasesize / mtd->writesize; |
| 24067 | +#else |
| 24068 | + param->total_bytes_per_chunk = mtd->oobblock; |
| 24069 | + param->chunks_per_block = mtd->erasesize / mtd->oobblock; |
| 24070 | +#endif |
| 24071 | + nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize); |
| 24072 | + |
| 24073 | + param->start_block = 0; |
| 24074 | + param->end_block = nBlocks - 1; |
| 24075 | + } else { |
| 24076 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 24077 | + /* use the MTD interface in yaffs_mtdif1.c */ |
| 24078 | + param->write_chunk_tags_fn = |
| 24079 | + nandmtd1_WriteChunkWithTagsToNAND; |
| 24080 | + param->read_chunk_tags_fn = |
| 24081 | + nandmtd1_ReadChunkWithTagsFromNAND; |
| 24082 | + param->bad_block_fn = nandmtd1_MarkNANDBlockBad; |
| 24083 | + param->query_block_fn = nandmtd1_QueryNANDBlock; |
| 24084 | +#else |
| 24085 | + param->write_chunk_fn = nandmtd_WriteChunkToNAND; |
| 24086 | + param->read_chunk_fn = nandmtd_ReadChunkFromNAND; |
| 24087 | +#endif |
| 24088 | + param->is_yaffs2 = 0; |
| 24089 | + } |
| 24090 | + /* ... and common functions */ |
| 24091 | + param->erase_fn = nandmtd_EraseBlockInNAND; |
| 24092 | + param->initialise_flash_fn = nandmtd_InitialiseNAND; |
| 24093 | + |
| 24094 | + yaffs_dev_to_lc(dev)->putSuperFunc = yaffs_MTDPutSuper; |
| 24095 | + |
| 24096 | + param->sb_dirty_fn = yaffs_touch_super; |
| 24097 | + param->gc_control = yaffs_gc_control_callback; |
| 24098 | + |
| 24099 | + yaffs_dev_to_lc(dev)->superBlock= sb; |
| 24100 | + |
| 24101 | + |
| 24102 | +#ifndef CONFIG_YAFFS_DOES_ECC |
| 24103 | + param->use_nand_ecc = 1; |
| 24104 | +#endif |
| 24105 | + |
| 24106 | +#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES |
| 24107 | + param->wide_tnodes_disabled = 1; |
| 24108 | +#endif |
| 24109 | + |
| 24110 | + param->skip_checkpt_rd = options.skip_checkpoint_read; |
| 24111 | + param->skip_checkpt_wr = options.skip_checkpoint_write; |
| 24112 | + |
| 24113 | + down(&yaffs_context_lock); |
| 24114 | + /* Get a mount id */ |
| 24115 | + found = 0; |
| 24116 | + for(mount_id=0; ! found; mount_id++){ |
| 24117 | + found = 1; |
| 24118 | + ylist_for_each(l,&yaffs_context_list){ |
| 24119 | + context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList); |
| 24120 | + if(context_iterator->mount_id == mount_id) |
| 24121 | + found = 0; |
| 24122 | + } |
| 24123 | + } |
| 24124 | + context->mount_id = mount_id; |
| 24125 | + |
| 24126 | + ylist_add_tail(&(yaffs_dev_to_lc(dev)->contextList), &yaffs_context_list); |
| 24127 | + up(&yaffs_context_lock); |
| 24128 | + |
| 24129 | + /* Directory search handling...*/ |
| 24130 | + YINIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->searchContexts)); |
| 24131 | + param->remove_obj_fn = yaffs_remove_obj_callback; |
| 24132 | + |
| 24133 | + init_MUTEX(&(yaffs_dev_to_lc(dev)->grossLock)); |
| 24134 | + |
| 24135 | + yaffs_gross_lock(dev); |
| 24136 | + |
| 24137 | + err = yaffs_guts_initialise(dev); |
| 24138 | + |
| 24139 | + T(YAFFS_TRACE_OS, |
| 24140 | + (TSTR("yaffs_read_super: guts initialised %s\n"), |
| 24141 | + (err == YAFFS_OK) ? "OK" : "FAILED")); |
| 24142 | + |
| 24143 | + if(err == YAFFS_OK) |
| 24144 | + yaffs_bg_start(dev); |
| 24145 | + |
| 24146 | + if(!context->bgThread) |
| 24147 | + param->defered_dir_update = 0; |
| 24148 | + |
| 24149 | + |
| 24150 | + /* Release lock before yaffs_get_inode() */ |
| 24151 | + yaffs_gross_unlock(dev); |
| 24152 | + |
| 24153 | + /* Create root inode */ |
| 24154 | + if (err == YAFFS_OK) |
| 24155 | + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, |
| 24156 | + yaffs_root(dev)); |
| 24157 | + |
| 24158 | + if (!inode) |
| 24159 | + return NULL; |
| 24160 | + |
| 24161 | + inode->i_op = &yaffs_dir_inode_operations; |
| 24162 | + inode->i_fop = &yaffs_dir_operations; |
| 24163 | + |
| 24164 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n"))); |
| 24165 | + |
| 24166 | + root = d_alloc_root(inode); |
| 24167 | + |
| 24168 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n"))); |
| 24169 | + |
| 24170 | + if (!root) { |
| 24171 | + iput(inode); |
| 24172 | + return NULL; |
| 24173 | + } |
| 24174 | + sb->s_root = root; |
| 24175 | + sb->s_dirt = !dev->is_checkpointed; |
| 24176 | + T(YAFFS_TRACE_ALWAYS, |
| 24177 | + (TSTR("yaffs_read_super: is_checkpointed %d\n"), |
| 24178 | + dev->is_checkpointed)); |
| 24179 | + |
| 24180 | + T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n"))); |
| 24181 | + return sb; |
| 24182 | +} |
| 24183 | + |
| 24184 | + |
| 24185 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 24186 | +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, |
| 24187 | + int silent) |
| 24188 | +{ |
| 24189 | + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; |
| 24190 | +} |
| 24191 | + |
| 24192 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 24193 | +static int yaffs_read_super(struct file_system_type *fs, |
| 24194 | + int flags, const char *dev_name, |
| 24195 | + void *data, struct vfsmount *mnt) |
| 24196 | +{ |
| 24197 | + |
| 24198 | + return get_sb_bdev(fs, flags, dev_name, data, |
| 24199 | + yaffs_internal_read_super_mtd, mnt); |
| 24200 | +} |
| 24201 | +#else |
| 24202 | +static struct super_block *yaffs_read_super(struct file_system_type *fs, |
| 24203 | + int flags, const char *dev_name, |
| 24204 | + void *data) |
| 24205 | +{ |
| 24206 | + |
| 24207 | + return get_sb_bdev(fs, flags, dev_name, data, |
| 24208 | + yaffs_internal_read_super_mtd); |
| 24209 | +} |
| 24210 | +#endif |
| 24211 | + |
| 24212 | +static struct file_system_type yaffs_fs_type = { |
| 24213 | + .owner = THIS_MODULE, |
| 24214 | + .name = "yaffs", |
| 24215 | + .get_sb = yaffs_read_super, |
| 24216 | + .kill_sb = kill_block_super, |
| 24217 | + .fs_flags = FS_REQUIRES_DEV, |
| 24218 | +}; |
| 24219 | +#else |
| 24220 | +static struct super_block *yaffs_read_super(struct super_block *sb, void *data, |
| 24221 | + int silent) |
| 24222 | +{ |
| 24223 | + return yaffs_internal_read_super(1, sb, data, silent); |
| 24224 | +} |
| 24225 | + |
| 24226 | +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super, |
| 24227 | + FS_REQUIRES_DEV); |
| 24228 | +#endif |
| 24229 | + |
| 24230 | + |
| 24231 | +#ifdef CONFIG_YAFFS_YAFFS2 |
| 24232 | + |
| 24233 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 24234 | +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, |
| 24235 | + int silent) |
| 24236 | +{ |
| 24237 | + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; |
| 24238 | +} |
| 24239 | + |
| 24240 | +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) |
| 24241 | +static int yaffs2_read_super(struct file_system_type *fs, |
| 24242 | + int flags, const char *dev_name, void *data, |
| 24243 | + struct vfsmount *mnt) |
| 24244 | +{ |
| 24245 | + return get_sb_bdev(fs, flags, dev_name, data, |
| 24246 | + yaffs2_internal_read_super_mtd, mnt); |
| 24247 | +} |
| 24248 | +#else |
| 24249 | +static struct super_block *yaffs2_read_super(struct file_system_type *fs, |
| 24250 | + int flags, const char *dev_name, |
| 24251 | + void *data) |
| 24252 | +{ |
| 24253 | + |
| 24254 | + return get_sb_bdev(fs, flags, dev_name, data, |
| 24255 | + yaffs2_internal_read_super_mtd); |
| 24256 | +} |
| 24257 | +#endif |
| 24258 | + |
| 24259 | +static struct file_system_type yaffs2_fs_type = { |
| 24260 | + .owner = THIS_MODULE, |
| 24261 | + .name = "yaffs2", |
| 24262 | + .get_sb = yaffs2_read_super, |
| 24263 | + .kill_sb = kill_block_super, |
| 24264 | + .fs_flags = FS_REQUIRES_DEV, |
| 24265 | +}; |
| 24266 | +#else |
| 24267 | +static struct super_block *yaffs2_read_super(struct super_block *sb, |
| 24268 | + void *data, int silent) |
| 24269 | +{ |
| 24270 | + return yaffs_internal_read_super(2, sb, data, silent); |
| 24271 | +} |
| 24272 | + |
| 24273 | +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, |
| 24274 | + FS_REQUIRES_DEV); |
| 24275 | +#endif |
| 24276 | + |
| 24277 | +#endif /* CONFIG_YAFFS_YAFFS2 */ |
| 24278 | + |
| 24279 | +static struct proc_dir_entry *my_proc_entry; |
| 24280 | +static struct proc_dir_entry *debug_proc_entry; |
| 24281 | + |
| 24282 | +static char *yaffs_dump_dev_part0(char *buf, yaffs_dev_t * dev) |
| 24283 | +{ |
| 24284 | + buf += sprintf(buf, "start_block.......... %d\n", dev->param.start_block); |
| 24285 | + buf += sprintf(buf, "end_block............ %d\n", dev->param.end_block); |
| 24286 | + buf += sprintf(buf, "total_bytes_per_chunk %d\n", dev->param.total_bytes_per_chunk); |
| 24287 | + buf += sprintf(buf, "use_nand_ecc......... %d\n", dev->param.use_nand_ecc); |
| 24288 | + buf += sprintf(buf, "no_tags_ecc.......... %d\n", dev->param.no_tags_ecc); |
| 24289 | + buf += sprintf(buf, "is_yaffs2............ %d\n", dev->param.is_yaffs2); |
| 24290 | + buf += sprintf(buf, "inband_tags.......... %d\n", dev->param.inband_tags); |
| 24291 | + buf += sprintf(buf, "empty_lost_n_found... %d\n", dev->param.empty_lost_n_found); |
| 24292 | + buf += sprintf(buf, "disable_lazy_load.... %d\n", dev->param.disable_lazy_load); |
| 24293 | + buf += sprintf(buf, "refresh_period....... %d\n", dev->param.refresh_period); |
| 24294 | + buf += sprintf(buf, "n_caches............. %d\n", dev->param.n_caches); |
| 24295 | + buf += sprintf(buf, "n_reserved_blocks.... %d\n", dev->param.n_reserved_blocks); |
| 24296 | + buf += sprintf(buf, "always_check_erased.. %d\n", dev->param.always_check_erased); |
| 24297 | + |
| 24298 | + buf += sprintf(buf, "\n"); |
| 24299 | + |
| 24300 | + return buf; |
| 24301 | +} |
| 24302 | + |
| 24303 | + |
| 24304 | +static char *yaffs_dump_dev_part1(char *buf, yaffs_dev_t * dev) |
| 24305 | +{ |
| 24306 | + buf += sprintf(buf, "data_bytes_per_chunk. %d\n", dev->data_bytes_per_chunk); |
| 24307 | + buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits); |
| 24308 | + buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size); |
| 24309 | + buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks); |
| 24310 | + buf += sprintf(buf, "blocks_in_checkpt.... %d\n", dev->blocks_in_checkpt); |
| 24311 | + buf += sprintf(buf, "\n"); |
| 24312 | + buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes); |
| 24313 | + buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj); |
| 24314 | + buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks); |
| 24315 | + buf += sprintf(buf, "\n"); |
| 24316 | + buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes); |
| 24317 | + buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads); |
| 24318 | + buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures); |
| 24319 | + buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies); |
| 24320 | + buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs); |
| 24321 | + buf += sprintf(buf, "passive_gc_count..... %u\n", dev->passive_gc_count); |
| 24322 | + buf += sprintf(buf, "oldest_dirty_gc_count %u\n", dev->oldest_dirty_gc_count); |
| 24323 | + buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks); |
| 24324 | + buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs); |
| 24325 | + buf += sprintf(buf, "n_retired_writes..... %u\n", dev->n_retired_writes); |
| 24326 | + buf += sprintf(buf, "nRetireBlocks........ %u\n", dev->n_retired_blocks); |
| 24327 | + buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed); |
| 24328 | + buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed); |
| 24329 | + buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n", dev->n_tags_ecc_fixed); |
| 24330 | + buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n", dev->n_tags_ecc_unfixed); |
| 24331 | + buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits); |
| 24332 | + buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files); |
| 24333 | + buf += sprintf(buf, "n_unlinked_files..... %u\n", dev->n_unlinked_files); |
| 24334 | + buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count); |
| 24335 | + buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions); |
| 24336 | + |
| 24337 | + return buf; |
| 24338 | +} |
| 24339 | + |
| 24340 | +static int yaffs_proc_read(char *page, |
| 24341 | + char **start, |
| 24342 | + off_t offset, int count, int *eof, void *data) |
| 24343 | +{ |
| 24344 | + struct ylist_head *item; |
| 24345 | + char *buf = page; |
| 24346 | + int step = offset; |
| 24347 | + int n = 0; |
| 24348 | + |
| 24349 | + /* Get proc_file_read() to step 'offset' by one on each sucessive call. |
| 24350 | + * We use 'offset' (*ppos) to indicate where we are in dev_list. |
| 24351 | + * This also assumes the user has posted a read buffer large |
| 24352 | + * enough to hold the complete output; but that's life in /proc. |
| 24353 | + */ |
| 24354 | + |
| 24355 | + *(int *)start = 1; |
| 24356 | + |
| 24357 | + /* Print header first */ |
| 24358 | + if (step == 0) |
| 24359 | + buf += sprintf(buf, "Multi-version YAFFS built:" __DATE__ " " __TIME__"\n"); |
| 24360 | + else if (step == 1) |
| 24361 | + buf += sprintf(buf,"\n"); |
| 24362 | + else { |
| 24363 | + step-=2; |
| 24364 | + |
| 24365 | + down(&yaffs_context_lock); |
| 24366 | + |
| 24367 | + /* Locate and print the Nth entry. Order N-squared but N is small. */ |
| 24368 | + ylist_for_each(item, &yaffs_context_list) { |
| 24369 | + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList); |
| 24370 | + yaffs_dev_t *dev = dc->dev; |
| 24371 | + |
| 24372 | + if (n < (step & ~1)) { |
| 24373 | + n+=2; |
| 24374 | + continue; |
| 24375 | + } |
| 24376 | + if((step & 1)==0){ |
| 24377 | + buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name); |
| 24378 | + buf = yaffs_dump_dev_part0(buf, dev); |
| 24379 | + } else |
| 24380 | + buf = yaffs_dump_dev_part1(buf, dev); |
| 24381 | + |
| 24382 | + break; |
| 24383 | + } |
| 24384 | + up(&yaffs_context_lock); |
| 24385 | + } |
| 24386 | + |
| 24387 | + return buf - page < count ? buf - page : count; |
| 24388 | +} |
| 24389 | + |
| 24390 | +static int yaffs_stats_proc_read(char *page, |
| 24391 | + char **start, |
| 24392 | + off_t offset, int count, int *eof, void *data) |
| 24393 | +{ |
| 24394 | + struct ylist_head *item; |
| 24395 | + char *buf = page; |
| 24396 | + int n = 0; |
| 24397 | + |
| 24398 | + down(&yaffs_context_lock); |
| 24399 | + |
| 24400 | + /* Locate and print the Nth entry. Order N-squared but N is small. */ |
| 24401 | + ylist_for_each(item, &yaffs_context_list) { |
| 24402 | + struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList); |
| 24403 | + yaffs_dev_t *dev = dc->dev; |
| 24404 | + |
| 24405 | + int erasedChunks; |
| 24406 | + |
| 24407 | + erasedChunks = dev->n_erased_blocks * dev->param.chunks_per_block; |
| 24408 | + |
| 24409 | + buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n", |
| 24410 | + n, dev->n_free_chunks, erasedChunks, |
| 24411 | + dev->bg_gcs, dev->oldest_dirty_gc_count, |
| 24412 | + dev->n_obj, dev->n_tnodes); |
| 24413 | + } |
| 24414 | + up(&yaffs_context_lock); |
| 24415 | + |
| 24416 | + |
| 24417 | + return buf - page < count ? buf - page : count; |
| 24418 | +} |
| 24419 | + |
| 24420 | +/** |
| 24421 | + * Set the verbosity of the warnings and error messages. |
| 24422 | + * |
| 24423 | + * Note that the names can only be a..z or _ with the current code. |
| 24424 | + */ |
| 24425 | + |
| 24426 | +static struct { |
| 24427 | + char *mask_name; |
| 24428 | + unsigned mask_bitfield; |
| 24429 | +} mask_flags[] = { |
| 24430 | + {"allocate", YAFFS_TRACE_ALLOCATE}, |
| 24431 | + {"always", YAFFS_TRACE_ALWAYS}, |
| 24432 | + {"background", YAFFS_TRACE_BACKGROUND}, |
| 24433 | + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS}, |
| 24434 | + {"buffers", YAFFS_TRACE_BUFFERS}, |
| 24435 | + {"bug", YAFFS_TRACE_BUG}, |
| 24436 | + {"checkpt", YAFFS_TRACE_CHECKPOINT}, |
| 24437 | + {"deletion", YAFFS_TRACE_DELETION}, |
| 24438 | + {"erase", YAFFS_TRACE_ERASE}, |
| 24439 | + {"error", YAFFS_TRACE_ERROR}, |
| 24440 | + {"gc_detail", YAFFS_TRACE_GC_DETAIL}, |
| 24441 | + {"gc", YAFFS_TRACE_GC}, |
| 24442 | + {"lock", YAFFS_TRACE_LOCK}, |
| 24443 | + {"mtd", YAFFS_TRACE_MTD}, |
| 24444 | + {"nandaccess", YAFFS_TRACE_NANDACCESS}, |
| 24445 | + {"os", YAFFS_TRACE_OS}, |
| 24446 | + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG}, |
| 24447 | + {"scan", YAFFS_TRACE_SCAN}, |
| 24448 | + {"tracing", YAFFS_TRACE_TRACING}, |
| 24449 | + {"sync", YAFFS_TRACE_SYNC}, |
| 24450 | + {"write", YAFFS_TRACE_WRITE}, |
| 24451 | + |
| 24452 | + {"verify", YAFFS_TRACE_VERIFY}, |
| 24453 | + {"verify_nand", YAFFS_TRACE_VERIFY_NAND}, |
| 24454 | + {"verify_full", YAFFS_TRACE_VERIFY_FULL}, |
| 24455 | + {"verify_all", YAFFS_TRACE_VERIFY_ALL}, |
| 24456 | + |
| 24457 | + {"all", 0xffffffff}, |
| 24458 | + {"none", 0}, |
| 24459 | + {NULL, 0}, |
| 24460 | +}; |
| 24461 | + |
| 24462 | +#define MAX_MASK_NAME_LENGTH 40 |
| 24463 | +static int yaffs_proc_write_trace_options(struct file *file, const char *buf, |
| 24464 | + unsigned long count, void *data) |
| 24465 | +{ |
| 24466 | + unsigned rg = 0, mask_bitfield; |
| 24467 | + char *end; |
| 24468 | + char *mask_name; |
| 24469 | + const char *x; |
| 24470 | + char substring[MAX_MASK_NAME_LENGTH + 1]; |
| 24471 | + int i; |
| 24472 | + int done = 0; |
| 24473 | + int add, len = 0; |
| 24474 | + int pos = 0; |
| 24475 | + |
| 24476 | + rg = yaffs_trace_mask; |
| 24477 | + |
| 24478 | + while (!done && (pos < count)) { |
| 24479 | + done = 1; |
| 24480 | + while ((pos < count) && isspace(buf[pos])) |
| 24481 | + pos++; |
| 24482 | + |
| 24483 | + switch (buf[pos]) { |
| 24484 | + case '+': |
| 24485 | + case '-': |
| 24486 | + case '=': |
| 24487 | + add = buf[pos]; |
| 24488 | + pos++; |
| 24489 | + break; |
| 24490 | + |
| 24491 | + default: |
| 24492 | + add = ' '; |
| 24493 | + break; |
| 24494 | + } |
| 24495 | + mask_name = NULL; |
| 24496 | + |
| 24497 | + mask_bitfield = simple_strtoul(buf + pos, &end, 0); |
| 24498 | + |
| 24499 | + if (end > buf + pos) { |
| 24500 | + mask_name = "numeral"; |
| 24501 | + len = end - (buf + pos); |
| 24502 | + pos += len; |
| 24503 | + done = 0; |
| 24504 | + } else { |
| 24505 | + for (x = buf + pos, i = 0; |
| 24506 | + (*x == '_' || (*x >= 'a' && *x <= 'z')) && |
| 24507 | + i < MAX_MASK_NAME_LENGTH; x++, i++, pos++) |
| 24508 | + substring[i] = *x; |
| 24509 | + substring[i] = '\0'; |
| 24510 | + |
| 24511 | + for (i = 0; mask_flags[i].mask_name != NULL; i++) { |
| 24512 | + if (strcmp(substring, mask_flags[i].mask_name) == 0) { |
| 24513 | + mask_name = mask_flags[i].mask_name; |
| 24514 | + mask_bitfield = mask_flags[i].mask_bitfield; |
| 24515 | + done = 0; |
| 24516 | + break; |
| 24517 | + } |
| 24518 | + } |
| 24519 | + } |
| 24520 | + |
| 24521 | + if (mask_name != NULL) { |
| 24522 | + done = 0; |
| 24523 | + switch (add) { |
| 24524 | + case '-': |
| 24525 | + rg &= ~mask_bitfield; |
| 24526 | + break; |
| 24527 | + case '+': |
| 24528 | + rg |= mask_bitfield; |
| 24529 | + break; |
| 24530 | + case '=': |
| 24531 | + rg = mask_bitfield; |
| 24532 | + break; |
| 24533 | + default: |
| 24534 | + rg |= mask_bitfield; |
| 24535 | + break; |
| 24536 | + } |
| 24537 | + } |
| 24538 | + } |
| 24539 | + |
| 24540 | + yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS; |
| 24541 | + |
| 24542 | + printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask); |
| 24543 | + |
| 24544 | + if (rg & YAFFS_TRACE_ALWAYS) { |
| 24545 | + for (i = 0; mask_flags[i].mask_name != NULL; i++) { |
| 24546 | + char flag; |
| 24547 | + flag = ((rg & mask_flags[i].mask_bitfield) == |
| 24548 | + mask_flags[i].mask_bitfield) ? '+' : '-'; |
| 24549 | + printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name); |
| 24550 | + } |
| 24551 | + } |
| 24552 | + |
| 24553 | + return count; |
| 24554 | +} |
| 24555 | + |
| 24556 | + |
| 24557 | +static int yaffs_proc_write(struct file *file, const char *buf, |
| 24558 | + unsigned long count, void *data) |
| 24559 | +{ |
| 24560 | + return yaffs_proc_write_trace_options(file, buf, count, data); |
| 24561 | +} |
| 24562 | + |
| 24563 | +/* Stuff to handle installation of file systems */ |
| 24564 | +struct file_system_to_install { |
| 24565 | + struct file_system_type *fst; |
| 24566 | + int installed; |
| 24567 | +}; |
| 24568 | + |
| 24569 | +static struct file_system_to_install fs_to_install[] = { |
| 24570 | + {&yaffs_fs_type, 0}, |
| 24571 | + {&yaffs2_fs_type, 0}, |
| 24572 | + {NULL, 0} |
| 24573 | +}; |
| 24574 | + |
| 24575 | +static int __init init_yaffs_fs(void) |
| 24576 | +{ |
| 24577 | + int error = 0; |
| 24578 | + struct file_system_to_install *fsinst; |
| 24579 | + |
| 24580 | + T(YAFFS_TRACE_ALWAYS, |
| 24581 | + (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n"))); |
| 24582 | + |
| 24583 | +#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED |
| 24584 | + T(YAFFS_TRACE_ALWAYS, |
| 24585 | + (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n"))); |
| 24586 | +#endif |
| 24587 | + |
| 24588 | + |
| 24589 | + |
| 24590 | + |
| 24591 | + init_MUTEX(&yaffs_context_lock); |
| 24592 | + |
| 24593 | + /* Install the proc_fs entries */ |
| 24594 | + my_proc_entry = create_proc_entry("yaffs", |
| 24595 | + S_IRUGO | S_IFREG, |
| 24596 | + YPROC_ROOT); |
| 24597 | + |
| 24598 | + if (my_proc_entry) { |
| 24599 | + my_proc_entry->write_proc = yaffs_proc_write; |
| 24600 | + my_proc_entry->read_proc = yaffs_proc_read; |
| 24601 | + my_proc_entry->data = NULL; |
| 24602 | + } else |
| 24603 | + return -ENOMEM; |
| 24604 | + |
| 24605 | + debug_proc_entry = create_proc_entry("yaffs_stats", |
| 24606 | + S_IRUGO | S_IFREG, |
| 24607 | + YPROC_ROOT); |
| 24608 | + |
| 24609 | + if (debug_proc_entry) { |
| 24610 | + debug_proc_entry->write_proc = NULL; |
| 24611 | + debug_proc_entry->read_proc = yaffs_stats_proc_read; |
| 24612 | + debug_proc_entry->data = NULL; |
| 24613 | + } else |
| 24614 | + return -ENOMEM; |
| 24615 | + |
| 24616 | + /* Now add the file system entries */ |
| 24617 | + |
| 24618 | + fsinst = fs_to_install; |
| 24619 | + |
| 24620 | + while (fsinst->fst && !error) { |
| 24621 | + error = register_filesystem(fsinst->fst); |
| 24622 | + if (!error) |
| 24623 | + fsinst->installed = 1; |
| 24624 | + fsinst++; |
| 24625 | + } |
| 24626 | + |
| 24627 | + /* Any errors? uninstall */ |
| 24628 | + if (error) { |
| 24629 | + fsinst = fs_to_install; |
| 24630 | + |
| 24631 | + while (fsinst->fst) { |
| 24632 | + if (fsinst->installed) { |
| 24633 | + unregister_filesystem(fsinst->fst); |
| 24634 | + fsinst->installed = 0; |
| 24635 | + } |
| 24636 | + fsinst++; |
| 24637 | + } |
| 24638 | + } |
| 24639 | + |
| 24640 | + return error; |
| 24641 | +} |
| 24642 | + |
| 24643 | +static void __exit exit_yaffs_fs(void) |
| 24644 | +{ |
| 24645 | + |
| 24646 | + struct file_system_to_install *fsinst; |
| 24647 | + |
| 24648 | + T(YAFFS_TRACE_ALWAYS, |
| 24649 | + (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n"))); |
| 24650 | + |
| 24651 | + remove_proc_entry("yaffs", YPROC_ROOT); |
| 24652 | + remove_proc_entry("yaffs_stats", YPROC_ROOT); |
| 24653 | + |
| 24654 | + fsinst = fs_to_install; |
| 24655 | + |
| 24656 | + while (fsinst->fst) { |
| 24657 | + if (fsinst->installed) { |
| 24658 | + unregister_filesystem(fsinst->fst); |
| 24659 | + fsinst->installed = 0; |
| 24660 | + } |
| 24661 | + fsinst++; |
| 24662 | + } |
| 24663 | +} |
| 24664 | + |
| 24665 | +module_init(init_yaffs_fs) |
| 24666 | +module_exit(exit_yaffs_fs) |
| 24667 | + |
| 24668 | +MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system"); |
| 24669 | +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010"); |
| 24670 | +MODULE_LICENSE("GPL"); |
| 24671 | --- /dev/null |
| 24672 | +++ b/fs/yaffs2/yaffs_yaffs1.c |
| 24673 | @@ -0,0 +1,465 @@ |
| 24674 | +/* |
| 24675 | + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 24676 | + * |
| 24677 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 24678 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 24679 | + * |
| 24680 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 24681 | + * |
| 24682 | + * This program is free software; you can redistribute it and/or modify |
| 24683 | + * it under the terms of the GNU General Public License version 2 as |
| 24684 | + * published by the Free Software Foundation. |
| 24685 | + */ |
| 24686 | +#include "yaffs_yaffs1.h" |
| 24687 | +#include "yportenv.h" |
| 24688 | +#include "yaffs_trace.h" |
| 24689 | +#include "yaffs_bitmap.h" |
| 24690 | +#include "yaffs_getblockinfo.h" |
| 24691 | +#include "yaffs_nand.h" |
| 24692 | + |
| 24693 | + |
| 24694 | +int yaffs1_scan(yaffs_dev_t *dev) |
| 24695 | +{ |
| 24696 | + yaffs_ext_tags tags; |
| 24697 | + int blk; |
| 24698 | + int blockIterator; |
| 24699 | + int startIterator; |
| 24700 | + int endIterator; |
| 24701 | + int result; |
| 24702 | + |
| 24703 | + int chunk; |
| 24704 | + int c; |
| 24705 | + int deleted; |
| 24706 | + yaffs_block_state_t state; |
| 24707 | + yaffs_obj_t *hard_list = NULL; |
| 24708 | + yaffs_block_info_t *bi; |
| 24709 | + __u32 seq_number; |
| 24710 | + yaffs_obj_header *oh; |
| 24711 | + yaffs_obj_t *in; |
| 24712 | + yaffs_obj_t *parent; |
| 24713 | + |
| 24714 | + int alloc_failed = 0; |
| 24715 | + |
| 24716 | + struct yaffs_shadow_fixer_s *shadowFixerList = NULL; |
| 24717 | + |
| 24718 | + |
| 24719 | + __u8 *chunkData; |
| 24720 | + |
| 24721 | + |
| 24722 | + |
| 24723 | + T(YAFFS_TRACE_SCAN, |
| 24724 | + (TSTR("yaffs1_scan starts intstartblk %d intendblk %d..." TENDSTR), |
| 24725 | + dev->internal_start_block, dev->internal_end_block)); |
| 24726 | + |
| 24727 | + chunkData = yaffs_get_temp_buffer(dev, __LINE__); |
| 24728 | + |
| 24729 | + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; |
| 24730 | + |
| 24731 | + /* Scan all the blocks to determine their state */ |
| 24732 | + bi = dev->block_info; |
| 24733 | + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) { |
| 24734 | + yaffs_clear_chunk_bits(dev, blk); |
| 24735 | + bi->pages_in_use = 0; |
| 24736 | + bi->soft_del_pages = 0; |
| 24737 | + |
| 24738 | + yaffs_query_init_block_state(dev, blk, &state, &seq_number); |
| 24739 | + |
| 24740 | + bi->block_state = state; |
| 24741 | + bi->seq_number = seq_number; |
| 24742 | + |
| 24743 | + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) |
| 24744 | + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; |
| 24745 | + |
| 24746 | + T(YAFFS_TRACE_SCAN_DEBUG, |
| 24747 | + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, |
| 24748 | + state, seq_number)); |
| 24749 | + |
| 24750 | + if (state == YAFFS_BLOCK_STATE_DEAD) { |
| 24751 | + T(YAFFS_TRACE_BAD_BLOCKS, |
| 24752 | + (TSTR("block %d is bad" TENDSTR), blk)); |
| 24753 | + } else if (state == YAFFS_BLOCK_STATE_EMPTY) { |
| 24754 | + T(YAFFS_TRACE_SCAN_DEBUG, |
| 24755 | + (TSTR("Block empty " TENDSTR))); |
| 24756 | + dev->n_erased_blocks++; |
| 24757 | + dev->n_free_chunks += dev->param.chunks_per_block; |
| 24758 | + } |
| 24759 | + bi++; |
| 24760 | + } |
| 24761 | + |
| 24762 | + startIterator = dev->internal_start_block; |
| 24763 | + endIterator = dev->internal_end_block; |
| 24764 | + |
| 24765 | + /* For each block.... */ |
| 24766 | + for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; |
| 24767 | + blockIterator++) { |
| 24768 | + |
| 24769 | + YYIELD(); |
| 24770 | + |
| 24771 | + YYIELD(); |
| 24772 | + |
| 24773 | + blk = blockIterator; |
| 24774 | + |
| 24775 | + bi = yaffs_get_block_info(dev, blk); |
| 24776 | + state = bi->block_state; |
| 24777 | + |
| 24778 | + deleted = 0; |
| 24779 | + |
| 24780 | + /* For each chunk in each block that needs scanning....*/ |
| 24781 | + for (c = 0; !alloc_failed && c < dev->param.chunks_per_block && |
| 24782 | + state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { |
| 24783 | + /* Read the tags and decide what to do */ |
| 24784 | + chunk = blk * dev->param.chunks_per_block + c; |
| 24785 | + |
| 24786 | + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, |
| 24787 | + &tags); |
| 24788 | + |
| 24789 | + /* Let's have a good look at this chunk... */ |
| 24790 | + |
| 24791 | + if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || tags.is_deleted) { |
| 24792 | + /* YAFFS1 only... |
| 24793 | + * A deleted chunk |
| 24794 | + */ |
| 24795 | + deleted++; |
| 24796 | + dev->n_free_chunks++; |
| 24797 | + /*T((" %d %d deleted\n",blk,c)); */ |
| 24798 | + } else if (!tags.chunk_used) { |
| 24799 | + /* An unassigned chunk in the block |
| 24800 | + * This means that either the block is empty or |
| 24801 | + * this is the one being allocated from |
| 24802 | + */ |
| 24803 | + |
| 24804 | + if (c == 0) { |
| 24805 | + /* We're looking at the first chunk in the block so the block is unused */ |
| 24806 | + state = YAFFS_BLOCK_STATE_EMPTY; |
| 24807 | + dev->n_erased_blocks++; |
| 24808 | + } else { |
| 24809 | + /* this is the block being allocated from */ |
| 24810 | + T(YAFFS_TRACE_SCAN, |
| 24811 | + (TSTR |
| 24812 | + (" Allocating from %d %d" TENDSTR), |
| 24813 | + blk, c)); |
| 24814 | + state = YAFFS_BLOCK_STATE_ALLOCATING; |
| 24815 | + dev->alloc_block = blk; |
| 24816 | + dev->alloc_page = c; |
| 24817 | + dev->alloc_block_finder = blk; |
| 24818 | + /* Set block finder here to encourage the allocator to go forth from here. */ |
| 24819 | + |
| 24820 | + } |
| 24821 | + |
| 24822 | + dev->n_free_chunks += (dev->param.chunks_per_block - c); |
| 24823 | + } else if (tags.chunk_id > 0) { |
| 24824 | + /* chunk_id > 0 so it is a data chunk... */ |
| 24825 | + unsigned int endpos; |
| 24826 | + |
| 24827 | + yaffs_set_chunk_bit(dev, blk, c); |
| 24828 | + bi->pages_in_use++; |
| 24829 | + |
| 24830 | + in = yaffs_find_or_create_by_number(dev, |
| 24831 | + tags. |
| 24832 | + obj_id, |
| 24833 | + YAFFS_OBJECT_TYPE_FILE); |
| 24834 | + /* PutChunkIntoFile checks for a clash (two data chunks with |
| 24835 | + * the same chunk_id). |
| 24836 | + */ |
| 24837 | + |
| 24838 | + if (!in) |
| 24839 | + alloc_failed = 1; |
| 24840 | + |
| 24841 | + if (in) { |
| 24842 | + if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, 1)) |
| 24843 | + alloc_failed = 1; |
| 24844 | + } |
| 24845 | + |
| 24846 | + endpos = |
| 24847 | + (tags.chunk_id - 1) * dev->data_bytes_per_chunk + |
| 24848 | + tags.n_bytes; |
| 24849 | + if (in && |
| 24850 | + in->variant_type == YAFFS_OBJECT_TYPE_FILE |
| 24851 | + && in->variant.file_variant.scanned_size < |
| 24852 | + endpos) { |
| 24853 | + in->variant.file_variant. |
| 24854 | + scanned_size = endpos; |
| 24855 | + if (!dev->param.use_header_file_size) { |
| 24856 | + in->variant.file_variant. |
| 24857 | + file_size = |
| 24858 | + in->variant.file_variant. |
| 24859 | + scanned_size; |
| 24860 | + } |
| 24861 | + |
| 24862 | + } |
| 24863 | + /* T((" %d %d data %d %d\n",blk,c,tags.obj_id,tags.chunk_id)); */ |
| 24864 | + } else { |
| 24865 | + /* chunk_id == 0, so it is an ObjectHeader. |
| 24866 | + * Thus, we read in the object header and make the object |
| 24867 | + */ |
| 24868 | + yaffs_set_chunk_bit(dev, blk, c); |
| 24869 | + bi->pages_in_use++; |
| 24870 | + |
| 24871 | + result = yaffs_rd_chunk_tags_nand(dev, chunk, |
| 24872 | + chunkData, |
| 24873 | + NULL); |
| 24874 | + |
| 24875 | + oh = (yaffs_obj_header *) chunkData; |
| 24876 | + |
| 24877 | + in = yaffs_find_by_number(dev, |
| 24878 | + tags.obj_id); |
| 24879 | + if (in && in->variant_type != oh->type) { |
| 24880 | + /* This should not happen, but somehow |
| 24881 | + * Wev'e ended up with an obj_id that has been reused but not yet |
| 24882 | + * deleted, and worse still it has changed type. Delete the old object. |
| 24883 | + */ |
| 24884 | + |
| 24885 | + yaffs_del_obj(in); |
| 24886 | + |
| 24887 | + in = 0; |
| 24888 | + } |
| 24889 | + |
| 24890 | + in = yaffs_find_or_create_by_number(dev, |
| 24891 | + tags. |
| 24892 | + obj_id, |
| 24893 | + oh->type); |
| 24894 | + |
| 24895 | + if (!in) |
| 24896 | + alloc_failed = 1; |
| 24897 | + |
| 24898 | + if (in && oh->shadows_obj > 0) { |
| 24899 | + |
| 24900 | + struct yaffs_shadow_fixer_s *fixer; |
| 24901 | + fixer = YMALLOC(sizeof(struct yaffs_shadow_fixer_s)); |
| 24902 | + if (fixer) { |
| 24903 | + fixer->next = shadowFixerList; |
| 24904 | + shadowFixerList = fixer; |
| 24905 | + fixer->obj_id = tags.obj_id; |
| 24906 | + fixer->shadowed_id = oh->shadows_obj; |
| 24907 | + T(YAFFS_TRACE_SCAN, |
| 24908 | + (TSTR |
| 24909 | + (" Shadow fixer: %d shadows %d" TENDSTR), |
| 24910 | + fixer->obj_id, fixer->shadowed_id)); |
| 24911 | + |
| 24912 | + } |
| 24913 | + |
| 24914 | + } |
| 24915 | + |
| 24916 | + if (in && in->valid) { |
| 24917 | + /* We have already filled this one. We have a duplicate and need to resolve it. */ |
| 24918 | + |
| 24919 | + unsigned existingSerial = in->serial; |
| 24920 | + unsigned newSerial = tags.serial_number; |
| 24921 | + |
| 24922 | + if (((existingSerial + 1) & 3) == newSerial) { |
| 24923 | + /* Use new one - destroy the exisiting one */ |
| 24924 | + yaffs_chunk_del(dev, |
| 24925 | + in->hdr_chunk, |
| 24926 | + 1, __LINE__); |
| 24927 | + in->valid = 0; |
| 24928 | + } else { |
| 24929 | + /* Use existing - destroy this one. */ |
| 24930 | + yaffs_chunk_del(dev, chunk, 1, |
| 24931 | + __LINE__); |
| 24932 | + } |
| 24933 | + } |
| 24934 | + |
| 24935 | + if (in && !in->valid && |
| 24936 | + (tags.obj_id == YAFFS_OBJECTID_ROOT || |
| 24937 | + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) { |
| 24938 | + /* We only load some info, don't fiddle with directory structure */ |
| 24939 | + in->valid = 1; |
| 24940 | + in->variant_type = oh->type; |
| 24941 | + |
| 24942 | + in->yst_mode = oh->yst_mode; |
| 24943 | +#ifdef CONFIG_YAFFS_WINCE |
| 24944 | + in->win_atime[0] = oh->win_atime[0]; |
| 24945 | + in->win_ctime[0] = oh->win_ctime[0]; |
| 24946 | + in->win_mtime[0] = oh->win_mtime[0]; |
| 24947 | + in->win_atime[1] = oh->win_atime[1]; |
| 24948 | + in->win_ctime[1] = oh->win_ctime[1]; |
| 24949 | + in->win_mtime[1] = oh->win_mtime[1]; |
| 24950 | +#else |
| 24951 | + in->yst_uid = oh->yst_uid; |
| 24952 | + in->yst_gid = oh->yst_gid; |
| 24953 | + in->yst_atime = oh->yst_atime; |
| 24954 | + in->yst_mtime = oh->yst_mtime; |
| 24955 | + in->yst_ctime = oh->yst_ctime; |
| 24956 | + in->yst_rdev = oh->yst_rdev; |
| 24957 | +#endif |
| 24958 | + in->hdr_chunk = chunk; |
| 24959 | + in->serial = tags.serial_number; |
| 24960 | + |
| 24961 | + } else if (in && !in->valid) { |
| 24962 | + /* we need to load this info */ |
| 24963 | + |
| 24964 | + in->valid = 1; |
| 24965 | + in->variant_type = oh->type; |
| 24966 | + |
| 24967 | + in->yst_mode = oh->yst_mode; |
| 24968 | +#ifdef CONFIG_YAFFS_WINCE |
| 24969 | + in->win_atime[0] = oh->win_atime[0]; |
| 24970 | + in->win_ctime[0] = oh->win_ctime[0]; |
| 24971 | + in->win_mtime[0] = oh->win_mtime[0]; |
| 24972 | + in->win_atime[1] = oh->win_atime[1]; |
| 24973 | + in->win_ctime[1] = oh->win_ctime[1]; |
| 24974 | + in->win_mtime[1] = oh->win_mtime[1]; |
| 24975 | +#else |
| 24976 | + in->yst_uid = oh->yst_uid; |
| 24977 | + in->yst_gid = oh->yst_gid; |
| 24978 | + in->yst_atime = oh->yst_atime; |
| 24979 | + in->yst_mtime = oh->yst_mtime; |
| 24980 | + in->yst_ctime = oh->yst_ctime; |
| 24981 | + in->yst_rdev = oh->yst_rdev; |
| 24982 | +#endif |
| 24983 | + in->hdr_chunk = chunk; |
| 24984 | + in->serial = tags.serial_number; |
| 24985 | + |
| 24986 | + yaffs_set_obj_name_from_oh(in, oh); |
| 24987 | + in->dirty = 0; |
| 24988 | + |
| 24989 | + /* directory stuff... |
| 24990 | + * hook up to parent |
| 24991 | + */ |
| 24992 | + |
| 24993 | + parent = |
| 24994 | + yaffs_find_or_create_by_number |
| 24995 | + (dev, oh->parent_obj_id, |
| 24996 | + YAFFS_OBJECT_TYPE_DIRECTORY); |
| 24997 | + if (!parent) |
| 24998 | + alloc_failed = 1; |
| 24999 | + if (parent && parent->variant_type == |
| 25000 | + YAFFS_OBJECT_TYPE_UNKNOWN) { |
| 25001 | + /* Set up as a directory */ |
| 25002 | + parent->variant_type = |
| 25003 | + YAFFS_OBJECT_TYPE_DIRECTORY; |
| 25004 | + YINIT_LIST_HEAD(&parent->variant. |
| 25005 | + dir_variant. |
| 25006 | + children); |
| 25007 | + } else if (!parent || parent->variant_type != |
| 25008 | + YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 25009 | + /* Hoosterman, another problem.... |
| 25010 | + * We're trying to use a non-directory as a directory |
| 25011 | + */ |
| 25012 | + |
| 25013 | + T(YAFFS_TRACE_ERROR, |
| 25014 | + (TSTR |
| 25015 | + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." |
| 25016 | + TENDSTR))); |
| 25017 | + parent = dev->lost_n_found; |
| 25018 | + } |
| 25019 | + |
| 25020 | + yaffs_add_obj_to_dir(parent, in); |
| 25021 | + |
| 25022 | + if (0 && (parent == dev->del_dir || |
| 25023 | + parent == dev->unlinked_dir)) { |
| 25024 | + in->deleted = 1; /* If it is unlinked at start up then it wants deleting */ |
| 25025 | + dev->n_deleted_files++; |
| 25026 | + } |
| 25027 | + /* Note re hardlinks. |
| 25028 | + * Since we might scan a hardlink before its equivalent object is scanned |
| 25029 | + * we put them all in a list. |
| 25030 | + * After scanning is complete, we should have all the objects, so we run through this |
| 25031 | + * list and fix up all the chains. |
| 25032 | + */ |
| 25033 | + |
| 25034 | + switch (in->variant_type) { |
| 25035 | + case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 25036 | + /* Todo got a problem */ |
| 25037 | + break; |
| 25038 | + case YAFFS_OBJECT_TYPE_FILE: |
| 25039 | + if (dev->param.use_header_file_size) |
| 25040 | + |
| 25041 | + in->variant.file_variant. |
| 25042 | + file_size = |
| 25043 | + oh->file_size; |
| 25044 | + |
| 25045 | + break; |
| 25046 | + case YAFFS_OBJECT_TYPE_HARDLINK: |
| 25047 | + in->variant.hardlink_variant. |
| 25048 | + equiv_id = |
| 25049 | + oh->equiv_id; |
| 25050 | + in->hard_links.next = |
| 25051 | + (struct ylist_head *) |
| 25052 | + hard_list; |
| 25053 | + hard_list = in; |
| 25054 | + break; |
| 25055 | + case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 25056 | + /* Do nothing */ |
| 25057 | + break; |
| 25058 | + case YAFFS_OBJECT_TYPE_SPECIAL: |
| 25059 | + /* Do nothing */ |
| 25060 | + break; |
| 25061 | + case YAFFS_OBJECT_TYPE_SYMLINK: |
| 25062 | + in->variant.symlink_variant.alias = |
| 25063 | + yaffs_clone_str(oh->alias); |
| 25064 | + if (!in->variant.symlink_variant.alias) |
| 25065 | + alloc_failed = 1; |
| 25066 | + break; |
| 25067 | + } |
| 25068 | + |
| 25069 | + } |
| 25070 | + } |
| 25071 | + } |
| 25072 | + |
| 25073 | + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { |
| 25074 | + /* If we got this far while scanning, then the block is fully allocated.*/ |
| 25075 | + state = YAFFS_BLOCK_STATE_FULL; |
| 25076 | + } |
| 25077 | + |
| 25078 | + if (state == YAFFS_BLOCK_STATE_ALLOCATING) { |
| 25079 | + /* If the block was partially allocated then treat it as fully allocated.*/ |
| 25080 | + state = YAFFS_BLOCK_STATE_FULL; |
| 25081 | + dev->alloc_block = -1; |
| 25082 | + } |
| 25083 | + |
| 25084 | + bi->block_state = state; |
| 25085 | + |
| 25086 | + /* Now let's see if it was dirty */ |
| 25087 | + if (bi->pages_in_use == 0 && |
| 25088 | + !bi->has_shrink_hdr && |
| 25089 | + bi->block_state == YAFFS_BLOCK_STATE_FULL) { |
| 25090 | + yaffs_block_became_dirty(dev, blk); |
| 25091 | + } |
| 25092 | + |
| 25093 | + } |
| 25094 | + |
| 25095 | + |
| 25096 | + /* Ok, we've done all the scanning. |
| 25097 | + * Fix up the hard link chains. |
| 25098 | + * We should now have scanned all the objects, now it's time to add these |
| 25099 | + * hardlinks. |
| 25100 | + */ |
| 25101 | + |
| 25102 | + yaffs_link_fixup(dev, hard_list); |
| 25103 | + |
| 25104 | + /* Fix up any shadowed objects */ |
| 25105 | + { |
| 25106 | + struct yaffs_shadow_fixer_s *fixer; |
| 25107 | + yaffs_obj_t *obj; |
| 25108 | + |
| 25109 | + while (shadowFixerList) { |
| 25110 | + fixer = shadowFixerList; |
| 25111 | + shadowFixerList = fixer->next; |
| 25112 | + /* Complete the rename transaction by deleting the shadowed object |
| 25113 | + * then setting the object header to unshadowed. |
| 25114 | + */ |
| 25115 | + obj = yaffs_find_by_number(dev, fixer->shadowed_id); |
| 25116 | + if (obj) |
| 25117 | + yaffs_del_obj(obj); |
| 25118 | + |
| 25119 | + obj = yaffs_find_by_number(dev, fixer->obj_id); |
| 25120 | + |
| 25121 | + if (obj) |
| 25122 | + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); |
| 25123 | + |
| 25124 | + YFREE(fixer); |
| 25125 | + } |
| 25126 | + } |
| 25127 | + |
| 25128 | + yaffs_release_temp_buffer(dev, chunkData, __LINE__); |
| 25129 | + |
| 25130 | + if (alloc_failed) |
| 25131 | + return YAFFS_FAIL; |
| 25132 | + |
| 25133 | + T(YAFFS_TRACE_SCAN, (TSTR("yaffs1_scan ends" TENDSTR))); |
| 25134 | + |
| 25135 | + |
| 25136 | + return YAFFS_OK; |
| 25137 | +} |
| 25138 | + |
| 25139 | --- /dev/null |
| 25140 | +++ b/fs/yaffs2/yaffs_yaffs1.h |
| 25141 | @@ -0,0 +1,22 @@ |
| 25142 | +/* |
| 25143 | + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 25144 | + * |
| 25145 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 25146 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 25147 | + * |
| 25148 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 25149 | + * |
| 25150 | + * This program is free software; you can redistribute it and/or modify |
| 25151 | + * it under the terms of the GNU Lesser General Public License version 2.1 as |
| 25152 | + * published by the Free Software Foundation. |
| 25153 | + * |
| 25154 | + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. |
| 25155 | + */ |
| 25156 | + |
| 25157 | +#ifndef __YAFFS_YAFFS1_H__ |
| 25158 | +#define __YAFFS_YAFFS1_H__ |
| 25159 | + |
| 25160 | +#include "yaffs_guts.h" |
| 25161 | +int yaffs1_scan(yaffs_dev_t *dev); |
| 25162 | + |
| 25163 | +#endif |
| 25164 | --- /dev/null |
| 25165 | +++ b/fs/yaffs2/yaffs_yaffs2.c |
| 25166 | @@ -0,0 +1,1540 @@ |
| 25167 | +/* |
| 25168 | + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 25169 | + * |
| 25170 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 25171 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 25172 | + * |
| 25173 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 25174 | + * |
| 25175 | + * This program is free software; you can redistribute it and/or modify |
| 25176 | + * it under the terms of the GNU General Public License version 2 as |
| 25177 | + * published by the Free Software Foundation. |
| 25178 | + */ |
| 25179 | + |
| 25180 | + |
| 25181 | +#include "yaffs_guts.h" |
| 25182 | +#include "yaffs_trace.h" |
| 25183 | +#include "yaffs_yaffs2.h" |
| 25184 | +#include "yaffs_checkptrw.h" |
| 25185 | +#include "yaffs_bitmap.h" |
| 25186 | +#include "yaffs_qsort.h" |
| 25187 | +#include "yaffs_nand.h" |
| 25188 | +#include "yaffs_getblockinfo.h" |
| 25189 | +#include "yaffs_verify.h" |
| 25190 | + |
| 25191 | +/* |
| 25192 | + * Checkpoints are really no benefit on very small partitions. |
| 25193 | + * |
| 25194 | + * To save space on small partitions don't bother with checkpoints unless |
| 25195 | + * the partition is at least this big. |
| 25196 | + */ |
| 25197 | +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60 |
| 25198 | + |
| 25199 | +#define YAFFS_SMALL_HOLE_THRESHOLD 4 |
| 25200 | + |
| 25201 | + |
| 25202 | +/* |
| 25203 | + * Oldest Dirty Sequence Number handling. |
| 25204 | + */ |
| 25205 | + |
| 25206 | +/* yaffs_calc_oldest_dirty_seq() |
| 25207 | + * yaffs2_find_oldest_dirty_seq() |
| 25208 | + * Calculate the oldest dirty sequence number if we don't know it. |
| 25209 | + */ |
| 25210 | +void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev) |
| 25211 | +{ |
| 25212 | + int i; |
| 25213 | + unsigned seq; |
| 25214 | + unsigned block_no = 0; |
| 25215 | + yaffs_block_info_t *b; |
| 25216 | + |
| 25217 | + if(!dev->param.is_yaffs2) |
| 25218 | + return; |
| 25219 | + |
| 25220 | + /* Find the oldest dirty sequence number. */ |
| 25221 | + seq = dev->seq_number + 1; |
| 25222 | + b = dev->block_info; |
| 25223 | + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { |
| 25224 | + if (b->block_state == YAFFS_BLOCK_STATE_FULL && |
| 25225 | + (b->pages_in_use - b->soft_del_pages) < dev->param.chunks_per_block && |
| 25226 | + b->seq_number < seq) { |
| 25227 | + seq = b->seq_number; |
| 25228 | + block_no = i; |
| 25229 | + } |
| 25230 | + b++; |
| 25231 | + } |
| 25232 | + |
| 25233 | + if(block_no){ |
| 25234 | + dev->oldest_dirty_seq = seq; |
| 25235 | + dev->oldest_dirty_block = block_no; |
| 25236 | + } |
| 25237 | + |
| 25238 | +} |
| 25239 | + |
| 25240 | + |
| 25241 | +void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev) |
| 25242 | +{ |
| 25243 | + if(!dev->param.is_yaffs2) |
| 25244 | + return; |
| 25245 | + |
| 25246 | + if(!dev->oldest_dirty_seq) |
| 25247 | + yaffs_calc_oldest_dirty_seq(dev); |
| 25248 | +} |
| 25249 | + |
| 25250 | +/* |
| 25251 | + * yaffs_clear_oldest_dirty_seq() |
| 25252 | + * Called when a block is erased or marked bad. (ie. when its seq_number |
| 25253 | + * becomes invalid). If the value matches the oldest then we clear |
| 25254 | + * dev->oldest_dirty_seq to force its recomputation. |
| 25255 | + */ |
| 25256 | +void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi) |
| 25257 | +{ |
| 25258 | + |
| 25259 | + if(!dev->param.is_yaffs2) |
| 25260 | + return; |
| 25261 | + |
| 25262 | + if(!bi || bi->seq_number == dev->oldest_dirty_seq){ |
| 25263 | + dev->oldest_dirty_seq = 0; |
| 25264 | + dev->oldest_dirty_block = 0; |
| 25265 | + } |
| 25266 | +} |
| 25267 | + |
| 25268 | +/* |
| 25269 | + * yaffs2_update_oldest_dirty_seq() |
| 25270 | + * Update the oldest dirty sequence number whenever we dirty a block. |
| 25271 | + * Only do this if the oldest_dirty_seq is actually being tracked. |
| 25272 | + */ |
| 25273 | +void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi) |
| 25274 | +{ |
| 25275 | + if(!dev->param.is_yaffs2) |
| 25276 | + return; |
| 25277 | + |
| 25278 | + if(dev->oldest_dirty_seq){ |
| 25279 | + if(dev->oldest_dirty_seq > bi->seq_number){ |
| 25280 | + dev->oldest_dirty_seq = bi->seq_number; |
| 25281 | + dev->oldest_dirty_block = block_no; |
| 25282 | + } |
| 25283 | + } |
| 25284 | +} |
| 25285 | + |
| 25286 | +int yaffs_block_ok_for_gc(yaffs_dev_t *dev, |
| 25287 | + yaffs_block_info_t *bi) |
| 25288 | +{ |
| 25289 | + |
| 25290 | + if (!dev->param.is_yaffs2) |
| 25291 | + return 1; /* disqualification only applies to yaffs2. */ |
| 25292 | + |
| 25293 | + if (!bi->has_shrink_hdr) |
| 25294 | + return 1; /* can gc */ |
| 25295 | + |
| 25296 | + yaffs2_find_oldest_dirty_seq(dev); |
| 25297 | + |
| 25298 | + /* Can't do gc of this block if there are any blocks older than this one that have |
| 25299 | + * discarded pages. |
| 25300 | + */ |
| 25301 | + return (bi->seq_number <= dev->oldest_dirty_seq); |
| 25302 | +} |
| 25303 | + |
| 25304 | +/* |
| 25305 | + * yaffs2_find_refresh_block() |
| 25306 | + * periodically finds the oldest full block by sequence number for refreshing. |
| 25307 | + * Only for yaffs2. |
| 25308 | + */ |
| 25309 | +__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev) |
| 25310 | +{ |
| 25311 | + __u32 b ; |
| 25312 | + |
| 25313 | + __u32 oldest = 0; |
| 25314 | + __u32 oldestSequence = 0; |
| 25315 | + |
| 25316 | + yaffs_block_info_t *bi; |
| 25317 | + |
| 25318 | + if(!dev->param.is_yaffs2) |
| 25319 | + return oldest; |
| 25320 | + |
| 25321 | + /* |
| 25322 | + * If refresh period < 10 then refreshing is disabled. |
| 25323 | + */ |
| 25324 | + if(dev->param.refresh_period < 10) |
| 25325 | + return oldest; |
| 25326 | + |
| 25327 | + /* |
| 25328 | + * Fix broken values. |
| 25329 | + */ |
| 25330 | + if(dev->refresh_skip > dev->param.refresh_period) |
| 25331 | + dev->refresh_skip = dev->param.refresh_period; |
| 25332 | + |
| 25333 | + if(dev->refresh_skip > 0) |
| 25334 | + return oldest; |
| 25335 | + |
| 25336 | + /* |
| 25337 | + * Refresh skip is now zero. |
| 25338 | + * We'll do a refresh this time around.... |
| 25339 | + * Update the refresh skip and find the oldest block. |
| 25340 | + */ |
| 25341 | + dev->refresh_skip = dev->param.refresh_period; |
| 25342 | + dev->refresh_count++; |
| 25343 | + bi = dev->block_info; |
| 25344 | + for (b = dev->internal_start_block; b <=dev->internal_end_block; b++){ |
| 25345 | + |
| 25346 | + if (bi->block_state == YAFFS_BLOCK_STATE_FULL){ |
| 25347 | + |
| 25348 | + if(oldest < 1 || |
| 25349 | + bi->seq_number < oldestSequence){ |
| 25350 | + oldest = b; |
| 25351 | + oldestSequence = bi->seq_number; |
| 25352 | + } |
| 25353 | + } |
| 25354 | + bi++; |
| 25355 | + } |
| 25356 | + |
| 25357 | + if (oldest > 0) { |
| 25358 | + T(YAFFS_TRACE_GC, |
| 25359 | + (TSTR("GC refresh count %d selected block %d with seq_number %d" TENDSTR), |
| 25360 | + dev->refresh_count, oldest, oldestSequence)); |
| 25361 | + } |
| 25362 | + |
| 25363 | + return oldest; |
| 25364 | +} |
| 25365 | + |
| 25366 | +int yaffs2_checkpt_required(yaffs_dev_t *dev) |
| 25367 | +{ |
| 25368 | + int nblocks; |
| 25369 | + |
| 25370 | + if(!dev->param.is_yaffs2) |
| 25371 | + return 0; |
| 25372 | + |
| 25373 | + nblocks = dev->internal_end_block - dev->internal_start_block + 1 ; |
| 25374 | + |
| 25375 | + return !dev->param.skip_checkpt_wr && |
| 25376 | + !dev->read_only && |
| 25377 | + (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS); |
| 25378 | +} |
| 25379 | + |
| 25380 | +int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev) |
| 25381 | +{ |
| 25382 | + int retval; |
| 25383 | + |
| 25384 | + if(!dev->param.is_yaffs2) |
| 25385 | + return 0; |
| 25386 | + |
| 25387 | + if (!dev->checkpoint_blocks_required && |
| 25388 | + yaffs2_checkpt_required(dev)){ |
| 25389 | + /* Not a valid value so recalculate */ |
| 25390 | + int n_bytes = 0; |
| 25391 | + int nBlocks; |
| 25392 | + int devBlocks = (dev->param.end_block - dev->param.start_block + 1); |
| 25393 | + |
| 25394 | + n_bytes += sizeof(yaffs_checkpt_validty_t); |
| 25395 | + n_bytes += sizeof(yaffs_checkpt_dev_t); |
| 25396 | + n_bytes += devBlocks * sizeof(yaffs_block_info_t); |
| 25397 | + n_bytes += devBlocks * dev->chunk_bit_stride; |
| 25398 | + n_bytes += (sizeof(yaffs_checkpt_obj_t) + sizeof(__u32)) * (dev->n_obj); |
| 25399 | + n_bytes += (dev->tnode_size + sizeof(__u32)) * (dev->n_tnodes); |
| 25400 | + n_bytes += sizeof(yaffs_checkpt_validty_t); |
| 25401 | + n_bytes += sizeof(__u32); /* checksum*/ |
| 25402 | + |
| 25403 | + /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */ |
| 25404 | + |
| 25405 | + nBlocks = (n_bytes/(dev->data_bytes_per_chunk * dev->param.chunks_per_block)) + 3; |
| 25406 | + |
| 25407 | + dev->checkpoint_blocks_required = nBlocks; |
| 25408 | + } |
| 25409 | + |
| 25410 | + retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt; |
| 25411 | + if(retval < 0) |
| 25412 | + retval = 0; |
| 25413 | + return retval; |
| 25414 | +} |
| 25415 | + |
| 25416 | +/*--------------------- Checkpointing --------------------*/ |
| 25417 | + |
| 25418 | + |
| 25419 | +static int yaffs2_wr_checkpt_validity_marker(yaffs_dev_t *dev, int head) |
| 25420 | +{ |
| 25421 | + yaffs_checkpt_validty_t cp; |
| 25422 | + |
| 25423 | + memset(&cp, 0, sizeof(cp)); |
| 25424 | + |
| 25425 | + cp.struct_type = sizeof(cp); |
| 25426 | + cp.magic = YAFFS_MAGIC; |
| 25427 | + cp.version = YAFFS_CHECKPOINT_VERSION; |
| 25428 | + cp.head = (head) ? 1 : 0; |
| 25429 | + |
| 25430 | + return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? |
| 25431 | + 1 : 0; |
| 25432 | +} |
| 25433 | + |
| 25434 | +static int yaffs2_rd_checkpt_validty_marker(yaffs_dev_t *dev, int head) |
| 25435 | +{ |
| 25436 | + yaffs_checkpt_validty_t cp; |
| 25437 | + int ok; |
| 25438 | + |
| 25439 | + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 25440 | + |
| 25441 | + if (ok) |
| 25442 | + ok = (cp.struct_type == sizeof(cp)) && |
| 25443 | + (cp.magic == YAFFS_MAGIC) && |
| 25444 | + (cp.version == YAFFS_CHECKPOINT_VERSION) && |
| 25445 | + (cp.head == ((head) ? 1 : 0)); |
| 25446 | + return ok ? 1 : 0; |
| 25447 | +} |
| 25448 | + |
| 25449 | +static void yaffs2_dev_to_checkpt_dev(yaffs_checkpt_dev_t *cp, |
| 25450 | + yaffs_dev_t *dev) |
| 25451 | +{ |
| 25452 | + cp->n_erased_blocks = dev->n_erased_blocks; |
| 25453 | + cp->alloc_block = dev->alloc_block; |
| 25454 | + cp->alloc_page = dev->alloc_page; |
| 25455 | + cp->n_free_chunks = dev->n_free_chunks; |
| 25456 | + |
| 25457 | + cp->n_deleted_files = dev->n_deleted_files; |
| 25458 | + cp->n_unlinked_files = dev->n_unlinked_files; |
| 25459 | + cp->n_bg_deletions = dev->n_bg_deletions; |
| 25460 | + cp->seq_number = dev->seq_number; |
| 25461 | + |
| 25462 | +} |
| 25463 | + |
| 25464 | +static void yaffs_checkpt_dev_to_dev(yaffs_dev_t *dev, |
| 25465 | + yaffs_checkpt_dev_t *cp) |
| 25466 | +{ |
| 25467 | + dev->n_erased_blocks = cp->n_erased_blocks; |
| 25468 | + dev->alloc_block = cp->alloc_block; |
| 25469 | + dev->alloc_page = cp->alloc_page; |
| 25470 | + dev->n_free_chunks = cp->n_free_chunks; |
| 25471 | + |
| 25472 | + dev->n_deleted_files = cp->n_deleted_files; |
| 25473 | + dev->n_unlinked_files = cp->n_unlinked_files; |
| 25474 | + dev->n_bg_deletions = cp->n_bg_deletions; |
| 25475 | + dev->seq_number = cp->seq_number; |
| 25476 | +} |
| 25477 | + |
| 25478 | + |
| 25479 | +static int yaffs2_wr_checkpt_dev(yaffs_dev_t *dev) |
| 25480 | +{ |
| 25481 | + yaffs_checkpt_dev_t cp; |
| 25482 | + __u32 n_bytes; |
| 25483 | + __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1); |
| 25484 | + |
| 25485 | + int ok; |
| 25486 | + |
| 25487 | + /* Write device runtime values*/ |
| 25488 | + yaffs2_dev_to_checkpt_dev(&cp, dev); |
| 25489 | + cp.struct_type = sizeof(cp); |
| 25490 | + |
| 25491 | + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 25492 | + |
| 25493 | + /* Write block info */ |
| 25494 | + if (ok) { |
| 25495 | + n_bytes = nBlocks * sizeof(yaffs_block_info_t); |
| 25496 | + ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes); |
| 25497 | + } |
| 25498 | + |
| 25499 | + /* Write chunk bits */ |
| 25500 | + if (ok) { |
| 25501 | + n_bytes = nBlocks * dev->chunk_bit_stride; |
| 25502 | + ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes); |
| 25503 | + } |
| 25504 | + return ok ? 1 : 0; |
| 25505 | + |
| 25506 | +} |
| 25507 | + |
| 25508 | +static int yaffs2_rd_checkpt_dev(yaffs_dev_t *dev) |
| 25509 | +{ |
| 25510 | + yaffs_checkpt_dev_t cp; |
| 25511 | + __u32 n_bytes; |
| 25512 | + __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1); |
| 25513 | + |
| 25514 | + int ok; |
| 25515 | + |
| 25516 | + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 25517 | + if (!ok) |
| 25518 | + return 0; |
| 25519 | + |
| 25520 | + if (cp.struct_type != sizeof(cp)) |
| 25521 | + return 0; |
| 25522 | + |
| 25523 | + |
| 25524 | + yaffs_checkpt_dev_to_dev(dev, &cp); |
| 25525 | + |
| 25526 | + n_bytes = nBlocks * sizeof(yaffs_block_info_t); |
| 25527 | + |
| 25528 | + ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes); |
| 25529 | + |
| 25530 | + if (!ok) |
| 25531 | + return 0; |
| 25532 | + n_bytes = nBlocks * dev->chunk_bit_stride; |
| 25533 | + |
| 25534 | + ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes); |
| 25535 | + |
| 25536 | + return ok ? 1 : 0; |
| 25537 | +} |
| 25538 | + |
| 25539 | +static void yaffs2_obj_checkpt_obj(yaffs_checkpt_obj_t *cp, |
| 25540 | + yaffs_obj_t *obj) |
| 25541 | +{ |
| 25542 | + |
| 25543 | + cp->obj_id = obj->obj_id; |
| 25544 | + cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0; |
| 25545 | + cp->hdr_chunk = obj->hdr_chunk; |
| 25546 | + cp->variant_type = obj->variant_type; |
| 25547 | + cp->deleted = obj->deleted; |
| 25548 | + cp->soft_del = obj->soft_del; |
| 25549 | + cp->unlinked = obj->unlinked; |
| 25550 | + cp->fake = obj->fake; |
| 25551 | + cp->rename_allowed = obj->rename_allowed; |
| 25552 | + cp->unlink_allowed = obj->unlink_allowed; |
| 25553 | + cp->serial = obj->serial; |
| 25554 | + cp->n_data_chunks = obj->n_data_chunks; |
| 25555 | + |
| 25556 | + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) |
| 25557 | + cp->size_or_equiv_obj = obj->variant.file_variant.file_size; |
| 25558 | + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) |
| 25559 | + cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id; |
| 25560 | +} |
| 25561 | + |
| 25562 | +static int taffs2_checkpt_obj_to_obj(yaffs_obj_t *obj, yaffs_checkpt_obj_t *cp) |
| 25563 | +{ |
| 25564 | + |
| 25565 | + yaffs_obj_t *parent; |
| 25566 | + |
| 25567 | + if (obj->variant_type != cp->variant_type) { |
| 25568 | + T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d " |
| 25569 | + TCONT("chunk %d does not match existing object type %d") |
| 25570 | + TENDSTR), cp->obj_id, cp->variant_type, cp->hdr_chunk, |
| 25571 | + obj->variant_type)); |
| 25572 | + return 0; |
| 25573 | + } |
| 25574 | + |
| 25575 | + obj->obj_id = cp->obj_id; |
| 25576 | + |
| 25577 | + if (cp->parent_id) |
| 25578 | + parent = yaffs_find_or_create_by_number( |
| 25579 | + obj->my_dev, |
| 25580 | + cp->parent_id, |
| 25581 | + YAFFS_OBJECT_TYPE_DIRECTORY); |
| 25582 | + else |
| 25583 | + parent = NULL; |
| 25584 | + |
| 25585 | + if (parent) { |
| 25586 | + if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 25587 | + T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d" |
| 25588 | + TCONT(" chunk %d Parent type, %d, not directory") |
| 25589 | + TENDSTR), |
| 25590 | + cp->obj_id, cp->parent_id, cp->variant_type, |
| 25591 | + cp->hdr_chunk, parent->variant_type)); |
| 25592 | + return 0; |
| 25593 | + } |
| 25594 | + yaffs_add_obj_to_dir(parent, obj); |
| 25595 | + } |
| 25596 | + |
| 25597 | + obj->hdr_chunk = cp->hdr_chunk; |
| 25598 | + obj->variant_type = cp->variant_type; |
| 25599 | + obj->deleted = cp->deleted; |
| 25600 | + obj->soft_del = cp->soft_del; |
| 25601 | + obj->unlinked = cp->unlinked; |
| 25602 | + obj->fake = cp->fake; |
| 25603 | + obj->rename_allowed = cp->rename_allowed; |
| 25604 | + obj->unlink_allowed = cp->unlink_allowed; |
| 25605 | + obj->serial = cp->serial; |
| 25606 | + obj->n_data_chunks = cp->n_data_chunks; |
| 25607 | + |
| 25608 | + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) |
| 25609 | + obj->variant.file_variant.file_size = cp->size_or_equiv_obj; |
| 25610 | + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) |
| 25611 | + obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj; |
| 25612 | + |
| 25613 | + if (obj->hdr_chunk > 0) |
| 25614 | + obj->lazy_loaded = 1; |
| 25615 | + return 1; |
| 25616 | +} |
| 25617 | + |
| 25618 | + |
| 25619 | + |
| 25620 | +static int yaffs2_checkpt_tnode_worker(yaffs_obj_t *in, yaffs_tnode_t *tn, |
| 25621 | + __u32 level, int chunk_offset) |
| 25622 | +{ |
| 25623 | + int i; |
| 25624 | + yaffs_dev_t *dev = in->my_dev; |
| 25625 | + int ok = 1; |
| 25626 | + |
| 25627 | + if (tn) { |
| 25628 | + if (level > 0) { |
| 25629 | + |
| 25630 | + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { |
| 25631 | + if (tn->internal[i]) { |
| 25632 | + ok = yaffs2_checkpt_tnode_worker(in, |
| 25633 | + tn->internal[i], |
| 25634 | + level - 1, |
| 25635 | + (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i); |
| 25636 | + } |
| 25637 | + } |
| 25638 | + } else if (level == 0) { |
| 25639 | + __u32 baseOffset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS; |
| 25640 | + ok = (yaffs2_checkpt_wr(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset)); |
| 25641 | + if (ok) |
| 25642 | + ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == dev->tnode_size); |
| 25643 | + } |
| 25644 | + } |
| 25645 | + |
| 25646 | + return ok; |
| 25647 | + |
| 25648 | +} |
| 25649 | + |
| 25650 | +static int yaffs2_wr_checkpt_tnodes(yaffs_obj_t *obj) |
| 25651 | +{ |
| 25652 | + __u32 endMarker = ~0; |
| 25653 | + int ok = 1; |
| 25654 | + |
| 25655 | + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) { |
| 25656 | + ok = yaffs2_checkpt_tnode_worker(obj, |
| 25657 | + obj->variant.file_variant.top, |
| 25658 | + obj->variant.file_variant.top_level, |
| 25659 | + 0); |
| 25660 | + if (ok) |
| 25661 | + ok = (yaffs2_checkpt_wr(obj->my_dev, &endMarker, sizeof(endMarker)) == |
| 25662 | + sizeof(endMarker)); |
| 25663 | + } |
| 25664 | + |
| 25665 | + return ok ? 1 : 0; |
| 25666 | +} |
| 25667 | + |
| 25668 | +static int yaffs2_rd_checkpt_tnodes(yaffs_obj_t *obj) |
| 25669 | +{ |
| 25670 | + __u32 baseChunk; |
| 25671 | + int ok = 1; |
| 25672 | + yaffs_dev_t *dev = obj->my_dev; |
| 25673 | + yaffs_file_s *fileStructPtr = &obj->variant.file_variant; |
| 25674 | + yaffs_tnode_t *tn; |
| 25675 | + int nread = 0; |
| 25676 | + |
| 25677 | + ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk)); |
| 25678 | + |
| 25679 | + while (ok && (~baseChunk)) { |
| 25680 | + nread++; |
| 25681 | + /* Read level 0 tnode */ |
| 25682 | + |
| 25683 | + |
| 25684 | + tn = yaffs_get_tnode(dev); |
| 25685 | + if (tn){ |
| 25686 | + ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == dev->tnode_size); |
| 25687 | + } else |
| 25688 | + ok = 0; |
| 25689 | + |
| 25690 | + if (tn && ok) |
| 25691 | + ok = yaffs_add_find_tnode_0(dev, |
| 25692 | + fileStructPtr, |
| 25693 | + baseChunk, |
| 25694 | + tn) ? 1 : 0; |
| 25695 | + |
| 25696 | + if (ok) |
| 25697 | + ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk)); |
| 25698 | + |
| 25699 | + } |
| 25700 | + |
| 25701 | + T(YAFFS_TRACE_CHECKPOINT, ( |
| 25702 | + TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR), |
| 25703 | + nread, baseChunk, ok)); |
| 25704 | + |
| 25705 | + return ok ? 1 : 0; |
| 25706 | +} |
| 25707 | + |
| 25708 | + |
| 25709 | +static int yaffs2_wr_checkpt_objs(yaffs_dev_t *dev) |
| 25710 | +{ |
| 25711 | + yaffs_obj_t *obj; |
| 25712 | + yaffs_checkpt_obj_t cp; |
| 25713 | + int i; |
| 25714 | + int ok = 1; |
| 25715 | + struct ylist_head *lh; |
| 25716 | + |
| 25717 | + |
| 25718 | + /* Iterate through the objects in each hash entry, |
| 25719 | + * dumping them to the checkpointing stream. |
| 25720 | + */ |
| 25721 | + |
| 25722 | + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) { |
| 25723 | + ylist_for_each(lh, &dev->obj_bucket[i].list) { |
| 25724 | + if (lh) { |
| 25725 | + obj = ylist_entry(lh, yaffs_obj_t, hash_link); |
| 25726 | + if (!obj->defered_free) { |
| 25727 | + yaffs2_obj_checkpt_obj(&cp, obj); |
| 25728 | + cp.struct_type = sizeof(cp); |
| 25729 | + |
| 25730 | + T(YAFFS_TRACE_CHECKPOINT, ( |
| 25731 | + TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR), |
| 25732 | + cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk, obj)); |
| 25733 | + |
| 25734 | + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 25735 | + |
| 25736 | + if (ok && obj->variant_type == YAFFS_OBJECT_TYPE_FILE) |
| 25737 | + ok = yaffs2_wr_checkpt_tnodes(obj); |
| 25738 | + } |
| 25739 | + } |
| 25740 | + } |
| 25741 | + } |
| 25742 | + |
| 25743 | + /* Dump end of list */ |
| 25744 | + memset(&cp, 0xFF, sizeof(yaffs_checkpt_obj_t)); |
| 25745 | + cp.struct_type = sizeof(cp); |
| 25746 | + |
| 25747 | + if (ok) |
| 25748 | + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 25749 | + |
| 25750 | + return ok ? 1 : 0; |
| 25751 | +} |
| 25752 | + |
| 25753 | +static int yaffs2_rd_checkpt_objs(yaffs_dev_t *dev) |
| 25754 | +{ |
| 25755 | + yaffs_obj_t *obj; |
| 25756 | + yaffs_checkpt_obj_t cp; |
| 25757 | + int ok = 1; |
| 25758 | + int done = 0; |
| 25759 | + yaffs_obj_t *hard_list = NULL; |
| 25760 | + |
| 25761 | + while (ok && !done) { |
| 25762 | + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); |
| 25763 | + if (cp.struct_type != sizeof(cp)) { |
| 25764 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR), |
| 25765 | + cp.struct_type, (int)sizeof(cp), ok)); |
| 25766 | + ok = 0; |
| 25767 | + } |
| 25768 | + |
| 25769 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR), |
| 25770 | + cp.obj_id, cp.parent_id, cp.variant_type, cp.hdr_chunk)); |
| 25771 | + |
| 25772 | + if (ok && cp.obj_id == ~0) |
| 25773 | + done = 1; |
| 25774 | + else if (ok) { |
| 25775 | + obj = yaffs_find_or_create_by_number(dev, cp.obj_id, cp.variant_type); |
| 25776 | + if (obj) { |
| 25777 | + ok = taffs2_checkpt_obj_to_obj(obj, &cp); |
| 25778 | + if (!ok) |
| 25779 | + break; |
| 25780 | + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) { |
| 25781 | + ok = yaffs2_rd_checkpt_tnodes(obj); |
| 25782 | + } else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { |
| 25783 | + obj->hard_links.next = |
| 25784 | + (struct ylist_head *) hard_list; |
| 25785 | + hard_list = obj; |
| 25786 | + } |
| 25787 | + } else |
| 25788 | + ok = 0; |
| 25789 | + } |
| 25790 | + } |
| 25791 | + |
| 25792 | + if (ok) |
| 25793 | + yaffs_link_fixup(dev, hard_list); |
| 25794 | + |
| 25795 | + return ok ? 1 : 0; |
| 25796 | +} |
| 25797 | + |
| 25798 | +static int yaffs2_wr_checkpt_sum(yaffs_dev_t *dev) |
| 25799 | +{ |
| 25800 | + __u32 checkpt_sum; |
| 25801 | + int ok; |
| 25802 | + |
| 25803 | + yaffs2_get_checkpt_sum(dev, &checkpt_sum); |
| 25804 | + |
| 25805 | + ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == sizeof(checkpt_sum)); |
| 25806 | + |
| 25807 | + if (!ok) |
| 25808 | + return 0; |
| 25809 | + |
| 25810 | + return 1; |
| 25811 | +} |
| 25812 | + |
| 25813 | +static int yaffs2_rd_checkpt_sum(yaffs_dev_t *dev) |
| 25814 | +{ |
| 25815 | + __u32 checkpt_sum0; |
| 25816 | + __u32 checkpt_sum1; |
| 25817 | + int ok; |
| 25818 | + |
| 25819 | + yaffs2_get_checkpt_sum(dev, &checkpt_sum0); |
| 25820 | + |
| 25821 | + ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == sizeof(checkpt_sum1)); |
| 25822 | + |
| 25823 | + if (!ok) |
| 25824 | + return 0; |
| 25825 | + |
| 25826 | + if (checkpt_sum0 != checkpt_sum1) |
| 25827 | + return 0; |
| 25828 | + |
| 25829 | + return 1; |
| 25830 | +} |
| 25831 | + |
| 25832 | + |
| 25833 | +static int yaffs2_wr_checkpt_data(yaffs_dev_t *dev) |
| 25834 | +{ |
| 25835 | + int ok = 1; |
| 25836 | + |
| 25837 | + if (!yaffs2_checkpt_required(dev)) { |
| 25838 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR))); |
| 25839 | + ok = 0; |
| 25840 | + } |
| 25841 | + |
| 25842 | + if (ok) |
| 25843 | + ok = yaffs2_checkpt_open(dev, 1); |
| 25844 | + |
| 25845 | + if (ok) { |
| 25846 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); |
| 25847 | + ok = yaffs2_wr_checkpt_validity_marker(dev, 1); |
| 25848 | + } |
| 25849 | + if (ok) { |
| 25850 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR))); |
| 25851 | + ok = yaffs2_wr_checkpt_dev(dev); |
| 25852 | + } |
| 25853 | + if (ok) { |
| 25854 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR))); |
| 25855 | + ok = yaffs2_wr_checkpt_objs(dev); |
| 25856 | + } |
| 25857 | + if (ok) { |
| 25858 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR))); |
| 25859 | + ok = yaffs2_wr_checkpt_validity_marker(dev, 0); |
| 25860 | + } |
| 25861 | + |
| 25862 | + if (ok) |
| 25863 | + ok = yaffs2_wr_checkpt_sum(dev); |
| 25864 | + |
| 25865 | + if (!yaffs_checkpt_close(dev)) |
| 25866 | + ok = 0; |
| 25867 | + |
| 25868 | + if (ok) |
| 25869 | + dev->is_checkpointed = 1; |
| 25870 | + else |
| 25871 | + dev->is_checkpointed = 0; |
| 25872 | + |
| 25873 | + return dev->is_checkpointed; |
| 25874 | +} |
| 25875 | + |
| 25876 | +static int yaffs2_rd_checkpt_data(yaffs_dev_t *dev) |
| 25877 | +{ |
| 25878 | + int ok = 1; |
| 25879 | + |
| 25880 | + if(!dev->param.is_yaffs2) |
| 25881 | + ok = 0; |
| 25882 | + |
| 25883 | + if (ok && dev->param.skip_checkpt_rd) { |
| 25884 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR))); |
| 25885 | + ok = 0; |
| 25886 | + } |
| 25887 | + |
| 25888 | + if (ok) |
| 25889 | + ok = yaffs2_checkpt_open(dev, 0); /* open for read */ |
| 25890 | + |
| 25891 | + if (ok) { |
| 25892 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); |
| 25893 | + ok = yaffs2_rd_checkpt_validty_marker(dev, 1); |
| 25894 | + } |
| 25895 | + if (ok) { |
| 25896 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR))); |
| 25897 | + ok = yaffs2_rd_checkpt_dev(dev); |
| 25898 | + } |
| 25899 | + if (ok) { |
| 25900 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR))); |
| 25901 | + ok = yaffs2_rd_checkpt_objs(dev); |
| 25902 | + } |
| 25903 | + if (ok) { |
| 25904 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR))); |
| 25905 | + ok = yaffs2_rd_checkpt_validty_marker(dev, 0); |
| 25906 | + } |
| 25907 | + |
| 25908 | + if (ok) { |
| 25909 | + ok = yaffs2_rd_checkpt_sum(dev); |
| 25910 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok)); |
| 25911 | + } |
| 25912 | + |
| 25913 | + if (!yaffs_checkpt_close(dev)) |
| 25914 | + ok = 0; |
| 25915 | + |
| 25916 | + if (ok) |
| 25917 | + dev->is_checkpointed = 1; |
| 25918 | + else |
| 25919 | + dev->is_checkpointed = 0; |
| 25920 | + |
| 25921 | + return ok ? 1 : 0; |
| 25922 | + |
| 25923 | +} |
| 25924 | + |
| 25925 | +void yaffs2_checkpt_invalidate(yaffs_dev_t *dev) |
| 25926 | +{ |
| 25927 | + if (dev->is_checkpointed || |
| 25928 | + dev->blocks_in_checkpt > 0) { |
| 25929 | + dev->is_checkpointed = 0; |
| 25930 | + yaffs2_checkpt_invalidate_stream(dev); |
| 25931 | + } |
| 25932 | + if (dev->param.sb_dirty_fn) |
| 25933 | + dev->param.sb_dirty_fn(dev); |
| 25934 | +} |
| 25935 | + |
| 25936 | + |
| 25937 | +int yaffs_checkpoint_save(yaffs_dev_t *dev) |
| 25938 | +{ |
| 25939 | + |
| 25940 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed)); |
| 25941 | + |
| 25942 | + yaffs_verify_objects(dev); |
| 25943 | + yaffs_verify_blocks(dev); |
| 25944 | + yaffs_verify_free_chunks(dev); |
| 25945 | + |
| 25946 | + if (!dev->is_checkpointed) { |
| 25947 | + yaffs2_checkpt_invalidate(dev); |
| 25948 | + yaffs2_wr_checkpt_data(dev); |
| 25949 | + } |
| 25950 | + |
| 25951 | + T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed)); |
| 25952 | + |
| 25953 | + return dev->is_checkpointed; |
| 25954 | +} |
| 25955 | + |
| 25956 | +int yaffs2_checkpt_restore(yaffs_dev_t *dev) |
| 25957 | +{ |
| 25958 | + int retval; |
| 25959 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed)); |
| 25960 | + |
| 25961 | + retval = yaffs2_rd_checkpt_data(dev); |
| 25962 | + |
| 25963 | + if (dev->is_checkpointed) { |
| 25964 | + yaffs_verify_objects(dev); |
| 25965 | + yaffs_verify_blocks(dev); |
| 25966 | + yaffs_verify_free_chunks(dev); |
| 25967 | + } |
| 25968 | + |
| 25969 | + T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed)); |
| 25970 | + |
| 25971 | + return retval; |
| 25972 | +} |
| 25973 | + |
| 25974 | +int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size) |
| 25975 | +{ |
| 25976 | + /* if newsSize > oldFileSize. |
| 25977 | + * We're going to be writing a hole. |
| 25978 | + * If the hole is small then write zeros otherwise write a start of hole marker. |
| 25979 | + */ |
| 25980 | + |
| 25981 | + |
| 25982 | + loff_t oldFileSize; |
| 25983 | + int increase; |
| 25984 | + int smallHole ; |
| 25985 | + int result = YAFFS_OK; |
| 25986 | + yaffs_dev_t *dev = NULL; |
| 25987 | + |
| 25988 | + __u8 *localBuffer = NULL; |
| 25989 | + |
| 25990 | + int smallIncreaseOk = 0; |
| 25991 | + |
| 25992 | + if(!obj) |
| 25993 | + return YAFFS_FAIL; |
| 25994 | + |
| 25995 | + if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE) |
| 25996 | + return YAFFS_FAIL; |
| 25997 | + |
| 25998 | + dev = obj->my_dev; |
| 25999 | + |
| 26000 | + /* Bail out if not yaffs2 mode */ |
| 26001 | + if(!dev->param.is_yaffs2) |
| 26002 | + return YAFFS_OK; |
| 26003 | + |
| 26004 | + oldFileSize = obj->variant.file_variant.file_size; |
| 26005 | + |
| 26006 | + if (new_size <= oldFileSize) |
| 26007 | + return YAFFS_OK; |
| 26008 | + |
| 26009 | + increase = new_size - oldFileSize; |
| 26010 | + |
| 26011 | + if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk && |
| 26012 | + yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1)) |
| 26013 | + smallHole = 1; |
| 26014 | + else |
| 26015 | + smallHole = 0; |
| 26016 | + |
| 26017 | + if(smallHole) |
| 26018 | + localBuffer= yaffs_get_temp_buffer(dev, __LINE__); |
| 26019 | + |
| 26020 | + if(localBuffer){ |
| 26021 | + /* fill hole with zero bytes */ |
| 26022 | + int pos = oldFileSize; |
| 26023 | + int thisWrite; |
| 26024 | + int written; |
| 26025 | + memset(localBuffer,0,dev->data_bytes_per_chunk); |
| 26026 | + smallIncreaseOk = 1; |
| 26027 | + |
| 26028 | + while(increase > 0 && smallIncreaseOk){ |
| 26029 | + thisWrite = increase; |
| 26030 | + if(thisWrite > dev->data_bytes_per_chunk) |
| 26031 | + thisWrite = dev->data_bytes_per_chunk; |
| 26032 | + written = yaffs_do_file_wr(obj,localBuffer,pos,thisWrite,0); |
| 26033 | + if(written == thisWrite){ |
| 26034 | + pos += thisWrite; |
| 26035 | + increase -= thisWrite; |
| 26036 | + } else |
| 26037 | + smallIncreaseOk = 0; |
| 26038 | + } |
| 26039 | + |
| 26040 | + yaffs_release_temp_buffer(dev,localBuffer,__LINE__); |
| 26041 | + |
| 26042 | + /* If we were out of space then reverse any chunks we've added */ |
| 26043 | + if(!smallIncreaseOk) |
| 26044 | + yaffs_resize_file_down(obj, oldFileSize); |
| 26045 | + } |
| 26046 | + |
| 26047 | + if (!smallIncreaseOk && |
| 26048 | + obj->parent && |
| 26049 | + obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED && |
| 26050 | + obj->parent->obj_id != YAFFS_OBJECTID_DELETED){ |
| 26051 | + /* Write a hole start header with the old file size */ |
| 26052 | + yaffs_update_oh(obj, NULL, 0, 1, 0, NULL); |
| 26053 | + } |
| 26054 | + |
| 26055 | + return result; |
| 26056 | + |
| 26057 | +} |
| 26058 | + |
| 26059 | + |
| 26060 | +typedef struct { |
| 26061 | + int seq; |
| 26062 | + int block; |
| 26063 | +} yaffs_BlockIndex; |
| 26064 | + |
| 26065 | + |
| 26066 | +static int yaffs2_ybicmp(const void *a, const void *b) |
| 26067 | +{ |
| 26068 | + register int aseq = ((yaffs_BlockIndex *)a)->seq; |
| 26069 | + register int bseq = ((yaffs_BlockIndex *)b)->seq; |
| 26070 | + register int ablock = ((yaffs_BlockIndex *)a)->block; |
| 26071 | + register int bblock = ((yaffs_BlockIndex *)b)->block; |
| 26072 | + if (aseq == bseq) |
| 26073 | + return ablock - bblock; |
| 26074 | + else |
| 26075 | + return aseq - bseq; |
| 26076 | +} |
| 26077 | + |
| 26078 | +int yaffs2_scan_backwards(yaffs_dev_t *dev) |
| 26079 | +{ |
| 26080 | + yaffs_ext_tags tags; |
| 26081 | + int blk; |
| 26082 | + int blockIterator; |
| 26083 | + int startIterator; |
| 26084 | + int endIterator; |
| 26085 | + int nBlocksToScan = 0; |
| 26086 | + |
| 26087 | + int chunk; |
| 26088 | + int result; |
| 26089 | + int c; |
| 26090 | + int deleted; |
| 26091 | + yaffs_block_state_t state; |
| 26092 | + yaffs_obj_t *hard_list = NULL; |
| 26093 | + yaffs_block_info_t *bi; |
| 26094 | + __u32 seq_number; |
| 26095 | + yaffs_obj_header *oh; |
| 26096 | + yaffs_obj_t *in; |
| 26097 | + yaffs_obj_t *parent; |
| 26098 | + int nBlocks = dev->internal_end_block - dev->internal_start_block + 1; |
| 26099 | + int itsUnlinked; |
| 26100 | + __u8 *chunkData; |
| 26101 | + |
| 26102 | + int file_size; |
| 26103 | + int is_shrink; |
| 26104 | + int foundChunksInBlock; |
| 26105 | + int equiv_id; |
| 26106 | + int alloc_failed = 0; |
| 26107 | + |
| 26108 | + |
| 26109 | + yaffs_BlockIndex *blockIndex = NULL; |
| 26110 | + int altBlockIndex = 0; |
| 26111 | + |
| 26112 | + T(YAFFS_TRACE_SCAN, |
| 26113 | + (TSTR |
| 26114 | + ("yaffs2_scan_backwards starts intstartblk %d intendblk %d..." |
| 26115 | + TENDSTR), dev->internal_start_block, dev->internal_end_block)); |
| 26116 | + |
| 26117 | + |
| 26118 | + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; |
| 26119 | + |
| 26120 | + blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); |
| 26121 | + |
| 26122 | + if (!blockIndex) { |
| 26123 | + blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex)); |
| 26124 | + altBlockIndex = 1; |
| 26125 | + } |
| 26126 | + |
| 26127 | + if (!blockIndex) { |
| 26128 | + T(YAFFS_TRACE_SCAN, |
| 26129 | + (TSTR("yaffs2_scan_backwards() could not allocate block index!" TENDSTR))); |
| 26130 | + return YAFFS_FAIL; |
| 26131 | + } |
| 26132 | + |
| 26133 | + dev->blocks_in_checkpt = 0; |
| 26134 | + |
| 26135 | + chunkData = yaffs_get_temp_buffer(dev, __LINE__); |
| 26136 | + |
| 26137 | + /* Scan all the blocks to determine their state */ |
| 26138 | + bi = dev->block_info; |
| 26139 | + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; blk++) { |
| 26140 | + yaffs_clear_chunk_bits(dev, blk); |
| 26141 | + bi->pages_in_use = 0; |
| 26142 | + bi->soft_del_pages = 0; |
| 26143 | + |
| 26144 | + yaffs_query_init_block_state(dev, blk, &state, &seq_number); |
| 26145 | + |
| 26146 | + bi->block_state = state; |
| 26147 | + bi->seq_number = seq_number; |
| 26148 | + |
| 26149 | + if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) |
| 26150 | + bi->block_state = state = YAFFS_BLOCK_STATE_CHECKPOINT; |
| 26151 | + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) |
| 26152 | + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; |
| 26153 | + |
| 26154 | + T(YAFFS_TRACE_SCAN_DEBUG, |
| 26155 | + (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, |
| 26156 | + state, seq_number)); |
| 26157 | + |
| 26158 | + |
| 26159 | + if (state == YAFFS_BLOCK_STATE_CHECKPOINT) { |
| 26160 | + dev->blocks_in_checkpt++; |
| 26161 | + |
| 26162 | + } else if (state == YAFFS_BLOCK_STATE_DEAD) { |
| 26163 | + T(YAFFS_TRACE_BAD_BLOCKS, |
| 26164 | + (TSTR("block %d is bad" TENDSTR), blk)); |
| 26165 | + } else if (state == YAFFS_BLOCK_STATE_EMPTY) { |
| 26166 | + T(YAFFS_TRACE_SCAN_DEBUG, |
| 26167 | + (TSTR("Block empty " TENDSTR))); |
| 26168 | + dev->n_erased_blocks++; |
| 26169 | + dev->n_free_chunks += dev->param.chunks_per_block; |
| 26170 | + } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { |
| 26171 | + |
| 26172 | + /* Determine the highest sequence number */ |
| 26173 | + if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER && |
| 26174 | + seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) { |
| 26175 | + |
| 26176 | + blockIndex[nBlocksToScan].seq = seq_number; |
| 26177 | + blockIndex[nBlocksToScan].block = blk; |
| 26178 | + |
| 26179 | + nBlocksToScan++; |
| 26180 | + |
| 26181 | + if (seq_number >= dev->seq_number) |
| 26182 | + dev->seq_number = seq_number; |
| 26183 | + } else { |
| 26184 | + /* TODO: Nasty sequence number! */ |
| 26185 | + T(YAFFS_TRACE_SCAN, |
| 26186 | + (TSTR |
| 26187 | + ("Block scanning block %d has bad sequence number %d" |
| 26188 | + TENDSTR), blk, seq_number)); |
| 26189 | + |
| 26190 | + } |
| 26191 | + } |
| 26192 | + bi++; |
| 26193 | + } |
| 26194 | + |
| 26195 | + T(YAFFS_TRACE_SCAN, |
| 26196 | + (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan)); |
| 26197 | + |
| 26198 | + |
| 26199 | + |
| 26200 | + YYIELD(); |
| 26201 | + |
| 26202 | + /* Sort the blocks by sequence number*/ |
| 26203 | + yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp); |
| 26204 | + |
| 26205 | + YYIELD(); |
| 26206 | + |
| 26207 | + T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR))); |
| 26208 | + |
| 26209 | + /* Now scan the blocks looking at the data. */ |
| 26210 | + startIterator = 0; |
| 26211 | + endIterator = nBlocksToScan - 1; |
| 26212 | + T(YAFFS_TRACE_SCAN_DEBUG, |
| 26213 | + (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); |
| 26214 | + |
| 26215 | + /* For each block.... backwards */ |
| 26216 | + for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; |
| 26217 | + blockIterator--) { |
| 26218 | + /* Cooperative multitasking! This loop can run for so |
| 26219 | + long that watchdog timers expire. */ |
| 26220 | + YYIELD(); |
| 26221 | + |
| 26222 | + /* get the block to scan in the correct order */ |
| 26223 | + blk = blockIndex[blockIterator].block; |
| 26224 | + |
| 26225 | + bi = yaffs_get_block_info(dev, blk); |
| 26226 | + |
| 26227 | + |
| 26228 | + state = bi->block_state; |
| 26229 | + |
| 26230 | + deleted = 0; |
| 26231 | + |
| 26232 | + /* For each chunk in each block that needs scanning.... */ |
| 26233 | + foundChunksInBlock = 0; |
| 26234 | + for (c = dev->param.chunks_per_block - 1; |
| 26235 | + !alloc_failed && c >= 0 && |
| 26236 | + (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || |
| 26237 | + state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { |
| 26238 | + /* Scan backwards... |
| 26239 | + * Read the tags and decide what to do |
| 26240 | + */ |
| 26241 | + |
| 26242 | + chunk = blk * dev->param.chunks_per_block + c; |
| 26243 | + |
| 26244 | + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, |
| 26245 | + &tags); |
| 26246 | + |
| 26247 | + /* Let's have a good look at this chunk... */ |
| 26248 | + |
| 26249 | + if (!tags.chunk_used) { |
| 26250 | + /* An unassigned chunk in the block. |
| 26251 | + * If there are used chunks after this one, then |
| 26252 | + * it is a chunk that was skipped due to failing the erased |
| 26253 | + * check. Just skip it so that it can be deleted. |
| 26254 | + * But, more typically, We get here when this is an unallocated |
| 26255 | + * chunk and his means that either the block is empty or |
| 26256 | + * this is the one being allocated from |
| 26257 | + */ |
| 26258 | + |
| 26259 | + if (foundChunksInBlock) { |
| 26260 | + /* This is a chunk that was skipped due to failing the erased check */ |
| 26261 | + } else if (c == 0) { |
| 26262 | + /* We're looking at the first chunk in the block so the block is unused */ |
| 26263 | + state = YAFFS_BLOCK_STATE_EMPTY; |
| 26264 | + dev->n_erased_blocks++; |
| 26265 | + } else { |
| 26266 | + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || |
| 26267 | + state == YAFFS_BLOCK_STATE_ALLOCATING) { |
| 26268 | + if (dev->seq_number == bi->seq_number) { |
| 26269 | + /* this is the block being allocated from */ |
| 26270 | + |
| 26271 | + T(YAFFS_TRACE_SCAN, |
| 26272 | + (TSTR |
| 26273 | + (" Allocating from %d %d" |
| 26274 | + TENDSTR), blk, c)); |
| 26275 | + |
| 26276 | + state = YAFFS_BLOCK_STATE_ALLOCATING; |
| 26277 | + dev->alloc_block = blk; |
| 26278 | + dev->alloc_page = c; |
| 26279 | + dev->alloc_block_finder = blk; |
| 26280 | + } else { |
| 26281 | + /* This is a partially written block that is not |
| 26282 | + * the current allocation block. |
| 26283 | + */ |
| 26284 | + |
| 26285 | + T(YAFFS_TRACE_SCAN, |
| 26286 | + (TSTR("Partially written block %d detected" TENDSTR), |
| 26287 | + blk)); |
| 26288 | + } |
| 26289 | + } |
| 26290 | + } |
| 26291 | + |
| 26292 | + dev->n_free_chunks++; |
| 26293 | + |
| 26294 | + } else if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED) { |
| 26295 | + T(YAFFS_TRACE_SCAN, |
| 26296 | + (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR), |
| 26297 | + blk, c)); |
| 26298 | + |
| 26299 | + dev->n_free_chunks++; |
| 26300 | + |
| 26301 | + } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID || |
| 26302 | + tags.chunk_id > YAFFS_MAX_CHUNK_ID || |
| 26303 | + (tags.chunk_id > 0 && tags.n_bytes > dev->data_bytes_per_chunk) || |
| 26304 | + tags.seq_number != bi->seq_number ) { |
| 26305 | + T(YAFFS_TRACE_SCAN, |
| 26306 | + (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored"TENDSTR), |
| 26307 | + blk, c,tags.obj_id, tags.chunk_id, tags.n_bytes)); |
| 26308 | + |
| 26309 | + dev->n_free_chunks++; |
| 26310 | + |
| 26311 | + } else if (tags.chunk_id > 0) { |
| 26312 | + /* chunk_id > 0 so it is a data chunk... */ |
| 26313 | + unsigned int endpos; |
| 26314 | + __u32 chunkBase = |
| 26315 | + (tags.chunk_id - 1) * dev->data_bytes_per_chunk; |
| 26316 | + |
| 26317 | + foundChunksInBlock = 1; |
| 26318 | + |
| 26319 | + |
| 26320 | + yaffs_set_chunk_bit(dev, blk, c); |
| 26321 | + bi->pages_in_use++; |
| 26322 | + |
| 26323 | + in = yaffs_find_or_create_by_number(dev, |
| 26324 | + tags. |
| 26325 | + obj_id, |
| 26326 | + YAFFS_OBJECT_TYPE_FILE); |
| 26327 | + if (!in) { |
| 26328 | + /* Out of memory */ |
| 26329 | + alloc_failed = 1; |
| 26330 | + } |
| 26331 | + |
| 26332 | + if (in && |
| 26333 | + in->variant_type == YAFFS_OBJECT_TYPE_FILE |
| 26334 | + && chunkBase < in->variant.file_variant.shrink_size) { |
| 26335 | + /* This has not been invalidated by a resize */ |
| 26336 | + if (!yaffs_put_chunk_in_file(in, tags.chunk_id, chunk, -1)) { |
| 26337 | + alloc_failed = 1; |
| 26338 | + } |
| 26339 | + |
| 26340 | + /* File size is calculated by looking at the data chunks if we have not |
| 26341 | + * seen an object header yet. Stop this practice once we find an object header. |
| 26342 | + */ |
| 26343 | + endpos = chunkBase + tags.n_bytes; |
| 26344 | + |
| 26345 | + if (!in->valid && /* have not got an object header yet */ |
| 26346 | + in->variant.file_variant.scanned_size < endpos) { |
| 26347 | + in->variant.file_variant.scanned_size = endpos; |
| 26348 | + in->variant.file_variant.file_size = endpos; |
| 26349 | + } |
| 26350 | + |
| 26351 | + } else if (in) { |
| 26352 | + /* This chunk has been invalidated by a resize, or a past file deletion |
| 26353 | + * so delete the chunk*/ |
| 26354 | + yaffs_chunk_del(dev, chunk, 1, __LINE__); |
| 26355 | + |
| 26356 | + } |
| 26357 | + } else { |
| 26358 | + /* chunk_id == 0, so it is an ObjectHeader. |
| 26359 | + * Thus, we read in the object header and make the object |
| 26360 | + */ |
| 26361 | + foundChunksInBlock = 1; |
| 26362 | + |
| 26363 | + yaffs_set_chunk_bit(dev, blk, c); |
| 26364 | + bi->pages_in_use++; |
| 26365 | + |
| 26366 | + oh = NULL; |
| 26367 | + in = NULL; |
| 26368 | + |
| 26369 | + if (tags.extra_available) { |
| 26370 | + in = yaffs_find_or_create_by_number(dev, |
| 26371 | + tags.obj_id, |
| 26372 | + tags.extra_obj_type); |
| 26373 | + if (!in) |
| 26374 | + alloc_failed = 1; |
| 26375 | + } |
| 26376 | + |
| 26377 | + if (!in || |
| 26378 | + (!in->valid && dev->param.disable_lazy_load) || |
| 26379 | + tags.extra_shadows || |
| 26380 | + (!in->valid && |
| 26381 | + (tags.obj_id == YAFFS_OBJECTID_ROOT || |
| 26382 | + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) { |
| 26383 | + |
| 26384 | + /* If we don't have valid info then we need to read the chunk |
| 26385 | + * TODO In future we can probably defer reading the chunk and |
| 26386 | + * living with invalid data until needed. |
| 26387 | + */ |
| 26388 | + |
| 26389 | + result = yaffs_rd_chunk_tags_nand(dev, |
| 26390 | + chunk, |
| 26391 | + chunkData, |
| 26392 | + NULL); |
| 26393 | + |
| 26394 | + oh = (yaffs_obj_header *) chunkData; |
| 26395 | + |
| 26396 | + if (dev->param.inband_tags) { |
| 26397 | + /* Fix up the header if they got corrupted by inband tags */ |
| 26398 | + oh->shadows_obj = oh->inband_shadowed_obj_id; |
| 26399 | + oh->is_shrink = oh->inband_is_shrink; |
| 26400 | + } |
| 26401 | + |
| 26402 | + if (!in) { |
| 26403 | + in = yaffs_find_or_create_by_number(dev, tags.obj_id, oh->type); |
| 26404 | + if (!in) |
| 26405 | + alloc_failed = 1; |
| 26406 | + } |
| 26407 | + |
| 26408 | + } |
| 26409 | + |
| 26410 | + if (!in) { |
| 26411 | + /* TODO Hoosterman we have a problem! */ |
| 26412 | + T(YAFFS_TRACE_ERROR, |
| 26413 | + (TSTR |
| 26414 | + ("yaffs tragedy: Could not make object for object %d at chunk %d during scan" |
| 26415 | + TENDSTR), tags.obj_id, chunk)); |
| 26416 | + continue; |
| 26417 | + } |
| 26418 | + |
| 26419 | + if (in->valid) { |
| 26420 | + /* We have already filled this one. |
| 26421 | + * We have a duplicate that will be discarded, but |
| 26422 | + * we first have to suck out resize info if it is a file. |
| 26423 | + */ |
| 26424 | + |
| 26425 | + if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) && |
| 26426 | + ((oh && |
| 26427 | + oh->type == YAFFS_OBJECT_TYPE_FILE) || |
| 26428 | + (tags.extra_available && |
| 26429 | + tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE))) { |
| 26430 | + __u32 thisSize = |
| 26431 | + (oh) ? oh->file_size : tags. |
| 26432 | + extra_length; |
| 26433 | + __u32 parent_obj_id = |
| 26434 | + (oh) ? oh-> |
| 26435 | + parent_obj_id : tags. |
| 26436 | + extra_parent_id; |
| 26437 | + |
| 26438 | + |
| 26439 | + is_shrink = |
| 26440 | + (oh) ? oh->is_shrink : tags. |
| 26441 | + extra_is_shrink; |
| 26442 | + |
| 26443 | + /* If it is deleted (unlinked at start also means deleted) |
| 26444 | + * we treat the file size as being zeroed at this point. |
| 26445 | + */ |
| 26446 | + if (parent_obj_id == |
| 26447 | + YAFFS_OBJECTID_DELETED |
| 26448 | + || parent_obj_id == |
| 26449 | + YAFFS_OBJECTID_UNLINKED) { |
| 26450 | + thisSize = 0; |
| 26451 | + is_shrink = 1; |
| 26452 | + } |
| 26453 | + |
| 26454 | + if (is_shrink && in->variant.file_variant.shrink_size > thisSize) |
| 26455 | + in->variant.file_variant.shrink_size = thisSize; |
| 26456 | + |
| 26457 | + if (is_shrink) |
| 26458 | + bi->has_shrink_hdr = 1; |
| 26459 | + |
| 26460 | + } |
| 26461 | + /* Use existing - destroy this one. */ |
| 26462 | + yaffs_chunk_del(dev, chunk, 1, __LINE__); |
| 26463 | + |
| 26464 | + } |
| 26465 | + |
| 26466 | + if (!in->valid && in->variant_type != |
| 26467 | + (oh ? oh->type : tags.extra_obj_type)) |
| 26468 | + T(YAFFS_TRACE_ERROR, ( |
| 26469 | + TSTR("yaffs tragedy: Bad object type, " |
| 26470 | + TCONT("%d != %d, for object %d at chunk ") |
| 26471 | + TCONT("%d during scan") |
| 26472 | + TENDSTR), oh ? |
| 26473 | + oh->type : tags.extra_obj_type, |
| 26474 | + in->variant_type, tags.obj_id, |
| 26475 | + chunk)); |
| 26476 | + |
| 26477 | + if (!in->valid && |
| 26478 | + (tags.obj_id == YAFFS_OBJECTID_ROOT || |
| 26479 | + tags.obj_id == |
| 26480 | + YAFFS_OBJECTID_LOSTNFOUND)) { |
| 26481 | + /* We only load some info, don't fiddle with directory structure */ |
| 26482 | + in->valid = 1; |
| 26483 | + |
| 26484 | + if (oh) { |
| 26485 | + |
| 26486 | + in->yst_mode = oh->yst_mode; |
| 26487 | +#ifdef CONFIG_YAFFS_WINCE |
| 26488 | + in->win_atime[0] = oh->win_atime[0]; |
| 26489 | + in->win_ctime[0] = oh->win_ctime[0]; |
| 26490 | + in->win_mtime[0] = oh->win_mtime[0]; |
| 26491 | + in->win_atime[1] = oh->win_atime[1]; |
| 26492 | + in->win_ctime[1] = oh->win_ctime[1]; |
| 26493 | + in->win_mtime[1] = oh->win_mtime[1]; |
| 26494 | +#else |
| 26495 | + in->yst_uid = oh->yst_uid; |
| 26496 | + in->yst_gid = oh->yst_gid; |
| 26497 | + in->yst_atime = oh->yst_atime; |
| 26498 | + in->yst_mtime = oh->yst_mtime; |
| 26499 | + in->yst_ctime = oh->yst_ctime; |
| 26500 | + in->yst_rdev = oh->yst_rdev; |
| 26501 | + |
| 26502 | + in->lazy_loaded = 0; |
| 26503 | + |
| 26504 | +#endif |
| 26505 | + } else |
| 26506 | + in->lazy_loaded = 1; |
| 26507 | + |
| 26508 | + in->hdr_chunk = chunk; |
| 26509 | + |
| 26510 | + } else if (!in->valid) { |
| 26511 | + /* we need to load this info */ |
| 26512 | + |
| 26513 | + in->valid = 1; |
| 26514 | + in->hdr_chunk = chunk; |
| 26515 | + |
| 26516 | + if (oh) { |
| 26517 | + in->variant_type = oh->type; |
| 26518 | + |
| 26519 | + in->yst_mode = oh->yst_mode; |
| 26520 | +#ifdef CONFIG_YAFFS_WINCE |
| 26521 | + in->win_atime[0] = oh->win_atime[0]; |
| 26522 | + in->win_ctime[0] = oh->win_ctime[0]; |
| 26523 | + in->win_mtime[0] = oh->win_mtime[0]; |
| 26524 | + in->win_atime[1] = oh->win_atime[1]; |
| 26525 | + in->win_ctime[1] = oh->win_ctime[1]; |
| 26526 | + in->win_mtime[1] = oh->win_mtime[1]; |
| 26527 | +#else |
| 26528 | + in->yst_uid = oh->yst_uid; |
| 26529 | + in->yst_gid = oh->yst_gid; |
| 26530 | + in->yst_atime = oh->yst_atime; |
| 26531 | + in->yst_mtime = oh->yst_mtime; |
| 26532 | + in->yst_ctime = oh->yst_ctime; |
| 26533 | + in->yst_rdev = oh->yst_rdev; |
| 26534 | +#endif |
| 26535 | + |
| 26536 | + if (oh->shadows_obj > 0) |
| 26537 | + yaffs_handle_shadowed_obj(dev, |
| 26538 | + oh-> |
| 26539 | + shadows_obj, |
| 26540 | + 1); |
| 26541 | + |
| 26542 | + |
| 26543 | + |
| 26544 | + yaffs_set_obj_name_from_oh(in, oh); |
| 26545 | + parent = |
| 26546 | + yaffs_find_or_create_by_number |
| 26547 | + (dev, oh->parent_obj_id, |
| 26548 | + YAFFS_OBJECT_TYPE_DIRECTORY); |
| 26549 | + |
| 26550 | + file_size = oh->file_size; |
| 26551 | + is_shrink = oh->is_shrink; |
| 26552 | + equiv_id = oh->equiv_id; |
| 26553 | + |
| 26554 | + } else { |
| 26555 | + in->variant_type = tags.extra_obj_type; |
| 26556 | + parent = |
| 26557 | + yaffs_find_or_create_by_number |
| 26558 | + (dev, tags.extra_parent_id, |
| 26559 | + YAFFS_OBJECT_TYPE_DIRECTORY); |
| 26560 | + file_size = tags.extra_length; |
| 26561 | + is_shrink = tags.extra_is_shrink; |
| 26562 | + equiv_id = tags.extra_equiv_id; |
| 26563 | + in->lazy_loaded = 1; |
| 26564 | + |
| 26565 | + } |
| 26566 | + in->dirty = 0; |
| 26567 | + |
| 26568 | + if (!parent) |
| 26569 | + alloc_failed = 1; |
| 26570 | + |
| 26571 | + /* directory stuff... |
| 26572 | + * hook up to parent |
| 26573 | + */ |
| 26574 | + |
| 26575 | + if (parent && parent->variant_type == |
| 26576 | + YAFFS_OBJECT_TYPE_UNKNOWN) { |
| 26577 | + /* Set up as a directory */ |
| 26578 | + parent->variant_type = |
| 26579 | + YAFFS_OBJECT_TYPE_DIRECTORY; |
| 26580 | + YINIT_LIST_HEAD(&parent->variant. |
| 26581 | + dir_variant. |
| 26582 | + children); |
| 26583 | + } else if (!parent || parent->variant_type != |
| 26584 | + YAFFS_OBJECT_TYPE_DIRECTORY) { |
| 26585 | + /* Hoosterman, another problem.... |
| 26586 | + * We're trying to use a non-directory as a directory |
| 26587 | + */ |
| 26588 | + |
| 26589 | + T(YAFFS_TRACE_ERROR, |
| 26590 | + (TSTR |
| 26591 | + ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." |
| 26592 | + TENDSTR))); |
| 26593 | + parent = dev->lost_n_found; |
| 26594 | + } |
| 26595 | + |
| 26596 | + yaffs_add_obj_to_dir(parent, in); |
| 26597 | + |
| 26598 | + itsUnlinked = (parent == dev->del_dir) || |
| 26599 | + (parent == dev->unlinked_dir); |
| 26600 | + |
| 26601 | + if (is_shrink) { |
| 26602 | + /* Mark the block as having a shrinkHeader */ |
| 26603 | + bi->has_shrink_hdr = 1; |
| 26604 | + } |
| 26605 | + |
| 26606 | + /* Note re hardlinks. |
| 26607 | + * Since we might scan a hardlink before its equivalent object is scanned |
| 26608 | + * we put them all in a list. |
| 26609 | + * After scanning is complete, we should have all the objects, so we run |
| 26610 | + * through this list and fix up all the chains. |
| 26611 | + */ |
| 26612 | + |
| 26613 | + switch (in->variant_type) { |
| 26614 | + case YAFFS_OBJECT_TYPE_UNKNOWN: |
| 26615 | + /* Todo got a problem */ |
| 26616 | + break; |
| 26617 | + case YAFFS_OBJECT_TYPE_FILE: |
| 26618 | + |
| 26619 | + if (in->variant.file_variant. |
| 26620 | + scanned_size < file_size) { |
| 26621 | + /* This covers the case where the file size is greater |
| 26622 | + * than where the data is |
| 26623 | + * This will happen if the file is resized to be larger |
| 26624 | + * than its current data extents. |
| 26625 | + */ |
| 26626 | + in->variant.file_variant.file_size = file_size; |
| 26627 | + in->variant.file_variant.scanned_size = file_size; |
| 26628 | + } |
| 26629 | + |
| 26630 | + if (in->variant.file_variant.shrink_size > file_size) |
| 26631 | + in->variant.file_variant.shrink_size = file_size; |
| 26632 | + |
| 26633 | + |
| 26634 | + break; |
| 26635 | + case YAFFS_OBJECT_TYPE_HARDLINK: |
| 26636 | + if (!itsUnlinked) { |
| 26637 | + in->variant.hardlink_variant.equiv_id = |
| 26638 | + equiv_id; |
| 26639 | + in->hard_links.next = |
| 26640 | + (struct ylist_head *) hard_list; |
| 26641 | + hard_list = in; |
| 26642 | + } |
| 26643 | + break; |
| 26644 | + case YAFFS_OBJECT_TYPE_DIRECTORY: |
| 26645 | + /* Do nothing */ |
| 26646 | + break; |
| 26647 | + case YAFFS_OBJECT_TYPE_SPECIAL: |
| 26648 | + /* Do nothing */ |
| 26649 | + break; |
| 26650 | + case YAFFS_OBJECT_TYPE_SYMLINK: |
| 26651 | + if (oh) { |
| 26652 | + in->variant.symlink_variant.alias = |
| 26653 | + yaffs_clone_str(oh->alias); |
| 26654 | + if (!in->variant.symlink_variant.alias) |
| 26655 | + alloc_failed = 1; |
| 26656 | + } |
| 26657 | + break; |
| 26658 | + } |
| 26659 | + |
| 26660 | + } |
| 26661 | + |
| 26662 | + } |
| 26663 | + |
| 26664 | + } /* End of scanning for each chunk */ |
| 26665 | + |
| 26666 | + if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { |
| 26667 | + /* If we got this far while scanning, then the block is fully allocated. */ |
| 26668 | + state = YAFFS_BLOCK_STATE_FULL; |
| 26669 | + } |
| 26670 | + |
| 26671 | + |
| 26672 | + bi->block_state = state; |
| 26673 | + |
| 26674 | + /* Now let's see if it was dirty */ |
| 26675 | + if (bi->pages_in_use == 0 && |
| 26676 | + !bi->has_shrink_hdr && |
| 26677 | + bi->block_state == YAFFS_BLOCK_STATE_FULL) { |
| 26678 | + yaffs_block_became_dirty(dev, blk); |
| 26679 | + } |
| 26680 | + |
| 26681 | + } |
| 26682 | + |
| 26683 | + yaffs_skip_rest_of_block(dev); |
| 26684 | + |
| 26685 | + if (altBlockIndex) |
| 26686 | + YFREE_ALT(blockIndex); |
| 26687 | + else |
| 26688 | + YFREE(blockIndex); |
| 26689 | + |
| 26690 | + /* Ok, we've done all the scanning. |
| 26691 | + * Fix up the hard link chains. |
| 26692 | + * We should now have scanned all the objects, now it's time to add these |
| 26693 | + * hardlinks. |
| 26694 | + */ |
| 26695 | + yaffs_link_fixup(dev, hard_list); |
| 26696 | + |
| 26697 | + |
| 26698 | + yaffs_release_temp_buffer(dev, chunkData, __LINE__); |
| 26699 | + |
| 26700 | + if (alloc_failed) |
| 26701 | + return YAFFS_FAIL; |
| 26702 | + |
| 26703 | + T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_scan_backwards ends" TENDSTR))); |
| 26704 | + |
| 26705 | + return YAFFS_OK; |
| 26706 | +} |
| 26707 | --- /dev/null |
| 26708 | +++ b/fs/yaffs2/yaffs_yaffs2.h |
| 26709 | @@ -0,0 +1,36 @@ |
| 26710 | +/* |
| 26711 | + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. |
| 26712 | + * |
| 26713 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 26714 | + * for Toby Churchill Ltd and Brightstar Engineering |
| 26715 | + * |
| 26716 | + * Created by Charles Manning <charles@aleph1.co.uk> |
| 26717 | + * |
| 26718 | + * This program is free software; you can redistribute it and/or modify |
| 26719 | + * it under the terms of the GNU General Public License version 2 as |
| 26720 | + * published by the Free Software Foundation. |
| 26721 | + */ |
| 26722 | + |
| 26723 | +#ifndef __YAFFS_YAFFS2_H__ |
| 26724 | +#define __YAFFS_YAFFS2_H__ |
| 26725 | + |
| 26726 | +#include "yaffs_guts.h" |
| 26727 | + |
| 26728 | +void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev); |
| 26729 | +void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev); |
| 26730 | +void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi); |
| 26731 | +void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi); |
| 26732 | +int yaffs_block_ok_for_gc(yaffs_dev_t *dev, yaffs_block_info_t *bi); |
| 26733 | +__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev); |
| 26734 | +int yaffs2_checkpt_required(yaffs_dev_t *dev); |
| 26735 | +int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev); |
| 26736 | + |
| 26737 | + |
| 26738 | +void yaffs2_checkpt_invalidate(yaffs_dev_t *dev); |
| 26739 | +int yaffs2_checkpt_save(yaffs_dev_t *dev); |
| 26740 | +int yaffs2_checkpt_restore(yaffs_dev_t *dev); |
| 26741 | + |
| 26742 | +int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size); |
| 26743 | +int yaffs2_scan_backwards(yaffs_dev_t *dev); |
| 26744 | + |
| 26745 | +#endif |
| 26746 | --- a/fs/yaffs2/yportenv.h |
| 26747 | +++ b/fs/yaffs2/yportenv.h |
| 26748 | @@ -1,7 +1,7 @@ |
| 26749 | /* |
| 26750 | * YAFFS: Yet another Flash File System . A NAND-flash specific file system. |
| 26751 | * |
| 26752 | - * Copyright (C) 2002-2007 Aleph One Ltd. |
| 26753 | + * Copyright (C) 2002-2010 Aleph One Ltd. |
| 26754 | * for Toby Churchill Ltd and Brightstar Engineering |
| 26755 | * |
| 26756 | * Created by Charles Manning <charles@aleph1.co.uk> |
| 26757 | @@ -41,12 +41,14 @@ |
| 26758 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) |
| 26759 | #include <linux/config.h> |
| 26760 | #endif |
| 26761 | + |
| 26762 | #include <linux/kernel.h> |
| 26763 | #include <linux/mm.h> |
| 26764 | #include <linux/sched.h> |
| 26765 | #include <linux/string.h> |
| 26766 | #include <linux/slab.h> |
| 26767 | #include <linux/vmalloc.h> |
| 26768 | +#include <linux/xattr.h> |
| 26769 | |
| 26770 | #define YCHAR char |
| 26771 | #define YUCHAR unsigned char |
| 26772 | @@ -55,11 +57,11 @@ |
| 26773 | #define yaffs_strcpy(a, b) strcpy(a, b) |
| 26774 | #define yaffs_strncpy(a, b, c) strncpy(a, b, c) |
| 26775 | #define yaffs_strncmp(a, b, c) strncmp(a, b, c) |
| 26776 | -#define yaffs_strlen(s) strlen(s) |
| 26777 | +#define yaffs_strnlen(s,m) strnlen(s,m) |
| 26778 | #define yaffs_sprintf sprintf |
| 26779 | #define yaffs_toupper(a) toupper(a) |
| 26780 | |
| 26781 | -#define Y_INLINE inline |
| 26782 | +#define Y_INLINE __inline__ |
| 26783 | |
| 26784 | #define YAFFS_LOSTNFOUND_NAME "lost+found" |
| 26785 | #define YAFFS_LOSTNFOUND_PREFIX "obj" |
| 26786 | @@ -71,11 +73,11 @@ |
| 26787 | #define YFREE_ALT(x) vfree(x) |
| 26788 | #define YMALLOC_DMA(x) YMALLOC(x) |
| 26789 | |
| 26790 | -/* KR - added for use in scan so processes aren't blocked indefinitely. */ |
| 26791 | #define YYIELD() schedule() |
| 26792 | +#define Y_DUMP_STACK() dump_stack() |
| 26793 | |
| 26794 | -#define YAFFS_ROOT_MODE 0666 |
| 26795 | -#define YAFFS_LOSTNFOUND_MODE 0666 |
| 26796 | +#define YAFFS_ROOT_MODE 0755 |
| 26797 | +#define YAFFS_LOSTNFOUND_MODE 0700 |
| 26798 | |
| 26799 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) |
| 26800 | #define Y_CURRENT_TIME CURRENT_TIME.tv_sec |
| 26801 | @@ -85,19 +87,14 @@ |
| 26802 | #define Y_TIME_CONVERT(x) (x) |
| 26803 | #endif |
| 26804 | |
| 26805 | -#define yaffs_SumCompare(x, y) ((x) == (y)) |
| 26806 | +#define yaffs_sum_cmp(x, y) ((x) == (y)) |
| 26807 | #define yaffs_strcmp(a, b) strcmp(a, b) |
| 26808 | |
| 26809 | #define TENDSTR "\n" |
| 26810 | -#define TSTR(x) KERN_WARNING x |
| 26811 | +#define TSTR(x) KERN_DEBUG x |
| 26812 | #define TCONT(x) x |
| 26813 | #define TOUT(p) printk p |
| 26814 | |
| 26815 | -#define yaffs_trace(mask, fmt, args...) \ |
| 26816 | - do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \ |
| 26817 | - printk(KERN_WARNING "yaffs: " fmt, ## args); \ |
| 26818 | - } while (0) |
| 26819 | - |
| 26820 | #define compile_time_assertion(assertion) \ |
| 26821 | ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) |
| 26822 | |
| 26823 | @@ -116,7 +113,6 @@ |
| 26824 | #include "stdio.h" |
| 26825 | #include "string.h" |
| 26826 | |
| 26827 | -#include "devextras.h" |
| 26828 | |
| 26829 | #define YMALLOC(x) malloc(x) |
| 26830 | #define YFREE(x) free(x) |
| 26831 | @@ -129,7 +125,7 @@ |
| 26832 | #define yaffs_strcat(a, b) strcat(a, b) |
| 26833 | #define yaffs_strcpy(a, b) strcpy(a, b) |
| 26834 | #define yaffs_strncpy(a, b, c) strncpy(a, b, c) |
| 26835 | -#define yaffs_strlen(s) strlen(s) |
| 26836 | +#define yaffs_strnlen(s,m) strnlen(s,m) |
| 26837 | #define yaffs_sprintf sprintf |
| 26838 | #define yaffs_toupper(a) toupper(a) |
| 26839 | |
| 26840 | @@ -146,10 +142,10 @@ |
| 26841 | #define YAFFS_LOSTNFOUND_PREFIX "obj" |
| 26842 | /* #define YPRINTF(x) printf x */ |
| 26843 | |
| 26844 | -#define YAFFS_ROOT_MODE 0666 |
| 26845 | -#define YAFFS_LOSTNFOUND_MODE 0666 |
| 26846 | +#define YAFFS_ROOT_MODE 0755 |
| 26847 | +#define YAFFS_LOSTNFOUND_MODE 0700 |
| 26848 | |
| 26849 | -#define yaffs_SumCompare(x, y) ((x) == (y)) |
| 26850 | +#define yaffs_sum_cmp(x, y) ((x) == (y)) |
| 26851 | #define yaffs_strcmp(a, b) strcmp(a, b) |
| 26852 | |
| 26853 | #else |
| 26854 | @@ -158,46 +154,180 @@ |
| 26855 | |
| 26856 | #endif |
| 26857 | |
| 26858 | -/* see yaffs_fs.c */ |
| 26859 | -extern unsigned int yaffs_traceMask; |
| 26860 | -extern unsigned int yaffs_wr_attempts; |
| 26861 | +#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE) |
| 26862 | |
| 26863 | -/* |
| 26864 | - * Tracing flags. |
| 26865 | - * The flags masked in YAFFS_TRACE_ALWAYS are always traced. |
| 26866 | - */ |
| 26867 | +#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES |
| 26868 | + |
| 26869 | +#ifndef O_RDONLY |
| 26870 | +#define O_RDONLY 00 |
| 26871 | +#endif |
| 26872 | + |
| 26873 | +#ifndef O_WRONLY |
| 26874 | +#define O_WRONLY 01 |
| 26875 | +#endif |
| 26876 | + |
| 26877 | +#ifndef O_RDWR |
| 26878 | +#define O_RDWR 02 |
| 26879 | +#endif |
| 26880 | + |
| 26881 | +#ifndef O_CREAT |
| 26882 | +#define O_CREAT 0100 |
| 26883 | +#endif |
| 26884 | + |
| 26885 | +#ifndef O_EXCL |
| 26886 | +#define O_EXCL 0200 |
| 26887 | +#endif |
| 26888 | + |
| 26889 | +#ifndef O_TRUNC |
| 26890 | +#define O_TRUNC 01000 |
| 26891 | +#endif |
| 26892 | + |
| 26893 | +#ifndef O_APPEND |
| 26894 | +#define O_APPEND 02000 |
| 26895 | +#endif |
| 26896 | + |
| 26897 | +#ifndef SEEK_SET |
| 26898 | +#define SEEK_SET 0 |
| 26899 | +#endif |
| 26900 | + |
| 26901 | +#ifndef SEEK_CUR |
| 26902 | +#define SEEK_CUR 1 |
| 26903 | +#endif |
| 26904 | + |
| 26905 | +#ifndef SEEK_END |
| 26906 | +#define SEEK_END 2 |
| 26907 | +#endif |
| 26908 | + |
| 26909 | +#ifndef EBUSY |
| 26910 | +#define EBUSY 16 |
| 26911 | +#endif |
| 26912 | + |
| 26913 | +#ifndef ENODEV |
| 26914 | +#define ENODEV 19 |
| 26915 | +#endif |
| 26916 | + |
| 26917 | +#ifndef EINVAL |
| 26918 | +#define EINVAL 22 |
| 26919 | +#endif |
| 26920 | + |
| 26921 | +#ifndef EBADF |
| 26922 | +#define EBADF 9 |
| 26923 | +#endif |
| 26924 | + |
| 26925 | +#ifndef EACCES |
| 26926 | +#define EACCES 13 |
| 26927 | +#endif |
| 26928 | + |
| 26929 | +#ifndef EXDEV |
| 26930 | +#define EXDEV 18 |
| 26931 | +#endif |
| 26932 | + |
| 26933 | +#ifndef ENOENT |
| 26934 | +#define ENOENT 2 |
| 26935 | +#endif |
| 26936 | + |
| 26937 | +#ifndef ENOSPC |
| 26938 | +#define ENOSPC 28 |
| 26939 | +#endif |
| 26940 | + |
| 26941 | +#ifndef ERANGE |
| 26942 | +#define ERANGE 34 |
| 26943 | +#endif |
| 26944 | + |
| 26945 | +#ifndef ENODATA |
| 26946 | +#define ENODATA 61 |
| 26947 | +#endif |
| 26948 | + |
| 26949 | +#ifndef ENOTEMPTY |
| 26950 | +#define ENOTEMPTY 39 |
| 26951 | +#endif |
| 26952 | + |
| 26953 | +#ifndef ENAMETOOLONG |
| 26954 | +#define ENAMETOOLONG 36 |
| 26955 | +#endif |
| 26956 | + |
| 26957 | +#ifndef ENOMEM |
| 26958 | +#define ENOMEM 12 |
| 26959 | +#endif |
| 26960 | + |
| 26961 | +#ifndef EEXIST |
| 26962 | +#define EEXIST 17 |
| 26963 | +#endif |
| 26964 | + |
| 26965 | +#ifndef ENOTDIR |
| 26966 | +#define ENOTDIR 20 |
| 26967 | +#endif |
| 26968 | + |
| 26969 | +#ifndef EISDIR |
| 26970 | +#define EISDIR 21 |
| 26971 | +#endif |
| 26972 | + |
| 26973 | + |
| 26974 | +// Mode flags |
| 26975 | + |
| 26976 | +#ifndef S_IFMT |
| 26977 | +#define S_IFMT 0170000 |
| 26978 | +#endif |
| 26979 | + |
| 26980 | +#ifndef S_IFLNK |
| 26981 | +#define S_IFLNK 0120000 |
| 26982 | +#endif |
| 26983 | |
| 26984 | -#define YAFFS_TRACE_OS 0x00000002 |
| 26985 | -#define YAFFS_TRACE_ALLOCATE 0x00000004 |
| 26986 | -#define YAFFS_TRACE_SCAN 0x00000008 |
| 26987 | -#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 |
| 26988 | -#define YAFFS_TRACE_ERASE 0x00000020 |
| 26989 | -#define YAFFS_TRACE_GC 0x00000040 |
| 26990 | -#define YAFFS_TRACE_WRITE 0x00000080 |
| 26991 | -#define YAFFS_TRACE_TRACING 0x00000100 |
| 26992 | -#define YAFFS_TRACE_DELETION 0x00000200 |
| 26993 | -#define YAFFS_TRACE_BUFFERS 0x00000400 |
| 26994 | -#define YAFFS_TRACE_NANDACCESS 0x00000800 |
| 26995 | -#define YAFFS_TRACE_GC_DETAIL 0x00001000 |
| 26996 | -#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 |
| 26997 | -#define YAFFS_TRACE_MTD 0x00004000 |
| 26998 | -#define YAFFS_TRACE_CHECKPOINT 0x00008000 |
| 26999 | - |
| 27000 | -#define YAFFS_TRACE_VERIFY 0x00010000 |
| 27001 | -#define YAFFS_TRACE_VERIFY_NAND 0x00020000 |
| 27002 | -#define YAFFS_TRACE_VERIFY_FULL 0x00040000 |
| 27003 | -#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 |
| 27004 | - |
| 27005 | - |
| 27006 | -#define YAFFS_TRACE_ERROR 0x40000000 |
| 27007 | -#define YAFFS_TRACE_BUG 0x80000000 |
| 27008 | -#define YAFFS_TRACE_ALWAYS 0xF0000000 |
| 27009 | +#ifndef S_IFDIR |
| 27010 | +#define S_IFDIR 0040000 |
| 27011 | +#endif |
| 27012 | + |
| 27013 | +#ifndef S_IFREG |
| 27014 | +#define S_IFREG 0100000 |
| 27015 | +#endif |
| 27016 | |
| 27017 | +#ifndef S_IREAD |
| 27018 | +#define S_IREAD 0000400 |
| 27019 | +#endif |
| 27020 | + |
| 27021 | +#ifndef S_IWRITE |
| 27022 | +#define S_IWRITE 0000200 |
| 27023 | +#endif |
| 27024 | |
| 27025 | -#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0) |
| 27026 | +#ifndef S_IEXEC |
| 27027 | +#define S_IEXEC 0000100 |
| 27028 | +#endif |
| 27029 | + |
| 27030 | +#ifndef XATTR_CREATE |
| 27031 | +#define XATTR_CREATE 1 |
| 27032 | +#endif |
| 27033 | + |
| 27034 | +#ifndef XATTR_REPLACE |
| 27035 | +#define XATTR_REPLACE 2 |
| 27036 | +#endif |
| 27037 | + |
| 27038 | +#ifndef R_OK |
| 27039 | +#define R_OK 4 |
| 27040 | +#define W_OK 2 |
| 27041 | +#define X_OK 1 |
| 27042 | +#define F_OK 0 |
| 27043 | +#endif |
| 27044 | + |
| 27045 | +#else |
| 27046 | +#include <errno.h> |
| 27047 | +#include <sys/stat.h> |
| 27048 | +#include <fcntl.h> |
| 27049 | +#endif |
| 27050 | + |
| 27051 | +#endif |
| 27052 | + |
| 27053 | +#ifndef Y_DUMP_STACK |
| 27054 | +#define Y_DUMP_STACK() do { } while (0) |
| 27055 | +#endif |
| 27056 | |
| 27057 | #ifndef YBUG |
| 27058 | -#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0) |
| 27059 | +#define YBUG() do {\ |
| 27060 | + T(YAFFS_TRACE_BUG,\ |
| 27061 | + (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),\ |
| 27062 | + __LINE__));\ |
| 27063 | + Y_DUMP_STACK();\ |
| 27064 | +} while (0) |
| 27065 | #endif |
| 27066 | |
| 27067 | + |
| 27068 | #endif |
| 27069 | |