aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtem B. Bityuckiy <dedekind@infradead.org>2005-03-01 05:50:52 -0500
committerThomas Gleixner <tglx@mtd.linutronix.de>2005-05-23 06:48:15 -0400
commit32f1a95d505b99b1f01b6aeea36ec3f97245b357 (patch)
tree5da0e8b01362cf6b0cc79f11e5e9b3fd4ad169d6
parent20a6c211903dce92a0db7f19c221cfa3f2cb4c32 (diff)
[JFFS2] Add symlink caching support.
Signed-off-by: Artem B. Bityuckiy <dedekind@infradead.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--fs/jffs2/dir.c28
-rw-r--r--fs/jffs2/read.c32
-rw-r--r--fs/jffs2/readinode.c54
-rw-r--r--fs/jffs2/symlink.c42
-rw-r--r--fs/jffs2/write.c31
5 files changed, 117 insertions, 70 deletions
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 757306fa3ff4..6421be874ce3 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: dir.c,v 1.84 2004/11/16 20:36:11 dwmw2 Exp $ 10 * $Id: dir.c,v 1.85 2005/03/01 10:34:03 dedekind Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -296,11 +296,11 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
296 struct jffs2_full_dirent *fd; 296 struct jffs2_full_dirent *fd;
297 int namelen; 297 int namelen;
298 uint32_t alloclen, phys_ofs; 298 uint32_t alloclen, phys_ofs;
299 int ret; 299 int ret, targetlen = strlen(target);
300 300
301 /* FIXME: If you care. We'd need to use frags for the target 301 /* FIXME: If you care. We'd need to use frags for the target
302 if it grows much more than this */ 302 if it grows much more than this */
303 if (strlen(target) > 254) 303 if (targetlen > 254)
304 return -EINVAL; 304 return -EINVAL;
305 305
306 ri = jffs2_alloc_raw_inode(); 306 ri = jffs2_alloc_raw_inode();
@@ -314,7 +314,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
314 * Just the node will do for now, though 314 * Just the node will do for now, though
315 */ 315 */
316 namelen = dentry->d_name.len; 316 namelen = dentry->d_name.len;
317 ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL); 317 ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL);
318 318
319 if (ret) { 319 if (ret) {
320 jffs2_free_raw_inode(ri); 320 jffs2_free_raw_inode(ri);
@@ -333,16 +333,16 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
333 333
334 f = JFFS2_INODE_INFO(inode); 334 f = JFFS2_INODE_INFO(inode);
335 335
336 inode->i_size = strlen(target); 336 inode->i_size = targetlen;
337 ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); 337 ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
338 ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); 338 ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
339 ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); 339 ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
340 340
341 ri->compr = JFFS2_COMPR_NONE; 341 ri->compr = JFFS2_COMPR_NONE;
342 ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target))); 342 ri->data_crc = cpu_to_je32(crc32(0, target, targetlen));
343 ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); 343 ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
344 344
345 fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL); 345 fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL);
346 346
347 jffs2_free_raw_inode(ri); 347 jffs2_free_raw_inode(ri);
348 348
@@ -353,6 +353,20 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
353 jffs2_clear_inode(inode); 353 jffs2_clear_inode(inode);
354 return PTR_ERR(fn); 354 return PTR_ERR(fn);
355 } 355 }
356
357 /* We use f->dents field to store the target path. */
358 f->dents = kmalloc(targetlen + 1, GFP_KERNEL);
359 if (!f->dents) {
360 printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1);
361 up(&f->sem);
362 jffs2_complete_reservation(c);
363 jffs2_clear_inode(inode);
364 return -ENOMEM;
365 }
366
367 memcpy(f->dents, target, targetlen + 1);
368 D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents));
369
356 /* No data here. Only a metadata node, which will be 370 /* No data here. Only a metadata node, which will be
357 obsoleted by the first data write 371 obsoleted by the first data write
358 */ 372 */
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c
index eb493dc06db7..c7f9068907cf 100644
--- a/fs/jffs2/read.c
+++ b/fs/jffs2/read.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $ 10 * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -214,33 +214,3 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
214 return 0; 214 return 0;
215} 215}
216 216
217/* Core function to read symlink target. */
218char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
219{
220 char *buf;
221 int ret;
222
223 down(&f->sem);
224
225 if (!f->metadata) {
226 printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino);
227 up(&f->sem);
228 return ERR_PTR(-EINVAL);
229 }
230 buf = kmalloc(f->metadata->size+1, GFP_USER);
231 if (!buf) {
232 up(&f->sem);
233 return ERR_PTR(-ENOMEM);
234 }
235 buf[f->metadata->size]=0;
236
237 ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size);
238
239 up(&f->sem);
240
241 if (ret) {
242 kfree(buf);
243 return ERR_PTR(ret);
244 }
245 return buf;
246}
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index a1980a9da531..ef552477c813 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: readinode.c,v 1.118 2005/02/27 23:01:33 dwmw2 Exp $ 10 * $Id: readinode.c,v 1.119 2005/03/01 10:34:03 dedekind Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -623,6 +623,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
623 case. */ 623 case. */
624 if (!je32_to_cpu(latest_node->isize)) 624 if (!je32_to_cpu(latest_node->isize))
625 latest_node->isize = latest_node->dsize; 625 latest_node->isize = latest_node->dsize;
626
627 if (f->inocache->state != INO_STATE_CHECKING) {
628 /* Symlink's inode data is the target path. Read it and
629 * keep in RAM to facilitate quick follow symlink operation.
630 * We use f->dents field to store the target path, which
631 * is somewhat ugly. */
632 f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
633 if (!f->dents) {
634 printk(KERN_WARNING "Can't allocate %d bytes of memory "
635 "for the symlink target path cache\n",
636 je32_to_cpu(latest_node->csize));
637 up(&f->sem);
638 jffs2_do_clear_inode(c, f);
639 return -ENOMEM;
640 }
641
642 ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node),
643 je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents);
644
645 if (ret || retlen != je32_to_cpu(latest_node->csize)) {
646 if (retlen != je32_to_cpu(latest_node->csize))
647 ret = -EIO;
648 kfree(f->dents);
649 f->dents = NULL;
650 up(&f->sem);
651 jffs2_do_clear_inode(c, f);
652 return -ret;
653 }
654
655 ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0';
656 D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n",
657 (char *)f->dents));
658 }
659
626 /* fall through... */ 660 /* fall through... */
627 661
628 case S_IFBLK: 662 case S_IFBLK:
@@ -683,12 +717,20 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
683 717
684 jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); 718 jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
685 719
686 fds = f->dents; 720 /* For symlink inodes we us f->dents to store the target path name */
721 if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) {
722 if (f->dents) {
723 kfree(f->dents);
724 f->dents = NULL;
725 }
726 } else {
727 fds = f->dents;
687 728
688 while(fds) { 729 while(fds) {
689 fd = fds; 730 fd = fds;
690 fds = fd->next; 731 fds = fd->next;
691 jffs2_free_full_dirent(fd); 732 jffs2_free_full_dirent(fd);
733 }
692 } 734 }
693 735
694 if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { 736 if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index 7b1820d13712..65ab6b001dca 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: symlink.c,v 1.14 2004/11/16 20:36:12 dwmw2 Exp $ 10 * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -19,27 +19,45 @@
19#include "nodelist.h" 19#include "nodelist.h"
20 20
21static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); 21static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
22static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd);
23 22
24struct inode_operations jffs2_symlink_inode_operations = 23struct inode_operations jffs2_symlink_inode_operations =
25{ 24{
26 .readlink = generic_readlink, 25 .readlink = generic_readlink,
27 .follow_link = jffs2_follow_link, 26 .follow_link = jffs2_follow_link,
28 .put_link = jffs2_put_link,
29 .setattr = jffs2_setattr 27 .setattr = jffs2_setattr
30}; 28};
31 29
32static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) 30static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
33{ 31{
34 unsigned char *buf; 32 struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
35 buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); 33
36 nd_set_link(nd, buf); 34 /*
35 * We don't acquire the f->sem mutex here since the only data we
36 * use is f->dents which in case of the symlink inode points to the
37 * symlink's target path.
38 *
39 * 1. If we are here the inode has already built and f->dents has
40 * to point to the target path.
41 * 2. Nobody uses f->dents (if the inode is symlink's inode). The
42 * exception is inode freeing function which frees f->dents. But
43 * it can't be called while we are here and before VFS has
44 * stopped using our f->dents string which we provide by means of
45 * nd_set_link() call.
46 */
47
48 if (!f->dents) {
49 printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n");
50 return -EIO;
51 }
52 D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents));
53
54 nd_set_link(nd, (char *)f->dents);
55
56 /*
57 * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe
58 * since the only way that may cause f->dents to be changed is iput() operation.
59 * But VFS will not use f->dents after iput() has been called.
60 */
37 return 0; 61 return 0;
38} 62}
39 63
40static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd)
41{
42 char *s = nd_get_link(nd);
43 if (!IS_ERR(s))
44 kfree(s);
45}
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index d6b4d55e70e4..f3910dc1c2c8 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: write.c,v 1.90 2005/01/28 18:53:01 hammache Exp $ 10 * $Id: write.c,v 1.91 2005/03/01 10:34:03 dedekind Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -644,20 +644,23 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
644 644
645 down(&dead_f->sem); 645 down(&dead_f->sem);
646 646
647 while (dead_f->dents) { 647 if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) {
648 /* There can be only deleted ones */ 648 while (dead_f->dents) {
649 fd = dead_f->dents; 649 /* There can be only deleted ones */
650 650 fd = dead_f->dents;
651 dead_f->dents = fd->next; 651
652 652 dead_f->dents = fd->next;
653 if (fd->ino) { 653
654 printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", 654 if (fd->ino) {
655 dead_f->inocache->ino, fd->name, fd->ino); 655 printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
656 } else { 656 dead_f->inocache->ino, fd->name, fd->ino);
657 D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino)); 657 } else {
658 D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n",
659 fd->name, dead_f->inocache->ino));
660 }
661 jffs2_mark_node_obsolete(c, fd->raw);
662 jffs2_free_full_dirent(fd);
658 } 663 }
659 jffs2_mark_node_obsolete(c, fd->raw);
660 jffs2_free_full_dirent(fd);
661 } 664 }
662 665
663 dead_f->inocache->nlink--; 666 dead_f->inocache->nlink--;