Loading fs/jffs2/dir.c +21 −7 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * * $Id: dir.c,v 1.84 2004/11/16 20:36:11 dwmw2 Exp $ * $Id: dir.c,v 1.85 2005/03/01 10:34:03 dedekind Exp $ * */ Loading Loading @@ -296,11 +296,11 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen, phys_ofs; int ret; int ret, targetlen = strlen(target); /* FIXME: If you care. We'd need to use frags for the target if it grows much more than this */ if (strlen(target) > 254) if (targetlen > 254) return -EINVAL; ri = jffs2_alloc_raw_inode(); Loading @@ -314,7 +314,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char * Just the node will do for now, though */ namelen = dentry->d_name.len; ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL); ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_inode(ri); Loading @@ -333,16 +333,16 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char f = JFFS2_INODE_INFO(inode); inode->i_size = strlen(target); inode->i_size = targetlen; ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); ri->compr = JFFS2_COMPR_NONE; ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target))); ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL); fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); Loading @@ -353,6 +353,20 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char jffs2_clear_inode(inode); return PTR_ERR(fn); } /* We use f->dents field to store the target path. */ f->dents = kmalloc(targetlen + 1, GFP_KERNEL); if (!f->dents) { printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); return -ENOMEM; } memcpy(f->dents, target, targetlen + 1); D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents)); /* No data here. Only a metadata node, which will be obsoleted by the first data write */ Loading fs/jffs2/read.c +1 −31 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * * $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $ * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $ * */ Loading Loading @@ -214,33 +214,3 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, return 0; } /* Core function to read symlink target. */ char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f) { char *buf; int ret; down(&f->sem); if (!f->metadata) { printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino); up(&f->sem); return ERR_PTR(-EINVAL); } buf = kmalloc(f->metadata->size+1, GFP_USER); if (!buf) { up(&f->sem); return ERR_PTR(-ENOMEM); } buf[f->metadata->size]=0; ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size); up(&f->sem); if (ret) { kfree(buf); return ERR_PTR(ret); } return buf; } fs/jffs2/readinode.c +48 −6 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * * $Id: readinode.c,v 1.118 2005/02/27 23:01:33 dwmw2 Exp $ * $Id: readinode.c,v 1.119 2005/03/01 10:34:03 dedekind Exp $ * */ Loading Loading @@ -623,6 +623,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, case. */ if (!je32_to_cpu(latest_node->isize)) latest_node->isize = latest_node->dsize; if (f->inocache->state != INO_STATE_CHECKING) { /* Symlink's inode data is the target path. Read it and * keep in RAM to facilitate quick follow symlink operation. * We use f->dents field to store the target path, which * is somewhat ugly. */ f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); if (!f->dents) { printk(KERN_WARNING "Can't allocate %d bytes of memory " "for the symlink target path cache\n", je32_to_cpu(latest_node->csize)); up(&f->sem); jffs2_do_clear_inode(c, f); return -ENOMEM; } ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); if (ret || retlen != je32_to_cpu(latest_node->csize)) { if (retlen != je32_to_cpu(latest_node->csize)) ret = -EIO; kfree(f->dents); f->dents = NULL; up(&f->sem); jffs2_do_clear_inode(c, f); return -ret; } ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", (char *)f->dents)); } /* fall through... */ case S_IFBLK: Loading Loading @@ -683,6 +717,13 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); /* For symlink inodes we us f->dents to store the target path name */ if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { if (f->dents) { kfree(f->dents); f->dents = NULL; } } else { fds = f->dents; while(fds) { Loading @@ -690,6 +731,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) fds = fd->next; jffs2_free_full_dirent(fd); } } if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); Loading fs/jffs2/symlink.c +30 −12 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * * $Id: symlink.c,v 1.14 2004/11/16 20:36:12 dwmw2 Exp $ * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $ * */ Loading @@ -19,27 +19,45 @@ #include "nodelist.h" static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd); struct inode_operations jffs2_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = jffs2_follow_link, .put_link = jffs2_put_link, .setattr = jffs2_setattr }; static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { unsigned char *buf; buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); nd_set_link(nd, buf); return 0; struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); /* * We don't acquire the f->sem mutex here since the only data we * use is f->dents which in case of the symlink inode points to the * symlink's target path. * * 1. If we are here the inode has already built and f->dents has * to point to the target path. * 2. Nobody uses f->dents (if the inode is symlink's inode). The * exception is inode freeing function which frees f->dents. But * it can't be called while we are here and before VFS has * stopped using our f->dents string which we provide by means of * nd_set_link() call. */ if (!f->dents) { printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n"); return -EIO; } D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents)); static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd) { char *s = nd_get_link(nd); if (!IS_ERR(s)) kfree(s); nd_set_link(nd, (char *)f->dents); /* * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe * since the only way that may cause f->dents to be changed is iput() operation. * But VFS will not use f->dents after iput() has been called. */ return 0; } fs/jffs2/write.c +17 −14 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * * $Id: write.c,v 1.90 2005/01/28 18:53:01 hammache Exp $ * $Id: write.c,v 1.91 2005/03/01 10:34:03 dedekind Exp $ * */ Loading Loading @@ -644,6 +644,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, down(&dead_f->sem); if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) { while (dead_f->dents) { /* There can be only deleted ones */ fd = dead_f->dents; Loading @@ -654,11 +655,13 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", 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, dead_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); } } dead_f->inocache->nlink--; /* NB: Caller must set inode nlink if appropriate */ Loading Loading
fs/jffs2/dir.c +21 −7 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * * $Id: dir.c,v 1.84 2004/11/16 20:36:11 dwmw2 Exp $ * $Id: dir.c,v 1.85 2005/03/01 10:34:03 dedekind Exp $ * */ Loading Loading @@ -296,11 +296,11 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen, phys_ofs; int ret; int ret, targetlen = strlen(target); /* FIXME: If you care. We'd need to use frags for the target if it grows much more than this */ if (strlen(target) > 254) if (targetlen > 254) return -EINVAL; ri = jffs2_alloc_raw_inode(); Loading @@ -314,7 +314,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char * Just the node will do for now, though */ namelen = dentry->d_name.len; ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL); ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_inode(ri); Loading @@ -333,16 +333,16 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char f = JFFS2_INODE_INFO(inode); inode->i_size = strlen(target); inode->i_size = targetlen; ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); ri->compr = JFFS2_COMPR_NONE; ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target))); ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL); fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); Loading @@ -353,6 +353,20 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char jffs2_clear_inode(inode); return PTR_ERR(fn); } /* We use f->dents field to store the target path. */ f->dents = kmalloc(targetlen + 1, GFP_KERNEL); if (!f->dents) { printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); up(&f->sem); jffs2_complete_reservation(c); jffs2_clear_inode(inode); return -ENOMEM; } memcpy(f->dents, target, targetlen + 1); D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents)); /* No data here. Only a metadata node, which will be obsoleted by the first data write */ Loading
fs/jffs2/read.c +1 −31 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * * $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $ * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $ * */ Loading Loading @@ -214,33 +214,3 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, return 0; } /* Core function to read symlink target. */ char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f) { char *buf; int ret; down(&f->sem); if (!f->metadata) { printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino); up(&f->sem); return ERR_PTR(-EINVAL); } buf = kmalloc(f->metadata->size+1, GFP_USER); if (!buf) { up(&f->sem); return ERR_PTR(-ENOMEM); } buf[f->metadata->size]=0; ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size); up(&f->sem); if (ret) { kfree(buf); return ERR_PTR(ret); } return buf; }
fs/jffs2/readinode.c +48 −6 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * * $Id: readinode.c,v 1.118 2005/02/27 23:01:33 dwmw2 Exp $ * $Id: readinode.c,v 1.119 2005/03/01 10:34:03 dedekind Exp $ * */ Loading Loading @@ -623,6 +623,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, case. */ if (!je32_to_cpu(latest_node->isize)) latest_node->isize = latest_node->dsize; if (f->inocache->state != INO_STATE_CHECKING) { /* Symlink's inode data is the target path. Read it and * keep in RAM to facilitate quick follow symlink operation. * We use f->dents field to store the target path, which * is somewhat ugly. */ f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); if (!f->dents) { printk(KERN_WARNING "Can't allocate %d bytes of memory " "for the symlink target path cache\n", je32_to_cpu(latest_node->csize)); up(&f->sem); jffs2_do_clear_inode(c, f); return -ENOMEM; } ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); if (ret || retlen != je32_to_cpu(latest_node->csize)) { if (retlen != je32_to_cpu(latest_node->csize)) ret = -EIO; kfree(f->dents); f->dents = NULL; up(&f->sem); jffs2_do_clear_inode(c, f); return -ret; } ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", (char *)f->dents)); } /* fall through... */ case S_IFBLK: Loading Loading @@ -683,6 +717,13 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); /* For symlink inodes we us f->dents to store the target path name */ if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { if (f->dents) { kfree(f->dents); f->dents = NULL; } } else { fds = f->dents; while(fds) { Loading @@ -690,6 +731,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) fds = fd->next; jffs2_free_full_dirent(fd); } } if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); Loading
fs/jffs2/symlink.c +30 −12 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * * $Id: symlink.c,v 1.14 2004/11/16 20:36:12 dwmw2 Exp $ * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $ * */ Loading @@ -19,27 +19,45 @@ #include "nodelist.h" static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd); struct inode_operations jffs2_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = jffs2_follow_link, .put_link = jffs2_put_link, .setattr = jffs2_setattr }; static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { unsigned char *buf; buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); nd_set_link(nd, buf); return 0; struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); /* * We don't acquire the f->sem mutex here since the only data we * use is f->dents which in case of the symlink inode points to the * symlink's target path. * * 1. If we are here the inode has already built and f->dents has * to point to the target path. * 2. Nobody uses f->dents (if the inode is symlink's inode). The * exception is inode freeing function which frees f->dents. But * it can't be called while we are here and before VFS has * stopped using our f->dents string which we provide by means of * nd_set_link() call. */ if (!f->dents) { printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n"); return -EIO; } D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents)); static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd) { char *s = nd_get_link(nd); if (!IS_ERR(s)) kfree(s); nd_set_link(nd, (char *)f->dents); /* * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe * since the only way that may cause f->dents to be changed is iput() operation. * But VFS will not use f->dents after iput() has been called. */ return 0; }
fs/jffs2/write.c +17 −14 Original line number Diff line number Diff line Loading @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * * $Id: write.c,v 1.90 2005/01/28 18:53:01 hammache Exp $ * $Id: write.c,v 1.91 2005/03/01 10:34:03 dedekind Exp $ * */ Loading Loading @@ -644,6 +644,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, down(&dead_f->sem); if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) { while (dead_f->dents) { /* There can be only deleted ones */ fd = dead_f->dents; Loading @@ -654,11 +655,13 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", 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, dead_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); } } dead_f->inocache->nlink--; /* NB: Caller must set inode nlink if appropriate */ Loading