11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * JFFS2 -- Journalling Flash File System, Version 2. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001-2003 Red Hat, Inc. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Created by David Woodhouse <dwmw2@infradead.org> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * For licensing information, see the file 'LICENCE' in this directory. 91da177e4SLinus Torvalds * 10dae6227fSArtem B. Bityutskiy * $Id: nodelist.c,v 1.99 2005/07/15 10:13:54 dedekind Exp $ 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <linux/kernel.h> 151da177e4SLinus Torvalds #include <linux/sched.h> 161da177e4SLinus Torvalds #include <linux/fs.h> 171da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 181da177e4SLinus Torvalds #include <linux/rbtree.h> 191da177e4SLinus Torvalds #include <linux/crc32.h> 201da177e4SLinus Torvalds #include <linux/slab.h> 211da177e4SLinus Torvalds #include <linux/pagemap.h> 221da177e4SLinus Torvalds #include "nodelist.h" 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list) 251da177e4SLinus Torvalds { 261da177e4SLinus Torvalds struct jffs2_full_dirent **prev = list; 271da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_add_fd_to_list( %p, %p (->%p))\n", new, list, *list)); 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds while ((*prev) && (*prev)->nhash <= new->nhash) { 301da177e4SLinus Torvalds if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) { 311da177e4SLinus Torvalds /* Duplicate. Free one */ 321da177e4SLinus Torvalds if (new->version < (*prev)->version) { 331da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Eep! Marking new dirent node obsolete\n")); 341da177e4SLinus Torvalds D1(printk(KERN_DEBUG "New dirent is \"%s\"->ino #%u. Old is \"%s\"->ino #%u\n", new->name, new->ino, (*prev)->name, (*prev)->ino)); 351da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, new->raw); 361da177e4SLinus Torvalds jffs2_free_full_dirent(new); 371da177e4SLinus Torvalds } else { 381da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) obsolete\n", (*prev)->ino)); 391da177e4SLinus Torvalds new->next = (*prev)->next; 401da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, ((*prev)->raw)); 411da177e4SLinus Torvalds jffs2_free_full_dirent(*prev); 421da177e4SLinus Torvalds *prev = new; 431da177e4SLinus Torvalds } 441da177e4SLinus Torvalds goto out; 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds prev = &((*prev)->next); 471da177e4SLinus Torvalds } 481da177e4SLinus Torvalds new->next = *prev; 491da177e4SLinus Torvalds *prev = new; 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds out: 521da177e4SLinus Torvalds D2(while(*list) { 531da177e4SLinus Torvalds printk(KERN_DEBUG "Dirent \"%s\" (hash 0x%08x, ino #%u\n", (*list)->name, (*list)->nhash, (*list)->ino); 541da177e4SLinus Torvalds list = &(*list)->next; 551da177e4SLinus Torvalds }); 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 58e4fef661SArtem B. Bityuckiy /* 59e4fef661SArtem B. Bityuckiy * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in 60e4fef661SArtem B. Bityuckiy * order of increasing version. 611da177e4SLinus Torvalds */ 62e4fef661SArtem B. Bityuckiy static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list) 631da177e4SLinus Torvalds { 649dee7503SDavid Woodhouse struct rb_node **p = &list->rb_node; 659dee7503SDavid Woodhouse struct rb_node * parent = NULL; 669dee7503SDavid Woodhouse struct jffs2_tmp_dnode_info *this; 671da177e4SLinus Torvalds 689dee7503SDavid Woodhouse while (*p) { 699dee7503SDavid Woodhouse parent = *p; 709dee7503SDavid Woodhouse this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); 719dee7503SDavid Woodhouse 726430a8deSArtem B. Bityuckiy /* There may actually be a collision here, but it doesn't 736430a8deSArtem B. Bityuckiy actually matter. As long as the two nodes with the same 746430a8deSArtem B. Bityuckiy version are together, it's all fine. */ 759dee7503SDavid Woodhouse if (tn->version < this->version) 769dee7503SDavid Woodhouse p = &(*p)->rb_left; 779dee7503SDavid Woodhouse else 789dee7503SDavid Woodhouse p = &(*p)->rb_right; 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds 819dee7503SDavid Woodhouse rb_link_node(&tn->rb, parent, p); 829dee7503SDavid Woodhouse rb_insert_color(&tn->rb, list); 839dee7503SDavid Woodhouse } 849dee7503SDavid Woodhouse 859dee7503SDavid Woodhouse static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) 861da177e4SLinus Torvalds { 879dee7503SDavid Woodhouse struct rb_node *this; 889dee7503SDavid Woodhouse struct jffs2_tmp_dnode_info *tn; 891da177e4SLinus Torvalds 909dee7503SDavid Woodhouse this = list->rb_node; 919dee7503SDavid Woodhouse 929dee7503SDavid Woodhouse /* Now at bottom of tree */ 939dee7503SDavid Woodhouse while (this) { 949dee7503SDavid Woodhouse if (this->rb_left) 959dee7503SDavid Woodhouse this = this->rb_left; 969dee7503SDavid Woodhouse else if (this->rb_right) 979dee7503SDavid Woodhouse this = this->rb_right; 989dee7503SDavid Woodhouse else { 999dee7503SDavid Woodhouse tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb); 1009dee7503SDavid Woodhouse jffs2_free_full_dnode(tn->fn); 1019dee7503SDavid Woodhouse jffs2_free_tmp_dnode_info(tn); 1029dee7503SDavid Woodhouse 1039dee7503SDavid Woodhouse this = this->rb_parent; 1049dee7503SDavid Woodhouse if (!this) 1059dee7503SDavid Woodhouse break; 1069dee7503SDavid Woodhouse 1079dee7503SDavid Woodhouse if (this->rb_left == &tn->rb) 1089dee7503SDavid Woodhouse this->rb_left = NULL; 1099dee7503SDavid Woodhouse else if (this->rb_right == &tn->rb) 1109dee7503SDavid Woodhouse this->rb_right = NULL; 1119dee7503SDavid Woodhouse else BUG(); 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds } 1149dee7503SDavid Woodhouse list->rb_node = NULL; 1159dee7503SDavid Woodhouse } 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) 1181da177e4SLinus Torvalds { 1191da177e4SLinus Torvalds struct jffs2_full_dirent *next; 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds while (fd) { 1221da177e4SLinus Torvalds next = fd->next; 1231da177e4SLinus Torvalds jffs2_free_full_dirent(fd); 1241da177e4SLinus Torvalds fd = next; 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds /* Returns first valid node after 'ref'. May return 'ref' */ 1291da177e4SLinus Torvalds static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds while (ref && ref->next_in_ino) { 1321da177e4SLinus Torvalds if (!ref_obsolete(ref)) 1331da177e4SLinus Torvalds return ref; 1341da177e4SLinus Torvalds D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref))); 1351da177e4SLinus Torvalds ref = ref->next_in_ino; 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds return NULL; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 140dae6227fSArtem B. Bityutskiy /* 141dae6227fSArtem B. Bityutskiy * Helper function for jffs2_get_inode_nodes(). 142dae6227fSArtem B. Bityutskiy * It is called every time an directory entry node is found. 143dae6227fSArtem B. Bityutskiy * 144dae6227fSArtem B. Bityutskiy * Returns: 0 on succes; 145dae6227fSArtem B. Bityutskiy * 1 if the node should be marked obsolete; 146dae6227fSArtem B. Bityutskiy * negative error code on failure. 147dae6227fSArtem B. Bityutskiy */ 148dae6227fSArtem B. Bityutskiy static inline int 149dae6227fSArtem B. Bityutskiy read_direntry(struct jffs2_sb_info *c, 150dae6227fSArtem B. Bityutskiy struct jffs2_raw_node_ref *ref, 151dae6227fSArtem B. Bityutskiy struct jffs2_raw_dirent *rd, 152dae6227fSArtem B. Bityutskiy uint32_t read, 153dae6227fSArtem B. Bityutskiy struct jffs2_full_dirent **fdp, 154dae6227fSArtem B. Bityutskiy int32_t *latest_mctime, 155dae6227fSArtem B. Bityutskiy uint32_t *mctime_ver) 156dae6227fSArtem B. Bityutskiy { 157dae6227fSArtem B. Bityutskiy struct jffs2_full_dirent *fd; 158dae6227fSArtem B. Bityutskiy 159dae6227fSArtem B. Bityutskiy /* The direntry nodes are checked during the flash scanning */ 160dae6227fSArtem B. Bityutskiy BUG_ON(ref_flags(ref) == REF_UNCHECKED); 161dae6227fSArtem B. Bityutskiy /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ 162dae6227fSArtem B. Bityutskiy BUG_ON(ref_obsolete(ref)); 163dae6227fSArtem B. Bityutskiy 164dae6227fSArtem B. Bityutskiy /* Sanity check */ 165dae6227fSArtem B. Bityutskiy if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { 166dae6227fSArtem B. Bityutskiy printk(KERN_ERR "Error! Illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", 167dae6227fSArtem B. Bityutskiy ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); 168dae6227fSArtem B. Bityutskiy return 1; 169dae6227fSArtem B. Bityutskiy } 170dae6227fSArtem B. Bityutskiy 171dae6227fSArtem B. Bityutskiy fd = jffs2_alloc_full_dirent(rd->nsize + 1); 172dae6227fSArtem B. Bityutskiy if (unlikely(!fd)) 173dae6227fSArtem B. Bityutskiy return -ENOMEM; 174dae6227fSArtem B. Bityutskiy 175dae6227fSArtem B. Bityutskiy fd->raw = ref; 176dae6227fSArtem B. Bityutskiy fd->version = je32_to_cpu(rd->version); 177dae6227fSArtem B. Bityutskiy fd->ino = je32_to_cpu(rd->ino); 178dae6227fSArtem B. Bityutskiy fd->type = rd->type; 179dae6227fSArtem B. Bityutskiy 180dae6227fSArtem B. Bityutskiy /* Pick out the mctime of the latest dirent */ 181dae6227fSArtem B. Bityutskiy if(fd->version > *mctime_ver) { 182dae6227fSArtem B. Bityutskiy *mctime_ver = fd->version; 183dae6227fSArtem B. Bityutskiy *latest_mctime = je32_to_cpu(rd->mctime); 184dae6227fSArtem B. Bityutskiy } 185dae6227fSArtem B. Bityutskiy 186dae6227fSArtem B. Bityutskiy /* 187dae6227fSArtem B. Bityutskiy * Copy as much of the name as possible from the raw 188dae6227fSArtem B. Bityutskiy * dirent we've already read from the flash. 189dae6227fSArtem B. Bityutskiy */ 190dae6227fSArtem B. Bityutskiy if (read > sizeof(*rd)) 191dae6227fSArtem B. Bityutskiy memcpy(&fd->name[0], &rd->name[0], 192dae6227fSArtem B. Bityutskiy min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) )); 193dae6227fSArtem B. Bityutskiy 194dae6227fSArtem B. Bityutskiy /* Do we need to copy any more of the name directly from the flash? */ 195dae6227fSArtem B. Bityutskiy if (rd->nsize + sizeof(*rd) > read) { 196dae6227fSArtem B. Bityutskiy /* FIXME: point() */ 197dae6227fSArtem B. Bityutskiy int err; 198dae6227fSArtem B. Bityutskiy int already = read - sizeof(*rd); 199dae6227fSArtem B. Bityutskiy 200dae6227fSArtem B. Bityutskiy err = jffs2_flash_read(c, (ref_offset(ref)) + read, 201dae6227fSArtem B. Bityutskiy rd->nsize - already, &read, &fd->name[already]); 202dae6227fSArtem B. Bityutskiy if (unlikely(read != rd->nsize - already) && likely(!err)) 203dae6227fSArtem B. Bityutskiy return -EIO; 204dae6227fSArtem B. Bityutskiy 205dae6227fSArtem B. Bityutskiy if (unlikely(err)) { 206dae6227fSArtem B. Bityutskiy printk(KERN_WARNING "Read remainder of name in jffs2_get_inode_nodes(): error %d\n", err); 207dae6227fSArtem B. Bityutskiy jffs2_free_full_dirent(fd); 208dae6227fSArtem B. Bityutskiy return -EIO; 209dae6227fSArtem B. Bityutskiy } 210dae6227fSArtem B. Bityutskiy } 211dae6227fSArtem B. Bityutskiy 212dae6227fSArtem B. Bityutskiy fd->nhash = full_name_hash(fd->name, rd->nsize); 213dae6227fSArtem B. Bityutskiy fd->next = NULL; 214dae6227fSArtem B. Bityutskiy fd->name[rd->nsize] = '\0'; 215dae6227fSArtem B. Bityutskiy 216dae6227fSArtem B. Bityutskiy /* 217dae6227fSArtem B. Bityutskiy * Wheee. We now have a complete jffs2_full_dirent structure, with 218dae6227fSArtem B. Bityutskiy * the name in it and everything. Link it into the list 219dae6227fSArtem B. Bityutskiy */ 220dae6227fSArtem B. Bityutskiy D1(printk(KERN_DEBUG "Adding fd \"%s\", ino #%u\n", fd->name, fd->ino)); 221dae6227fSArtem B. Bityutskiy 222dae6227fSArtem B. Bityutskiy jffs2_add_fd_to_list(c, fd, fdp); 223dae6227fSArtem B. Bityutskiy 224dae6227fSArtem B. Bityutskiy return 0; 225dae6227fSArtem B. Bityutskiy } 226dae6227fSArtem B. Bityutskiy 227dae6227fSArtem B. Bityutskiy /* 228dae6227fSArtem B. Bityutskiy * Helper function for jffs2_get_inode_nodes(). 229dae6227fSArtem B. Bityutskiy * It is called every time an inode node is found. 230dae6227fSArtem B. Bityutskiy * 231dae6227fSArtem B. Bityutskiy * Returns: 0 on succes; 232dae6227fSArtem B. Bityutskiy * 1 if the node should be marked obsolete; 233dae6227fSArtem B. Bityutskiy * negative error code on failure. 234dae6227fSArtem B. Bityutskiy */ 235dae6227fSArtem B. Bityutskiy static inline int 236dae6227fSArtem B. Bityutskiy read_dnode(struct jffs2_sb_info *c, 237dae6227fSArtem B. Bityutskiy struct jffs2_raw_node_ref *ref, 238dae6227fSArtem B. Bityutskiy struct jffs2_raw_inode *rd, 239dae6227fSArtem B. Bityutskiy uint32_t read, 240dae6227fSArtem B. Bityutskiy struct rb_root *tnp, 241dae6227fSArtem B. Bityutskiy int32_t *latest_mctime, 242dae6227fSArtem B. Bityutskiy uint32_t *mctime_ver) 243dae6227fSArtem B. Bityutskiy { 244dae6227fSArtem B. Bityutskiy struct jffs2_eraseblock *jeb; 245dae6227fSArtem B. Bityutskiy struct jffs2_tmp_dnode_info *tn; 246dae6227fSArtem B. Bityutskiy 247dae6227fSArtem B. Bityutskiy /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ 248dae6227fSArtem B. Bityutskiy BUG_ON(ref_obsolete(ref)); 249dae6227fSArtem B. Bityutskiy 250dae6227fSArtem B. Bityutskiy /* If we've never checked the CRCs on this node, check them now */ 251dae6227fSArtem B. Bityutskiy if (ref_flags(ref) == REF_UNCHECKED) { 252dae6227fSArtem B. Bityutskiy uint32_t crc, len; 253dae6227fSArtem B. Bityutskiy 254dae6227fSArtem B. Bityutskiy crc = crc32(0, rd, sizeof(*rd) - 8); 255dae6227fSArtem B. Bityutskiy if (unlikely(crc != je32_to_cpu(rd->node_crc))) { 256dae6227fSArtem B. Bityutskiy printk(KERN_WARNING "Header CRC failed on node at %#08x: read %#08x, calculated %#08x\n", 257dae6227fSArtem B. Bityutskiy ref_offset(ref), je32_to_cpu(rd->node_crc), crc); 258dae6227fSArtem B. Bityutskiy return 1; 259dae6227fSArtem B. Bityutskiy } 260dae6227fSArtem B. Bityutskiy 261dae6227fSArtem B. Bityutskiy /* Sanity checks */ 262dae6227fSArtem B. Bityutskiy if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) || 263dae6227fSArtem B. Bityutskiy unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) { 264dae6227fSArtem B. Bityutskiy printk(KERN_WARNING "Inode corrupted at %#08x, totlen %d, #ino %d, version %d, " 265dae6227fSArtem B. Bityutskiy "isize %d, csize %d, dsize %d \n", 266dae6227fSArtem B. Bityutskiy ref_offset(ref), je32_to_cpu(rd->totlen), je32_to_cpu(rd->ino), 267dae6227fSArtem B. Bityutskiy je32_to_cpu(rd->version), je32_to_cpu(rd->isize), 268dae6227fSArtem B. Bityutskiy je32_to_cpu(rd->csize), je32_to_cpu(rd->dsize)); 269dae6227fSArtem B. Bityutskiy return 1; 270dae6227fSArtem B. Bityutskiy } 271dae6227fSArtem B. Bityutskiy 272dae6227fSArtem B. Bityutskiy if (rd->compr != JFFS2_COMPR_ZERO && je32_to_cpu(rd->csize)) { 273dae6227fSArtem B. Bityutskiy unsigned char *buf = NULL; 274dae6227fSArtem B. Bityutskiy uint32_t pointed = 0; 275dae6227fSArtem B. Bityutskiy int err; 276dae6227fSArtem B. Bityutskiy #ifndef __ECOS 277dae6227fSArtem B. Bityutskiy if (c->mtd->point) { 278dae6227fSArtem B. Bityutskiy err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize), 279dae6227fSArtem B. Bityutskiy &read, &buf); 280dae6227fSArtem B. Bityutskiy if (unlikely(read < je32_to_cpu(rd->csize)) && likely(!err)) { 281dae6227fSArtem B. Bityutskiy D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", read)); 282dae6227fSArtem B. Bityutskiy c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd), 283dae6227fSArtem B. Bityutskiy je32_to_cpu(rd->csize)); 284dae6227fSArtem B. Bityutskiy } else if (unlikely(err)){ 285dae6227fSArtem B. Bityutskiy D1(printk(KERN_DEBUG "MTD point failed %d\n", err)); 286dae6227fSArtem B. Bityutskiy } else 287dae6227fSArtem B. Bityutskiy pointed = 1; /* succefully pointed to device */ 288dae6227fSArtem B. Bityutskiy } 289dae6227fSArtem B. Bityutskiy #endif 290dae6227fSArtem B. Bityutskiy if(!pointed){ 291dae6227fSArtem B. Bityutskiy buf = kmalloc(je32_to_cpu(rd->csize), GFP_KERNEL); 292dae6227fSArtem B. Bityutskiy if (!buf) 293dae6227fSArtem B. Bityutskiy return -ENOMEM; 294dae6227fSArtem B. Bityutskiy 295dae6227fSArtem B. Bityutskiy err = jffs2_flash_read(c, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize), 296dae6227fSArtem B. Bityutskiy &read, buf); 297dae6227fSArtem B. Bityutskiy if (unlikely(read != je32_to_cpu(rd->csize)) && likely(!err)) 298dae6227fSArtem B. Bityutskiy err = -EIO; 299dae6227fSArtem B. Bityutskiy if (err) { 300dae6227fSArtem B. Bityutskiy kfree(buf); 301dae6227fSArtem B. Bityutskiy return err; 302dae6227fSArtem B. Bityutskiy } 303dae6227fSArtem B. Bityutskiy } 304dae6227fSArtem B. Bityutskiy crc = crc32(0, buf, je32_to_cpu(rd->csize)); 305dae6227fSArtem B. Bityutskiy if(!pointed) 306dae6227fSArtem B. Bityutskiy kfree(buf); 307dae6227fSArtem B. Bityutskiy #ifndef __ECOS 308dae6227fSArtem B. Bityutskiy else 309dae6227fSArtem B. Bityutskiy c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize)); 310dae6227fSArtem B. Bityutskiy #endif 311dae6227fSArtem B. Bityutskiy 312dae6227fSArtem B. Bityutskiy if (crc != je32_to_cpu(rd->data_crc)) { 313dae6227fSArtem B. Bityutskiy printk(KERN_NOTICE "Data CRC failed on node at %#08x: read %#08x, calculated %#08x\n", 314dae6227fSArtem B. Bityutskiy ref_offset(ref), je32_to_cpu(rd->data_crc), crc); 315dae6227fSArtem B. Bityutskiy return 1; 316dae6227fSArtem B. Bityutskiy } 317dae6227fSArtem B. Bityutskiy 318dae6227fSArtem B. Bityutskiy } 319dae6227fSArtem B. Bityutskiy 320dae6227fSArtem B. Bityutskiy /* Mark the node as having been checked and fix the accounting accordingly */ 321dae6227fSArtem B. Bityutskiy jeb = &c->blocks[ref->flash_offset / c->sector_size]; 322dae6227fSArtem B. Bityutskiy len = ref_totlen(c, jeb, ref); 323dae6227fSArtem B. Bityutskiy 324dae6227fSArtem B. Bityutskiy spin_lock(&c->erase_completion_lock); 325dae6227fSArtem B. Bityutskiy jeb->used_size += len; 326dae6227fSArtem B. Bityutskiy jeb->unchecked_size -= len; 327dae6227fSArtem B. Bityutskiy c->used_size += len; 328dae6227fSArtem B. Bityutskiy c->unchecked_size -= len; 329dae6227fSArtem B. Bityutskiy 330dae6227fSArtem B. Bityutskiy /* If node covers at least a whole page, or if it starts at the 331dae6227fSArtem B. Bityutskiy beginning of a page and runs to the end of the file, or if 332dae6227fSArtem B. Bityutskiy it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. 333dae6227fSArtem B. Bityutskiy 334dae6227fSArtem B. Bityutskiy If it's actually overlapped, it'll get made NORMAL (or OBSOLETE) 335dae6227fSArtem B. Bityutskiy when the overlapping node(s) get added to the tree anyway. 336dae6227fSArtem B. Bityutskiy */ 337dae6227fSArtem B. Bityutskiy if ((je32_to_cpu(rd->dsize) >= PAGE_CACHE_SIZE) || 338dae6227fSArtem B. Bityutskiy ( ((je32_to_cpu(rd->offset) & (PAGE_CACHE_SIZE-1))==0) && 339dae6227fSArtem B. Bityutskiy (je32_to_cpu(rd->dsize) + je32_to_cpu(rd->offset) == je32_to_cpu(rd->isize)))) { 340dae6227fSArtem B. Bityutskiy D1(printk(KERN_DEBUG "Marking node at %#08x REF_PRISTINE\n", ref_offset(ref))); 341dae6227fSArtem B. Bityutskiy ref->flash_offset = ref_offset(ref) | REF_PRISTINE; 342dae6227fSArtem B. Bityutskiy } else { 343dae6227fSArtem B. Bityutskiy D1(printk(KERN_DEBUG "Marking node at %#08x REF_NORMAL\n", ref_offset(ref))); 344dae6227fSArtem B. Bityutskiy ref->flash_offset = ref_offset(ref) | REF_NORMAL; 345dae6227fSArtem B. Bityutskiy } 346dae6227fSArtem B. Bityutskiy spin_unlock(&c->erase_completion_lock); 347dae6227fSArtem B. Bityutskiy } 348dae6227fSArtem B. Bityutskiy 349dae6227fSArtem B. Bityutskiy tn = jffs2_alloc_tmp_dnode_info(); 350dae6227fSArtem B. Bityutskiy if (!tn) { 351dae6227fSArtem B. Bityutskiy D1(printk(KERN_DEBUG "alloc tn failed\n")); 352dae6227fSArtem B. Bityutskiy return -ENOMEM; 353dae6227fSArtem B. Bityutskiy } 354dae6227fSArtem B. Bityutskiy 355dae6227fSArtem B. Bityutskiy tn->fn = jffs2_alloc_full_dnode(); 356dae6227fSArtem B. Bityutskiy if (!tn->fn) { 357dae6227fSArtem B. Bityutskiy D1(printk(KERN_DEBUG "alloc fn failed\n")); 358dae6227fSArtem B. Bityutskiy jffs2_free_tmp_dnode_info(tn); 359dae6227fSArtem B. Bityutskiy return -ENOMEM; 360dae6227fSArtem B. Bityutskiy } 361dae6227fSArtem B. Bityutskiy 362dae6227fSArtem B. Bityutskiy tn->version = je32_to_cpu(rd->version); 363dae6227fSArtem B. Bityutskiy tn->fn->ofs = je32_to_cpu(rd->offset); 364dae6227fSArtem B. Bityutskiy tn->fn->raw = ref; 365dae6227fSArtem B. Bityutskiy 366dae6227fSArtem B. Bityutskiy /* There was a bug where we wrote hole nodes out with 367dae6227fSArtem B. Bityutskiy csize/dsize swapped. Deal with it */ 368dae6227fSArtem B. Bityutskiy if (rd->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(rd->dsize) && je32_to_cpu(rd->csize)) 369dae6227fSArtem B. Bityutskiy tn->fn->size = je32_to_cpu(rd->csize); 370dae6227fSArtem B. Bityutskiy else // normal case... 371dae6227fSArtem B. Bityutskiy tn->fn->size = je32_to_cpu(rd->dsize); 372dae6227fSArtem B. Bityutskiy 373dae6227fSArtem B. Bityutskiy D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %#04x, dsize %#04x\n", 374dae6227fSArtem B. Bityutskiy ref_offset(ref), je32_to_cpu(rd->version), 375dae6227fSArtem B. Bityutskiy je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize))); 376dae6227fSArtem B. Bityutskiy 377dae6227fSArtem B. Bityutskiy jffs2_add_tn_to_tree(tn, tnp); 378dae6227fSArtem B. Bityutskiy 379dae6227fSArtem B. Bityutskiy return 0; 380dae6227fSArtem B. Bityutskiy } 381dae6227fSArtem B. Bityutskiy 382dae6227fSArtem B. Bityutskiy /* 383dae6227fSArtem B. Bityutskiy * Helper function for jffs2_get_inode_nodes(). 384dae6227fSArtem B. Bityutskiy * It is called every time an unknown node is found. 385dae6227fSArtem B. Bityutskiy * 386dae6227fSArtem B. Bityutskiy * Returns: 0 on succes; 387dae6227fSArtem B. Bityutskiy * 1 if the node should be marked obsolete; 388dae6227fSArtem B. Bityutskiy * negative error code on failure. 389dae6227fSArtem B. Bityutskiy */ 390dae6227fSArtem B. Bityutskiy static inline int 391dae6227fSArtem B. Bityutskiy read_unknown(struct jffs2_sb_info *c, 392dae6227fSArtem B. Bityutskiy struct jffs2_raw_node_ref *ref, 393dae6227fSArtem B. Bityutskiy struct jffs2_unknown_node *un, 394dae6227fSArtem B. Bityutskiy uint32_t read) 395dae6227fSArtem B. Bityutskiy { 396dae6227fSArtem B. Bityutskiy /* We don't mark unknown nodes as REF_UNCHECKED */ 397dae6227fSArtem B. Bityutskiy BUG_ON(ref_flags(ref) == REF_UNCHECKED); 398dae6227fSArtem B. Bityutskiy 399dae6227fSArtem B. Bityutskiy un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); 400dae6227fSArtem B. Bityutskiy 401dae6227fSArtem B. Bityutskiy if (crc32(0, un, sizeof(struct jffs2_unknown_node) - 4) != je32_to_cpu(un->hdr_crc)) { 402dae6227fSArtem B. Bityutskiy 403dae6227fSArtem B. Bityutskiy /* Hmmm. This should have been caught at scan time. */ 404dae6227fSArtem B. Bityutskiy printk(KERN_WARNING "Warning! Node header CRC failed at %#08x. " 405dae6227fSArtem B. Bityutskiy "But it must have been OK earlier.\n", ref_offset(ref)); 406dae6227fSArtem B. Bityutskiy D1(printk(KERN_DEBUG "Node was: { %#04x, %#04x, %#08x, %#08x }\n", 407dae6227fSArtem B. Bityutskiy je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), 408dae6227fSArtem B. Bityutskiy je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc))); 409dae6227fSArtem B. Bityutskiy return 1; 410dae6227fSArtem B. Bityutskiy } else { 411dae6227fSArtem B. Bityutskiy switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) { 412dae6227fSArtem B. Bityutskiy 413dae6227fSArtem B. Bityutskiy case JFFS2_FEATURE_INCOMPAT: 414dae6227fSArtem B. Bityutskiy printk(KERN_NOTICE "Unknown INCOMPAT nodetype %#04X at %#08x\n", 415dae6227fSArtem B. Bityutskiy je16_to_cpu(un->nodetype), ref_offset(ref)); 416dae6227fSArtem B. Bityutskiy /* EEP */ 417dae6227fSArtem B. Bityutskiy BUG(); 418dae6227fSArtem B. Bityutskiy break; 419dae6227fSArtem B. Bityutskiy 420dae6227fSArtem B. Bityutskiy case JFFS2_FEATURE_ROCOMPAT: 421dae6227fSArtem B. Bityutskiy printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %#04X at %#08x\n", 422dae6227fSArtem B. Bityutskiy je16_to_cpu(un->nodetype), ref_offset(ref)); 423dae6227fSArtem B. Bityutskiy BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO)); 424dae6227fSArtem B. Bityutskiy break; 425dae6227fSArtem B. Bityutskiy 426dae6227fSArtem B. Bityutskiy case JFFS2_FEATURE_RWCOMPAT_COPY: 427dae6227fSArtem B. Bityutskiy printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n", 428dae6227fSArtem B. Bityutskiy je16_to_cpu(un->nodetype), ref_offset(ref)); 429dae6227fSArtem B. Bityutskiy break; 430dae6227fSArtem B. Bityutskiy 431dae6227fSArtem B. Bityutskiy case JFFS2_FEATURE_RWCOMPAT_DELETE: 432dae6227fSArtem B. Bityutskiy printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n", 433dae6227fSArtem B. Bityutskiy je16_to_cpu(un->nodetype), ref_offset(ref)); 434dae6227fSArtem B. Bityutskiy return 1; 435dae6227fSArtem B. Bityutskiy } 436dae6227fSArtem B. Bityutskiy } 437dae6227fSArtem B. Bityutskiy 438dae6227fSArtem B. Bityutskiy return 0; 439dae6227fSArtem B. Bityutskiy } 440dae6227fSArtem B. Bityutskiy 4411da177e4SLinus Torvalds /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated 4421da177e4SLinus Torvalds with this ino, returning the former in order of version */ 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 4459dee7503SDavid Woodhouse struct rb_root *tnp, struct jffs2_full_dirent **fdp, 4461da177e4SLinus Torvalds uint32_t *highest_version, uint32_t *latest_mctime, 4471da177e4SLinus Torvalds uint32_t *mctime_ver) 4481da177e4SLinus Torvalds { 4491da177e4SLinus Torvalds struct jffs2_raw_node_ref *ref, *valid_ref; 4509dee7503SDavid Woodhouse struct rb_root ret_tn = RB_ROOT; 451dae6227fSArtem B. Bityutskiy struct jffs2_full_dirent *ret_fd = NULL; 4521da177e4SLinus Torvalds union jffs2_node_union node; 4531da177e4SLinus Torvalds size_t retlen; 4541da177e4SLinus Torvalds int err; 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds *mctime_ver = 0; 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino)); 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds valid_ref = jffs2_first_valid_node(f->inocache->nodes); 4631da177e4SLinus Torvalds 4648fabed4aSTodd Poynor if (!valid_ref && (f->inocache->ino != 1)) 4651da177e4SLinus Torvalds printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino); 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds while (valid_ref) { 4681da177e4SLinus Torvalds /* We can hold a pointer to a non-obsolete node without the spinlock, 4691da177e4SLinus Torvalds but _obsolete_ nodes may disappear at any time, if the block 4701da177e4SLinus Torvalds they're in gets erased. So if we mark 'ref' obsolete while we're 4711da177e4SLinus Torvalds not holding the lock, it can go away immediately. For that reason, 4721da177e4SLinus Torvalds we find the next valid node first, before processing 'ref'. 4731da177e4SLinus Torvalds */ 4741da177e4SLinus Torvalds ref = valid_ref; 4751da177e4SLinus Torvalds valid_ref = jffs2_first_valid_node(ref->next_in_ino); 4761da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds cond_resched(); 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds /* FIXME: point() */ 4811da177e4SLinus Torvalds err = jffs2_flash_read(c, (ref_offset(ref)), 4821da177e4SLinus Torvalds min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)), 4831da177e4SLinus Torvalds &retlen, (void *)&node); 4841da177e4SLinus Torvalds if (err) { 4851da177e4SLinus Torvalds printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref)); 4861da177e4SLinus Torvalds goto free_out; 4871da177e4SLinus Torvalds } 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds switch (je16_to_cpu(node.u.nodetype)) { 490dae6227fSArtem B. Bityutskiy 4911da177e4SLinus Torvalds case JFFS2_NODETYPE_DIRENT: 4921da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref))); 493dae6227fSArtem B. Bityutskiy 4941da177e4SLinus Torvalds if (retlen < sizeof(node.d)) { 495dae6227fSArtem B. Bityutskiy printk(KERN_WARNING "Warning! Short read dirent at %#08x\n", ref_offset(ref)); 4961da177e4SLinus Torvalds err = -EIO; 4971da177e4SLinus Torvalds goto free_out; 4981da177e4SLinus Torvalds } 499dae6227fSArtem B. Bityutskiy 500dae6227fSArtem B. Bityutskiy err = read_direntry(c, ref, &node.d, retlen, &ret_fd, latest_mctime, mctime_ver); 501dae6227fSArtem B. Bityutskiy if (err == 1) { 5021da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, ref); 503dae6227fSArtem B. Bityutskiy break; 504dae6227fSArtem B. Bityutskiy } else if (unlikely(err)) 505dae6227fSArtem B. Bityutskiy goto free_out; 506dae6227fSArtem B. Bityutskiy 5071da177e4SLinus Torvalds if (je32_to_cpu(node.d.version) > *highest_version) 5081da177e4SLinus Torvalds *highest_version = je32_to_cpu(node.d.version); 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds break; 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds case JFFS2_NODETYPE_INODE: 5131da177e4SLinus Torvalds D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref))); 514dae6227fSArtem B. Bityutskiy 5151da177e4SLinus Torvalds if (retlen < sizeof(node.i)) { 516dae6227fSArtem B. Bityutskiy printk(KERN_WARNING "Warning! Short read dnode at %#08x\n", ref_offset(ref)); 5171da177e4SLinus Torvalds err = -EIO; 5181da177e4SLinus Torvalds goto free_out; 5191da177e4SLinus Torvalds } 520dae6227fSArtem B. Bityutskiy 521dae6227fSArtem B. Bityutskiy err = read_dnode(c, ref, &node.i, retlen, &ret_tn, latest_mctime, mctime_ver); 522dae6227fSArtem B. Bityutskiy if (err == 1) { 523dae6227fSArtem B. Bityutskiy jffs2_mark_node_obsolete(c, ref); 524dae6227fSArtem B. Bityutskiy break; 525dae6227fSArtem B. Bityutskiy } else if (unlikely(err)) 526dae6227fSArtem B. Bityutskiy goto free_out; 527dae6227fSArtem B. Bityutskiy 5281da177e4SLinus Torvalds if (je32_to_cpu(node.i.version) > *highest_version) 5291da177e4SLinus Torvalds *highest_version = je32_to_cpu(node.i.version); 5301da177e4SLinus Torvalds 531dae6227fSArtem B. Bityutskiy D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", 532dae6227fSArtem B. Bityutskiy je32_to_cpu(node.i.version), *highest_version)); 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds break; 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds default: 537dae6227fSArtem B. Bityutskiy /* Check we've managed to read at least the common node header */ 538dae6227fSArtem B. Bityutskiy if (retlen < sizeof(struct jffs2_unknown_node)) { 539dae6227fSArtem B. Bityutskiy printk(KERN_WARNING "Warning! Short read unknown node at %#08x\n", 5401da177e4SLinus Torvalds ref_offset(ref)); 541dae6227fSArtem B. Bityutskiy return -EIO; 5421da177e4SLinus Torvalds } 5431da177e4SLinus Torvalds 544dae6227fSArtem B. Bityutskiy err = read_unknown(c, ref, &node.u, retlen); 545dae6227fSArtem B. Bityutskiy if (err == 1) { 546dae6227fSArtem B. Bityutskiy jffs2_mark_node_obsolete(c, ref); 547dae6227fSArtem B. Bityutskiy break; 548dae6227fSArtem B. Bityutskiy } else if (unlikely(err)) 549dae6227fSArtem B. Bityutskiy goto free_out; 550dae6227fSArtem B. Bityutskiy 5511da177e4SLinus Torvalds } 5521da177e4SLinus Torvalds spin_lock(&c->erase_completion_lock); 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds } 5551da177e4SLinus Torvalds spin_unlock(&c->erase_completion_lock); 5561da177e4SLinus Torvalds *tnp = ret_tn; 5571da177e4SLinus Torvalds *fdp = ret_fd; 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds return 0; 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds free_out: 5629dee7503SDavid Woodhouse jffs2_free_tmp_dnode_info_list(&ret_tn); 5631da177e4SLinus Torvalds jffs2_free_full_dirent_list(ret_fd); 5641da177e4SLinus Torvalds return err; 5651da177e4SLinus Torvalds } 5661da177e4SLinus Torvalds 5671da177e4SLinus Torvalds void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) 5681da177e4SLinus Torvalds { 5691da177e4SLinus Torvalds spin_lock(&c->inocache_lock); 5701da177e4SLinus Torvalds ic->state = state; 5711da177e4SLinus Torvalds wake_up(&c->inocache_wq); 5721da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds /* During mount, this needs no locking. During normal operation, its 5761da177e4SLinus Torvalds callers want to do other stuff while still holding the inocache_lock. 5771da177e4SLinus Torvalds Rather than introducing special case get_ino_cache functions or 5781da177e4SLinus Torvalds callbacks, we just let the caller do the locking itself. */ 5791da177e4SLinus Torvalds 5801da177e4SLinus Torvalds struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino) 5811da177e4SLinus Torvalds { 5821da177e4SLinus Torvalds struct jffs2_inode_cache *ret; 5831da177e4SLinus Torvalds 5841da177e4SLinus Torvalds D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino)); 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds ret = c->inocache_list[ino % INOCACHE_HASHSIZE]; 5871da177e4SLinus Torvalds while (ret && ret->ino < ino) { 5881da177e4SLinus Torvalds ret = ret->next; 5891da177e4SLinus Torvalds } 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds if (ret && ret->ino != ino) 5921da177e4SLinus Torvalds ret = NULL; 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds D2(printk(KERN_DEBUG "jffs2_get_ino_cache found %p for ino %u\n", ret, ino)); 5951da177e4SLinus Torvalds return ret; 5961da177e4SLinus Torvalds } 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new) 5991da177e4SLinus Torvalds { 6001da177e4SLinus Torvalds struct jffs2_inode_cache **prev; 6017d27c814SThomas Gleixner 6021da177e4SLinus Torvalds spin_lock(&c->inocache_lock); 6037d200960SDavid Woodhouse if (!new->ino) 6047d200960SDavid Woodhouse new->ino = ++c->highest_ino; 6057d200960SDavid Woodhouse 6067d200960SDavid Woodhouse D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds while ((*prev) && (*prev)->ino < new->ino) { 6111da177e4SLinus Torvalds prev = &(*prev)->next; 6121da177e4SLinus Torvalds } 6131da177e4SLinus Torvalds new->next = *prev; 6141da177e4SLinus Torvalds *prev = new; 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) 6201da177e4SLinus Torvalds { 6211da177e4SLinus Torvalds struct jffs2_inode_cache **prev; 62267e345d1SDavid Woodhouse D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino)); 6231da177e4SLinus Torvalds spin_lock(&c->inocache_lock); 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds while ((*prev) && (*prev)->ino < old->ino) { 6281da177e4SLinus Torvalds prev = &(*prev)->next; 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds if ((*prev) == old) { 6311da177e4SLinus Torvalds *prev = old->next; 6321da177e4SLinus Torvalds } 6331da177e4SLinus Torvalds 63467e345d1SDavid Woodhouse /* Free it now unless it's in READING or CLEARING state, which 63567e345d1SDavid Woodhouse are the transitions upon read_inode() and clear_inode(). The 63667e345d1SDavid Woodhouse rest of the time we know nobody else is looking at it, and 63767e345d1SDavid Woodhouse if it's held by read_inode() or clear_inode() they'll free it 63867e345d1SDavid Woodhouse for themselves. */ 63967e345d1SDavid Woodhouse if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING) 64067e345d1SDavid Woodhouse jffs2_free_inode_cache(old); 64167e345d1SDavid Woodhouse 6421da177e4SLinus Torvalds spin_unlock(&c->inocache_lock); 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds void jffs2_free_ino_caches(struct jffs2_sb_info *c) 6461da177e4SLinus Torvalds { 6471da177e4SLinus Torvalds int i; 6481da177e4SLinus Torvalds struct jffs2_inode_cache *this, *next; 6491da177e4SLinus Torvalds 6501da177e4SLinus Torvalds for (i=0; i<INOCACHE_HASHSIZE; i++) { 6511da177e4SLinus Torvalds this = c->inocache_list[i]; 6521da177e4SLinus Torvalds while (this) { 6531da177e4SLinus Torvalds next = this->next; 6541da177e4SLinus Torvalds jffs2_free_inode_cache(this); 6551da177e4SLinus Torvalds this = next; 6561da177e4SLinus Torvalds } 6571da177e4SLinus Torvalds c->inocache_list[i] = NULL; 6581da177e4SLinus Torvalds } 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds void jffs2_free_raw_node_refs(struct jffs2_sb_info *c) 6621da177e4SLinus Torvalds { 6631da177e4SLinus Torvalds int i; 6641da177e4SLinus Torvalds struct jffs2_raw_node_ref *this, *next; 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds for (i=0; i<c->nr_blocks; i++) { 6671da177e4SLinus Torvalds this = c->blocks[i].first_node; 6681da177e4SLinus Torvalds while(this) { 6691da177e4SLinus Torvalds next = this->next_phys; 6701da177e4SLinus Torvalds jffs2_free_raw_node_ref(this); 6711da177e4SLinus Torvalds this = next; 6721da177e4SLinus Torvalds } 6731da177e4SLinus Torvalds c->blocks[i].first_node = c->blocks[i].last_node = NULL; 6741da177e4SLinus Torvalds } 6751da177e4SLinus Torvalds } 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) 6781da177e4SLinus Torvalds { 6791da177e4SLinus Torvalds /* The common case in lookup is that there will be a node 6801da177e4SLinus Torvalds which precisely matches. So we go looking for that first */ 6811da177e4SLinus Torvalds struct rb_node *next; 6821da177e4SLinus Torvalds struct jffs2_node_frag *prev = NULL; 6831da177e4SLinus Torvalds struct jffs2_node_frag *frag = NULL; 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds D2(printk(KERN_DEBUG "jffs2_lookup_node_frag(%p, %d)\n", fragtree, offset)); 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds next = fragtree->rb_node; 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds while(next) { 6901da177e4SLinus Torvalds frag = rb_entry(next, struct jffs2_node_frag, rb); 6911da177e4SLinus Torvalds 6921da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Considering frag %d-%d (%p). left %p, right %p\n", 6931da177e4SLinus Torvalds frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right)); 6941da177e4SLinus Torvalds if (frag->ofs + frag->size <= offset) { 6951da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n", 6961da177e4SLinus Torvalds frag->ofs, frag->ofs+frag->size)); 6971da177e4SLinus Torvalds /* Remember the closest smaller match on the way down */ 6981da177e4SLinus Torvalds if (!prev || frag->ofs > prev->ofs) 6991da177e4SLinus Torvalds prev = frag; 7001da177e4SLinus Torvalds next = frag->rb.rb_right; 7011da177e4SLinus Torvalds } else if (frag->ofs > offset) { 7021da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n", 7031da177e4SLinus Torvalds frag->ofs, frag->ofs+frag->size)); 7041da177e4SLinus Torvalds next = frag->rb.rb_left; 7051da177e4SLinus Torvalds } else { 7061da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Returning frag %d,%d, matched\n", 7071da177e4SLinus Torvalds frag->ofs, frag->ofs+frag->size)); 7081da177e4SLinus Torvalds return frag; 7091da177e4SLinus Torvalds } 7101da177e4SLinus Torvalds } 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds /* Exact match not found. Go back up looking at each parent, 7131da177e4SLinus Torvalds and return the closest smaller one */ 7141da177e4SLinus Torvalds 7151da177e4SLinus Torvalds if (prev) 7161da177e4SLinus Torvalds D2(printk(KERN_DEBUG "No match. Returning frag %d,%d, closest previous\n", 7171da177e4SLinus Torvalds prev->ofs, prev->ofs+prev->size)); 7181da177e4SLinus Torvalds else 7191da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Returning NULL, empty fragtree\n")); 7201da177e4SLinus Torvalds 7211da177e4SLinus Torvalds return prev; 7221da177e4SLinus Torvalds } 7231da177e4SLinus Torvalds 7241da177e4SLinus Torvalds /* Pass 'c' argument to indicate that nodes should be marked obsolete as 7251da177e4SLinus Torvalds they're killed. */ 7261da177e4SLinus Torvalds void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) 7271da177e4SLinus Torvalds { 7281da177e4SLinus Torvalds struct jffs2_node_frag *frag; 7291da177e4SLinus Torvalds struct jffs2_node_frag *parent; 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds if (!root->rb_node) 7321da177e4SLinus Torvalds return; 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb)); 7351da177e4SLinus Torvalds 7361da177e4SLinus Torvalds while(frag) { 7371da177e4SLinus Torvalds if (frag->rb.rb_left) { 7381da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Going left from frag (%p) %d-%d\n", 7391da177e4SLinus Torvalds frag, frag->ofs, frag->ofs+frag->size)); 7401da177e4SLinus Torvalds frag = frag_left(frag); 7411da177e4SLinus Torvalds continue; 7421da177e4SLinus Torvalds } 7431da177e4SLinus Torvalds if (frag->rb.rb_right) { 7441da177e4SLinus Torvalds D2(printk(KERN_DEBUG "Going right from frag (%p) %d-%d\n", 7451da177e4SLinus Torvalds frag, frag->ofs, frag->ofs+frag->size)); 7461da177e4SLinus Torvalds frag = frag_right(frag); 7471da177e4SLinus Torvalds continue; 7481da177e4SLinus Torvalds } 7491da177e4SLinus Torvalds 7501da177e4SLinus Torvalds D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n", 7511da177e4SLinus Torvalds frag->ofs, frag->ofs+frag->size, frag->node, 7521da177e4SLinus Torvalds frag->node?frag->node->frags:0)); 7531da177e4SLinus Torvalds 7541da177e4SLinus Torvalds if (frag->node && !(--frag->node->frags)) { 7551da177e4SLinus Torvalds /* Not a hole, and it's the final remaining frag 7561da177e4SLinus Torvalds of this node. Free the node */ 7571da177e4SLinus Torvalds if (c) 7581da177e4SLinus Torvalds jffs2_mark_node_obsolete(c, frag->node->raw); 7591da177e4SLinus Torvalds 7601da177e4SLinus Torvalds jffs2_free_full_dnode(frag->node); 7611da177e4SLinus Torvalds } 7621da177e4SLinus Torvalds parent = frag_parent(frag); 7631da177e4SLinus Torvalds if (parent) { 7641da177e4SLinus Torvalds if (frag_left(parent) == frag) 7651da177e4SLinus Torvalds parent->rb.rb_left = NULL; 7661da177e4SLinus Torvalds else 7671da177e4SLinus Torvalds parent->rb.rb_right = NULL; 7681da177e4SLinus Torvalds } 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds jffs2_free_node_frag(frag); 7711da177e4SLinus Torvalds frag = parent; 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds cond_resched(); 7741da177e4SLinus Torvalds } 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base) 7781da177e4SLinus Torvalds { 7791da177e4SLinus Torvalds struct rb_node *parent = &base->rb; 7801da177e4SLinus Torvalds struct rb_node **link = &parent; 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag, 7831da177e4SLinus Torvalds newfrag->ofs, newfrag->ofs+newfrag->size, base)); 7841da177e4SLinus Torvalds 7851da177e4SLinus Torvalds while (*link) { 7861da177e4SLinus Torvalds parent = *link; 7871da177e4SLinus Torvalds base = rb_entry(parent, struct jffs2_node_frag, rb); 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs)); 7901da177e4SLinus Torvalds if (newfrag->ofs > base->ofs) 7911da177e4SLinus Torvalds link = &base->rb.rb_right; 7921da177e4SLinus Torvalds else if (newfrag->ofs < base->ofs) 7931da177e4SLinus Torvalds link = &base->rb.rb_left; 7941da177e4SLinus Torvalds else { 7951da177e4SLinus Torvalds printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base); 7961da177e4SLinus Torvalds BUG(); 7971da177e4SLinus Torvalds } 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds rb_link_node(&newfrag->rb, &base->rb, link); 8011da177e4SLinus Torvalds } 802