diff options
Diffstat (limited to 'fs/jffs2/symlink.c')
-rw-r--r-- | fs/jffs2/symlink.c | 42 |
1 files changed, 30 insertions, 12 deletions
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 | } | ||