--- zzzz-none-000/linux-2.4.17/fs/jffs2/dir.c 2001-09-14 21:04:07.000000000 +0000 +++ sangam-fb-322/linux-2.4.17/fs/jffs2/dir.c 2004-11-24 13:22:18.000000000 +0000 @@ -1,7 +1,7 @@ /* * JFFS2 -- Journalling Flash File System, Version 2. * - * Copyright (C) 2001 Red Hat, Inc. + * Copyright (C) 2001, 2002 Red Hat, Inc. * * Created by David Woodhouse * @@ -31,13 +31,15 @@ * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * - * $Id: dir.c,v 1.42 2001/05/24 22:24:39 dwmw2 Exp $ + * $Id: dir.c,v 1.1.1.1 2003/06/23 22:18:37 jharrell Exp $ * */ #include #include +#include #include +#include /* For completion */ #include #include #include @@ -92,7 +94,7 @@ struct jffs2_inode_info *dir_f; struct jffs2_sb_info *c; struct jffs2_full_dirent *fd = NULL, *fd_list; - __u32 ino = 0; + uint32_t ino = 0; struct inode *inode = NULL; D1(printk(KERN_DEBUG "jffs2_lookup()\n")); @@ -187,68 +189,35 @@ /***********************************************************************/ -static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode) +static int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen) { - struct jffs2_inode_info *f, *dir_f; - struct jffs2_sb_info *c; - struct inode *inode; - struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; - int namelen; - __u32 alloclen, phys_ofs; - __u32 writtenlen; + uint32_t alloclen, phys_ofs; + uint32_t writtenlen; int ret; - ri = jffs2_alloc_raw_inode(); - if (!ri) - return -ENOMEM; - - c = JFFS2_SB_INFO(dir_i->i_sb); - - D1(printk(KERN_DEBUG "jffs2_create()\n")); - /* Try to reserve enough space for both node and dirent. * Just the node will do for now, though */ - namelen = dentry->d_name.len; ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); - D1(printk(KERN_DEBUG "jffs2_create(): reserved 0x%x bytes\n", alloclen)); - if (ret) { - jffs2_free_raw_inode(ri); + D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); + if (ret) return ret; - } - - inode = jffs2_new_inode(dir_i, mode, ri); - - if (IS_ERR(inode)) { - D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n")); - jffs2_free_raw_inode(ri); - jffs2_complete_reservation(c); - return PTR_ERR(inode); - } - - inode->i_op = &jffs2_file_inode_operations; - inode->i_fop = &jffs2_file_operations; - inode->i_mapping->a_ops = &jffs2_file_address_operations; - inode->i_mapping->nrpages = 0; - - f = JFFS2_INODE_INFO(inode); ri->data_crc = 0; ri->node_crc = crc32(0, ri, sizeof(*ri)-8); - fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen); - D1(printk(KERN_DEBUG "jffs2_create created file with mode 0x%x\n", ri->mode)); - jffs2_free_raw_inode(ri); + fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen); + + D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n", ri->mode)); if (IS_ERR(fn)) { D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); /* Eeek. Wave bye bye */ up(&f->sem); jffs2_complete_reservation(c); - jffs2_clear_inode(inode); return PTR_ERR(fn); } /* No data here. Only a metadata node, which will be @@ -270,7 +239,6 @@ if (ret) { /* Eep. */ D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n")); - jffs2_clear_inode(inode); return ret; } } @@ -279,11 +247,9 @@ if (!rd) { /* Argh. Now we treat it like a normal delete */ jffs2_complete_reservation(c); - jffs2_clear_inode(inode); return -ENOMEM; } - dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); rd->magic = JFFS2_MAGIC_BITMASK; @@ -291,16 +257,16 @@ rd->totlen = sizeof(*rd) + namelen; rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); - rd->pino = dir_i->i_ino; + rd->pino = dir_f->inocache->ino; rd->version = dir_f->highest_version++; - rd->ino = inode->i_ino; + rd->ino = ri->ino; rd->mctime = CURRENT_TIME; rd->nsize = namelen; rd->type = DT_REG; rd->node_crc = crc32(0, rd, sizeof(*rd)-8); - rd->name_crc = crc32(0, dentry->d_name.name, namelen); + rd->name_crc = crc32(0, name, namelen); - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); + fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, &writtenlen); jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); @@ -309,7 +275,6 @@ /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ up(&dir_f->sem); - jffs2_clear_inode(inode); return PTR_ERR(fd); } @@ -318,6 +283,53 @@ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); + return 0; +} + +static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode) +{ + struct jffs2_raw_inode *ri; + struct jffs2_inode_info *f, *dir_f; + struct jffs2_sb_info *c; + struct inode *inode; + int ret; + + ri = jffs2_alloc_raw_inode(); + if (!ri) + return -ENOMEM; + + c = JFFS2_SB_INFO(dir_i->i_sb); + + D1(printk(KERN_DEBUG "jffs2_create()\n")); + + inode = jffs2_new_inode(dir_i, mode, ri); + + if (IS_ERR(inode)) { + D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n")); + jffs2_free_raw_inode(ri); + return PTR_ERR(inode); + } + + inode->i_op = &jffs2_file_inode_operations; + inode->i_fop = &jffs2_file_operations; + inode->i_mapping->a_ops = &jffs2_file_address_operations; + inode->i_mapping->nrpages = 0; + + f = JFFS2_INODE_INFO(inode); + dir_f = JFFS2_INODE_INFO(dir_i); + + ret = jffs2_do_create(c, dir_f, f, ri, + dentry->d_name.name, dentry->d_name.len); + + if (ret) { + jffs2_clear_inode(inode); + make_bad_inode(inode); + iput(inode); + jffs2_free_raw_inode(ri); + return ret; + } + + jffs2_free_raw_inode(ri); d_instantiate(dentry, inode); D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", @@ -327,46 +339,41 @@ /***********************************************************************/ -static int jffs2_do_unlink(struct inode *dir_i, struct dentry *dentry, int rename) +static int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f) { - struct jffs2_inode_info *dir_f, *f; - struct jffs2_sb_info *c; struct jffs2_raw_dirent *rd; struct jffs2_full_dirent *fd; - __u32 alloclen, phys_ofs; + uint32_t alloclen, phys_ofs; int ret; - c = JFFS2_SB_INFO(dir_i->i_sb); - rd = jffs2_alloc_raw_dirent(); if (!rd) return -ENOMEM; - ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_DELETION); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION); if (ret) { jffs2_free_raw_dirent(rd); return ret; } - dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); /* Build a deletion node */ rd->magic = JFFS2_MAGIC_BITMASK; rd->nodetype = JFFS2_NODETYPE_DIRENT; - rd->totlen = sizeof(*rd) + dentry->d_name.len; + rd->totlen = sizeof(*rd) + namelen; rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); - rd->pino = dir_i->i_ino; + rd->pino = dir_f->inocache->ino; rd->version = dir_f->highest_version++; rd->ino = 0; rd->mctime = CURRENT_TIME; - rd->nsize = dentry->d_name.len; + rd->nsize = namelen; rd->type = DT_UNKNOWN; rd->node_crc = crc32(0, rd, sizeof(*rd)-8); - rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len); + rd->name_crc = crc32(0, name, namelen); - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL); + fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, NULL); jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); @@ -380,29 +387,29 @@ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); - if (!rename) { - f = JFFS2_INODE_INFO(dentry->d_inode); - down(&f->sem); + if (dead_f) { /* Null if this was a rename not a real unlink */ + + down(&dead_f->sem); - while (f->dents) { + while (dead_f->dents) { /* There can be only deleted ones */ - fd = f->dents; + fd = dead_f->dents; - f->dents = fd->next; + dead_f->dents = fd->next; if (fd->ino) { printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", - f->inocache->ino, fd->name, fd->ino); + dead_f->inocache->ino, fd->name, fd->ino); } else { - D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, f->inocache->ino)); + D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino)); } jffs2_mark_node_obsolete(c, fd->raw); jffs2_free_full_dirent(fd); } - f->inocache->nlink--; - dentry->d_inode->i_nlink--; - up(&f->sem); + dead_f->inocache->nlink--; + /* NB: Caller must set inode nlink if appropriate */ + up(&dead_f->sem); } return 0; @@ -410,54 +417,55 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) { - return jffs2_do_unlink(dir_i, dentry, 0); + struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); + struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); + struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode); + int ret; + + ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, + dentry->d_name.len, dead_f); + dentry->d_inode->i_nlink = dead_f->inocache->nlink; + return ret; } /***********************************************************************/ -static int jffs2_do_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry, int rename) +static int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen) { - struct jffs2_inode_info *dir_f, *f; - struct jffs2_sb_info *c; struct jffs2_raw_dirent *rd; struct jffs2_full_dirent *fd; - __u32 alloclen, phys_ofs; + uint32_t alloclen, phys_ofs; int ret; - c = JFFS2_SB_INFO(dir_i->i_sb); - rd = jffs2_alloc_raw_dirent(); if (!rd) return -ENOMEM; - ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_dirent(rd); return ret; } - dir_f = JFFS2_INODE_INFO(dir_i); down(&dir_f->sem); /* Build a deletion node */ rd->magic = JFFS2_MAGIC_BITMASK; rd->nodetype = JFFS2_NODETYPE_DIRENT; - rd->totlen = sizeof(*rd) + dentry->d_name.len; + rd->totlen = sizeof(*rd) + namelen; rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); - rd->pino = dir_i->i_ino; + rd->pino = dir_f->inocache->ino; rd->version = dir_f->highest_version++; - rd->ino = old_dentry->d_inode->i_ino; + rd->ino = ino; rd->mctime = CURRENT_TIME; - rd->nsize = dentry->d_name.len; + rd->nsize = namelen; - /* XXX: This is ugly. */ - rd->type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; - if (!rd->type) rd->type = DT_REG; + rd->type = type; rd->node_crc = crc32(0, rd, sizeof(*rd)-8); - rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len); + rd->name_crc = crc32(0, name, namelen); - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL); + fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, NULL); jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); @@ -471,19 +479,26 @@ jffs2_add_fd_to_list(c, fd, &dir_f->dents); up(&dir_f->sem); - if (!rename) { - f = JFFS2_INODE_INFO(old_dentry->d_inode); - down(&f->sem); - old_dentry->d_inode->i_nlink = ++f->inocache->nlink; - up(&f->sem); - } return 0; } static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) { - int ret = jffs2_do_link(old_dentry, dir_i, dentry, 0); + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_inode->i_sb); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); + struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); + int ret; + + /* XXX: This is ugly */ + uint8_t type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; + if (!type) type = DT_REG; + + ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len); + if (!ret) { + down(&f->sem); + old_dentry->d_inode->i_nlink = ++f->inocache->nlink; + up(&f->sem); d_instantiate(dentry, old_dentry->d_inode); atomic_inc(&old_dentry->d_inode->i_count); } @@ -502,8 +517,8 @@ struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; - __u32 alloclen, phys_ofs; - __u32 writtenlen; + uint32_t alloclen, phys_ofs; + uint32_t writtenlen; int ret; /* FIXME: If you care. We'd need to use frags for the target @@ -541,7 +556,7 @@ f = JFFS2_INODE_INFO(inode); - ri->dsize = ri->csize = strlen(target); + inode->i_size = ri->isize = ri->dsize = ri->csize = strlen(target); ri->totlen = sizeof(*ri) + ri->dsize; ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); @@ -549,7 +564,7 @@ ri->data_crc = crc32(0, target, strlen(target)); ri->node_crc = crc32(0, ri, sizeof(*ri)-8); - fn = jffs2_write_dnode(inode, ri, target, strlen(target), phys_ofs, &writtenlen); + fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, &writtenlen); jffs2_free_raw_inode(ri); @@ -607,7 +622,7 @@ rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->name_crc = crc32(0, dentry->d_name.name, namelen); - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); + fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); @@ -640,8 +655,8 @@ struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; - __u32 alloclen, phys_ofs; - __u32 writtenlen; + uint32_t alloclen, phys_ofs; + uint32_t writtenlen; int ret; mode |= S_IFDIR; @@ -679,7 +694,7 @@ ri->data_crc = 0; ri->node_crc = crc32(0, ri, sizeof(*ri)-8); - fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen); + fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen); jffs2_free_raw_inode(ri); @@ -737,7 +752,7 @@ rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->name_crc = crc32(0, dentry->d_name.name, namelen); - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); + fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); @@ -783,8 +798,8 @@ int namelen; unsigned short dev; int devlen = 0; - __u32 alloclen, phys_ofs; - __u32 writtenlen; + uint32_t alloclen, phys_ofs; + uint32_t writtenlen; int ret; ri = jffs2_alloc_raw_inode(); @@ -830,7 +845,7 @@ ri->data_crc = crc32(0, &dev, devlen); ri->node_crc = crc32(0, ri, sizeof(*ri)-8); - fn = jffs2_write_dnode(inode, ri, (char *)&dev, devlen, phys_ofs, &writtenlen); + fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, &writtenlen); jffs2_free_raw_inode(ri); @@ -891,7 +906,7 @@ rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->name_crc = crc32(0, dentry->d_name.name, namelen); - fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); + fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); @@ -917,34 +932,44 @@ struct inode *new_dir_i, struct dentry *new_dentry) { int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); + uint8_t type; + /* XXX: We probably ought to alloc enough space for both nodes at the same time. Writing the new link, then getting -ENOSPC, is quite bad :) */ /* Make a hard link */ - ret = jffs2_do_link(old_dentry, new_dir_i, new_dentry, 1); + + /* XXX: This is ugly */ + type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; + if (!type) type = DT_REG; + + ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), + old_dentry->d_inode->i_ino, type, + new_dentry->d_name.name, new_dentry->d_name.len); + if (ret) return ret; /* Unlink the original */ - ret = jffs2_do_unlink(old_dir_i, old_dentry, 1); - + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), + old_dentry->d_name.name, old_dentry->d_name.len, NULL); + + /* We don't touch inode->i_nlink */ + if (ret) { - /* Try to delete the _new_ link to return a clean failure */ - int ret2 = jffs2_do_unlink(new_dir_i, new_dentry, 1); - if (ret2) { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); - down(&f->sem); - old_dentry->d_inode->i_nlink = f->inocache->nlink++; - up(&f->sem); - - printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (old err %d, new err %d). You now have a hard link\n", ret, ret2); - /* Might as well let the VFS know */ - d_instantiate(new_dentry, old_dentry->d_inode); - atomic_inc(&old_dentry->d_inode->i_count); - } - + /* Oh shit. We really ought to make a single node which can do both atomically */ + struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); + down(&f->sem); + old_dentry->d_inode->i_nlink = f->inocache->nlink++; + up(&f->sem); + + printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); + /* Might as well let the VFS know */ + d_instantiate(new_dentry, old_dentry->d_inode); + atomic_inc(&old_dentry->d_inode->i_count); } return ret; }