mtd/fs/jffs2 dir.c, 1.84, 1.85 read.c, 1.38, 1.39 readinode.c, 1.118,
1.119 symlink.c, 1.14, 1.15 write.c, 1.90, 1.91
Artem Bityuckiy
dedekind at infradead.org
Tue Mar 1 05:34:07 EST 2005
Update of /home/cvs/mtd/fs/jffs2
In directory phoenix.infradead.org:/tmp/cvs-serv20157/fs/jffs2
Modified Files:
dir.c read.c readinode.c symlink.c write.c
Log Message:
Add symlink caching support.
Index: dir.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/dir.c,v
retrieving revision 1.84
retrieving revision 1.85
diff -u -r1.84 -r1.85
--- dir.c 16 Nov 2004 20:36:11 -0000 1.84
+++ dir.c 1 Mar 2005 10:34:03 -0000 1.85
@@ -296,11 +296,11 @@
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();
@@ -314,7 +314,7 @@
* 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);
@@ -333,16 +333,16 @@
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);
@@ -353,6 +353,20 @@
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
*/
Index: read.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/read.c,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -r1.38 -r1.39
--- read.c 16 Nov 2004 20:36:12 -0000 1.38
+++ read.c 1 Mar 2005 10:34:03 -0000 1.39
@@ -214,33 +214,3 @@
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;
-}
Index: readinode.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/readinode.c,v
retrieving revision 1.118
retrieving revision 1.119
diff -u -r1.118 -r1.119
--- readinode.c 27 Feb 2005 23:01:33 -0000 1.118
+++ readinode.c 1 Mar 2005 10:34:03 -0000 1.119
@@ -623,6 +623,40 @@
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:
@@ -683,12 +717,20 @@
jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
- fds = f->dents;
+ /* 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) {
- fd = fds;
- fds = fd->next;
- jffs2_free_full_dirent(fd);
+ while(fds) {
+ fd = fds;
+ fds = fd->next;
+ jffs2_free_full_dirent(fd);
+ }
}
if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
Index: symlink.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/symlink.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- symlink.c 16 Nov 2004 20:36:12 -0000 1.14
+++ symlink.c 1 Mar 2005 10:34:03 -0000 1.15
@@ -19,27 +19,42 @@
#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);
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
+
+ /*
+ * We don't aquire 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 build and f->dents has
+ * to point to the target path.
+ * 2. Nobody use f->dents (if the inode is symlink's inode). The
+ * exception is inode freeing function which frees f->dents.
+ */
+
+ 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));
+
+ 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;
}
-static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd)
-{
- char *s = nd_get_link(nd);
- if (!IS_ERR(s))
- kfree(s);
-}
Index: write.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/write.c,v
retrieving revision 1.90
retrieving revision 1.91
diff -u -r1.90 -r1.91
--- write.c 28 Jan 2005 18:53:01 -0000 1.90
+++ write.c 1 Mar 2005 10:34:03 -0000 1.91
@@ -644,20 +644,23 @@
down(&dead_f->sem);
- while (dead_f->dents) {
- /* There can be only deleted ones */
- fd = dead_f->dents;
-
- dead_f->dents = fd->next;
-
- if (fd->ino) {
- 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));
+ if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) {
+ while (dead_f->dents) {
+ /* There can be only deleted ones */
+ fd = dead_f->dents;
+
+ dead_f->dents = fd->next;
+
+ if (fd->ino) {
+ 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));
+ }
+ jffs2_mark_node_obsolete(c, fd->raw);
+ jffs2_free_full_dirent(fd);
}
- jffs2_mark_node_obsolete(c, fd->raw);
- jffs2_free_full_dirent(fd);
}
dead_f->inocache->nlink--;
More information about the linux-mtd-cvs
mailing list