aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDave Johnson <djohnson+linux-kernel@sw.starentnetworks.com>2005-09-06 18:17:40 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:57:33 -0400
commita97c9bf33f4612e2aed6f000f6b1d268b6814f3c (patch)
tree5950b47e63f046ff4ce0812720a356ca3eac20dd /fs
parent7f4bde9a3486cd7e70bedd2aff35b38667d50173 (diff)
[PATCH] fix cramfs making duplicate entries in inode cache
Every time cramfs_lookup() is called to lookup and inode for a dentry, get_cramfs_inode() will allocate a new inode without checking to see if that inode already exists in the inode cache. This is fine the first time, but if the dentry cache entry(ies) associated with that inode are aged out, but the inode entry is not aged out (which can be quite common if the inode has buffer cache linked to it), cramfs_lookup() will be called again and another inode will be allocated and added to the inode cache creating a duplicate in the inode cache. The big issue here is that the buffers associated with each inode cache entry are not shared between the duplicates! The older inode entries are now orphaned as no dentry points to it and won't be freed until the buffer cache assoicated with them are first freed. The newest entry will have to create all new buffer cache for each part of its file as the old buffer cache is now orphaned as well. Patch below fixes this by making get_cramfs_inode() use the inode cache before blindly creating a new entry every time. This eliminates the duplicate inodes and duplicate buffer cache. Cc: Phillip Lougher <phillip@lougher.demon.co.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/cramfs/inode.c43
1 files changed, 39 insertions, 4 deletions
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 6c285efa2004..7fe85415ae7c 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -39,12 +39,47 @@ static DECLARE_MUTEX(read_mutex);
39#define CRAMINO(x) ((x)->offset?(x)->offset<<2:1) 39#define CRAMINO(x) ((x)->offset?(x)->offset<<2:1)
40#define OFFSET(x) ((x)->i_ino) 40#define OFFSET(x) ((x)->i_ino)
41 41
42static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode) 42
43static int cramfs_iget5_test(struct inode *inode, void *opaque)
44{
45 struct cramfs_inode *cramfs_inode = opaque;
46
47 if (inode->i_ino != CRAMINO(cramfs_inode))
48 return 0; /* does not match */
49
50 if (inode->i_ino != 1)
51 return 1;
52
53 /* all empty directories, char, block, pipe, and sock, share inode #1 */
54
55 if ((inode->i_mode != cramfs_inode->mode) ||
56 (inode->i_gid != cramfs_inode->gid) ||
57 (inode->i_uid != cramfs_inode->uid))
58 return 0; /* does not match */
59
60 if ((S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) &&
61 (inode->i_rdev != old_decode_dev(cramfs_inode->size)))
62 return 0; /* does not match */
63
64 return 1; /* matches */
65}
66
67static int cramfs_iget5_set(struct inode *inode, void *opaque)
68{
69 struct cramfs_inode *cramfs_inode = opaque;
70 inode->i_ino = CRAMINO(cramfs_inode);
71 return 0;
72}
73
74static struct inode *get_cramfs_inode(struct super_block *sb,
75 struct cramfs_inode * cramfs_inode)
43{ 76{
44 struct inode * inode = new_inode(sb); 77 struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),
78 cramfs_iget5_test, cramfs_iget5_set,
79 cramfs_inode);
45 static struct timespec zerotime; 80 static struct timespec zerotime;
46 81
47 if (inode) { 82 if (inode && (inode->i_state & I_NEW)) {
48 inode->i_mode = cramfs_inode->mode; 83 inode->i_mode = cramfs_inode->mode;
49 inode->i_uid = cramfs_inode->uid; 84 inode->i_uid = cramfs_inode->uid;
50 inode->i_size = cramfs_inode->size; 85 inode->i_size = cramfs_inode->size;
@@ -58,7 +93,6 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod
58 but it's the best we can do without reading the directory 93 but it's the best we can do without reading the directory
59 contents. 1 yields the right result in GNU find, even 94 contents. 1 yields the right result in GNU find, even
60 without -noleaf option. */ 95 without -noleaf option. */
61 insert_inode_hash(inode);
62 if (S_ISREG(inode->i_mode)) { 96 if (S_ISREG(inode->i_mode)) {
63 inode->i_fop = &generic_ro_fops; 97 inode->i_fop = &generic_ro_fops;
64 inode->i_data.a_ops = &cramfs_aops; 98 inode->i_data.a_ops = &cramfs_aops;
@@ -74,6 +108,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod
74 init_special_inode(inode, inode->i_mode, 108 init_special_inode(inode, inode->i_mode,
75 old_decode_dev(cramfs_inode->size)); 109 old_decode_dev(cramfs_inode->size));
76 } 110 }
111 unlock_new_inode(inode);
77 } 112 }
78 return inode; 113 return inode;
79} 114}