diff options
author | Artem B. Bityuckiy <dedekind@infradead.org> | 2005-03-01 05:50:52 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-05-23 06:48:15 -0400 |
commit | 32f1a95d505b99b1f01b6aeea36ec3f97245b357 (patch) | |
tree | 5da0e8b01362cf6b0cc79f11e5e9b3fd4ad169d6 | |
parent | 20a6c211903dce92a0db7f19c221cfa3f2cb4c32 (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.c | 28 | ||||
-rw-r--r-- | fs/jffs2/read.c | 32 | ||||
-rw-r--r-- | fs/jffs2/readinode.c | 54 | ||||
-rw-r--r-- | fs/jffs2/symlink.c | 42 | ||||
-rw-r--r-- | fs/jffs2/write.c | 31 |
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. */ | ||
218 | char *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 | ||
21 | static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); | 21 | static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); |
22 | static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd); | ||
23 | 22 | ||
24 | struct inode_operations jffs2_symlink_inode_operations = | 23 | struct 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 | ||
32 | static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) | 30 | static 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 | ||
40 | static 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--; |