mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 06:34:12 +08:00
[JFFS2] Add symlink caching support.
Signed-off-by: Artem B. Bityuckiy <dedekind@infradead.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
parent
20a6c21190
commit
32f1a95d50
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* For licensing information, see the file 'LICENCE' in this directory.
|
* 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;
|
struct jffs2_full_dirent *fd;
|
||||||
int namelen;
|
int namelen;
|
||||||
uint32_t alloclen, phys_ofs;
|
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
|
/* FIXME: If you care. We'd need to use frags for the target
|
||||||
if it grows much more than this */
|
if it grows much more than this */
|
||||||
if (strlen(target) > 254)
|
if (targetlen > 254)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ri = jffs2_alloc_raw_inode();
|
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
|
* Just the node will do for now, though
|
||||||
*/
|
*/
|
||||||
namelen = dentry->d_name.len;
|
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) {
|
if (ret) {
|
||||||
jffs2_free_raw_inode(ri);
|
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);
|
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->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
|
||||||
ri->totlen = cpu_to_je32(sizeof(*ri) + 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->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
|
||||||
|
|
||||||
ri->compr = JFFS2_COMPR_NONE;
|
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));
|
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);
|
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);
|
jffs2_clear_inode(inode);
|
||||||
return PTR_ERR(fn);
|
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
|
/* No data here. Only a metadata node, which will be
|
||||||
obsoleted by the first data write
|
obsoleted by the first data write
|
||||||
*/
|
*/
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* For licensing information, see the file 'LICENCE' in this directory.
|
* 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;
|
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;
|
|
||||||
}
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* For licensing information, see the file 'LICENCE' in this directory.
|
* 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. */
|
case. */
|
||||||
if (!je32_to_cpu(latest_node->isize))
|
if (!je32_to_cpu(latest_node->isize))
|
||||||
latest_node->isize = latest_node->dsize;
|
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... */
|
/* fall through... */
|
||||||
|
|
||||||
case S_IFBLK:
|
case S_IFBLK:
|
||||||
@ -683,12 +717,20 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
|
|||||||
|
|
||||||
jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
|
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) {
|
while(fds) {
|
||||||
fd = fds;
|
fd = fds;
|
||||||
fds = fd->next;
|
fds = fd->next;
|
||||||
jffs2_free_full_dirent(fd);
|
jffs2_free_full_dirent(fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
|
if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* For licensing information, see the file 'LICENCE' in this directory.
|
* 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"
|
#include "nodelist.h"
|
||||||
|
|
||||||
static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
|
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 =
|
struct inode_operations jffs2_symlink_inode_operations =
|
||||||
{
|
{
|
||||||
.readlink = generic_readlink,
|
.readlink = generic_readlink,
|
||||||
.follow_link = jffs2_follow_link,
|
.follow_link = jffs2_follow_link,
|
||||||
.put_link = jffs2_put_link,
|
|
||||||
.setattr = jffs2_setattr
|
.setattr = jffs2_setattr
|
||||||
};
|
};
|
||||||
|
|
||||||
static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
|
static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||||
{
|
{
|
||||||
unsigned char *buf;
|
struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
|
||||||
buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
|
|
||||||
nd_set_link(nd, buf);
|
/*
|
||||||
|
* 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));
|
||||||
|
|
||||||
|
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;
|
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);
|
|
||||||
}
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* For licensing information, see the file 'LICENCE' in this directory.
|
* 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,20 +644,23 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
|
|||||||
|
|
||||||
down(&dead_f->sem);
|
down(&dead_f->sem);
|
||||||
|
|
||||||
while (dead_f->dents) {
|
if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) {
|
||||||
/* There can be only deleted ones */
|
while (dead_f->dents) {
|
||||||
fd = dead_f->dents;
|
/* There can be only deleted ones */
|
||||||
|
fd = dead_f->dents;
|
||||||
dead_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",
|
if (fd->ino) {
|
||||||
dead_f->inocache->ino, fd->name, fd->ino);
|
printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
|
||||||
} else {
|
dead_f->inocache->ino, fd->name, fd->ino);
|
||||||
D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->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--;
|
dead_f->inocache->nlink--;
|
||||||
|
Loading…
Reference in New Issue
Block a user