Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32f1a95d authored by Artem B. Bityuckiy's avatar Artem B. Bityuckiy Committed by Thomas Gleixner
Browse files

[JFFS2] Add symlink caching support.

parent 20a6c211
Loading
Loading
Loading
Loading
+21 −7
Original line number Diff line number Diff line
@@ -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 $
 *
 */

@@ -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();
@@ -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);
@@ -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);

@@ -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
	*/
+1 −31
Original line number Diff line number Diff line
@@ -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 $
 *
 */

@@ -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;
}
+48 −6
Original line number Diff line number Diff line
@@ -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 $
 *
 */

@@ -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:
@@ -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) {
@@ -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);
+30 −12
Original line number Diff line number Diff line
@@ -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 $
 *
 */

@@ -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;
}
+17 −14
Original line number Diff line number Diff line
@@ -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 $
 *
 */

@@ -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;
@@ -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 */