diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2011-01-18 09:49:08 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2011-01-18 09:49:08 -0500 |
commit | 24d9765fc18c7838ccdbb0d71fb706321d9b824c (patch) | |
tree | 75875b69c1bb694d2ad5e1ab19f278bf7d3a8acc /fs | |
parent | 23c3010808de86f21436eb822aacfa551bfc17e4 (diff) |
GFS2: Fix error path in gfs2_lookup_by_inum()
In the (impossible, except if there is fs corruption) error path
in gfs2_lookup_by_inum() if the call to gfs2_inode_refresh()
fails, it was leaving the function by calling iput() rather
than iget_failed(). This would cause future lookups of the same
inode to block forever.
This patch fixes the problem by moving the call to gfs2_inode_refresh()
into gfs2_inode_lookup() where iget_failed() is part of the error path
already. Also this cleans up some unreachable code and makes
gfs2_set_iop() static.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/inode.c | 72 | ||||
-rw-r--r-- | fs/gfs2/inode.h | 1 |
2 files changed, 22 insertions, 51 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 2232b3c780bd..7aa7d4f8984a 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -74,16 +74,14 @@ static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr) | |||
74 | } | 74 | } |
75 | 75 | ||
76 | /** | 76 | /** |
77 | * GFS2 lookup code fills in vfs inode contents based on info obtained | 77 | * gfs2_set_iop - Sets inode operations |
78 | * from directory entry inside gfs2_inode_lookup(). This has caused issues | 78 | * @inode: The inode with correct i_mode filled in |
79 | * with NFS code path since its get_dentry routine doesn't have the relevant | ||
80 | * directory entry when gfs2_inode_lookup() is invoked. Part of the code | ||
81 | * segment inside gfs2_inode_lookup code needs to get moved around. | ||
82 | * | 79 | * |
83 | * Clears I_NEW as well. | 80 | * GFS2 lookup code fills in vfs inode contents based on info obtained |
84 | **/ | 81 | * from directory entry inside gfs2_inode_lookup(). |
82 | */ | ||
85 | 83 | ||
86 | void gfs2_set_iop(struct inode *inode) | 84 | static void gfs2_set_iop(struct inode *inode) |
87 | { | 85 | { |
88 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 86 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
89 | umode_t mode = inode->i_mode; | 87 | umode_t mode = inode->i_mode; |
@@ -106,8 +104,6 @@ void gfs2_set_iop(struct inode *inode) | |||
106 | inode->i_op = &gfs2_file_iops; | 104 | inode->i_op = &gfs2_file_iops; |
107 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | 105 | init_special_inode(inode, inode->i_mode, inode->i_rdev); |
108 | } | 106 | } |
109 | |||
110 | unlock_new_inode(inode); | ||
111 | } | 107 | } |
112 | 108 | ||
113 | /** | 109 | /** |
@@ -119,10 +115,8 @@ void gfs2_set_iop(struct inode *inode) | |||
119 | * Returns: A VFS inode, or an error | 115 | * Returns: A VFS inode, or an error |
120 | */ | 116 | */ |
121 | 117 | ||
122 | struct inode *gfs2_inode_lookup(struct super_block *sb, | 118 | struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, |
123 | unsigned int type, | 119 | u64 no_addr, u64 no_formal_ino) |
124 | u64 no_addr, | ||
125 | u64 no_formal_ino) | ||
126 | { | 120 | { |
127 | struct inode *inode; | 121 | struct inode *inode; |
128 | struct gfs2_inode *ip; | 122 | struct gfs2_inode *ip; |
@@ -152,51 +146,37 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, | |||
152 | error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); | 146 | error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); |
153 | if (unlikely(error)) | 147 | if (unlikely(error)) |
154 | goto fail_iopen; | 148 | goto fail_iopen; |
155 | ip->i_iopen_gh.gh_gl->gl_object = ip; | ||
156 | 149 | ||
150 | ip->i_iopen_gh.gh_gl->gl_object = ip; | ||
157 | gfs2_glock_put(io_gl); | 151 | gfs2_glock_put(io_gl); |
158 | io_gl = NULL; | 152 | io_gl = NULL; |
159 | 153 | ||
160 | if ((type == DT_UNKNOWN) && (no_formal_ino == 0)) | ||
161 | goto gfs2_nfsbypass; | ||
162 | |||
163 | inode->i_mode = DT2IF(type); | ||
164 | |||
165 | /* | ||
166 | * We must read the inode in order to work out its type in | ||
167 | * this case. Note that this doesn't happen often as we normally | ||
168 | * know the type beforehand. This code path only occurs during | ||
169 | * unlinked inode recovery (where it is safe to do this glock, | ||
170 | * which is not true in the general case). | ||
171 | */ | ||
172 | if (type == DT_UNKNOWN) { | 154 | if (type == DT_UNKNOWN) { |
173 | struct gfs2_holder gh; | 155 | /* Inode glock must be locked already */ |
174 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | 156 | error = gfs2_inode_refresh(GFS2_I(inode)); |
175 | if (unlikely(error)) | 157 | if (error) |
176 | goto fail_glock; | 158 | goto fail_refresh; |
177 | /* Inode is now uptodate */ | 159 | } else { |
178 | gfs2_glock_dq_uninit(&gh); | 160 | inode->i_mode = DT2IF(type); |
179 | } | 161 | } |
180 | 162 | ||
181 | gfs2_set_iop(inode); | 163 | gfs2_set_iop(inode); |
164 | unlock_new_inode(inode); | ||
182 | } | 165 | } |
183 | 166 | ||
184 | gfs2_nfsbypass: | ||
185 | return inode; | 167 | return inode; |
186 | fail_glock: | 168 | |
187 | gfs2_glock_dq(&ip->i_iopen_gh); | 169 | fail_refresh: |
170 | ip->i_iopen_gh.gh_gl->gl_object = NULL; | ||
171 | gfs2_glock_dq_uninit(&ip->i_iopen_gh); | ||
188 | fail_iopen: | 172 | fail_iopen: |
189 | if (io_gl) | 173 | if (io_gl) |
190 | gfs2_glock_put(io_gl); | 174 | gfs2_glock_put(io_gl); |
191 | fail_put: | 175 | fail_put: |
192 | if (inode->i_state & I_NEW) | 176 | ip->i_gl->gl_object = NULL; |
193 | ip->i_gl->gl_object = NULL; | ||
194 | gfs2_glock_put(ip->i_gl); | 177 | gfs2_glock_put(ip->i_gl); |
195 | fail: | 178 | fail: |
196 | if (inode->i_state & I_NEW) | 179 | iget_failed(inode); |
197 | iget_failed(inode); | ||
198 | else | ||
199 | iput(inode); | ||
200 | return ERR_PTR(error); | 180 | return ERR_PTR(error); |
201 | } | 181 | } |
202 | 182 | ||
@@ -221,14 +201,6 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, | |||
221 | if (IS_ERR(inode)) | 201 | if (IS_ERR(inode)) |
222 | goto fail; | 202 | goto fail; |
223 | 203 | ||
224 | error = gfs2_inode_refresh(GFS2_I(inode)); | ||
225 | if (error) | ||
226 | goto fail_iput; | ||
227 | |||
228 | /* Pick up the works we bypass in gfs2_inode_lookup */ | ||
229 | if (inode->i_state & I_NEW) | ||
230 | gfs2_set_iop(inode); | ||
231 | |||
232 | /* Two extra checks for NFS only */ | 204 | /* Two extra checks for NFS only */ |
233 | if (no_formal_ino) { | 205 | if (no_formal_ino) { |
234 | error = -ESTALE; | 206 | error = -ESTALE; |
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 732a183efdb3..3e00a66e7cbd 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h | |||
@@ -96,7 +96,6 @@ err: | |||
96 | return -EIO; | 96 | return -EIO; |
97 | } | 97 | } |
98 | 98 | ||
99 | extern void gfs2_set_iop(struct inode *inode); | ||
100 | extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, | 99 | extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, |
101 | u64 no_addr, u64 no_formal_ino); | 100 | u64 no_addr, u64 no_formal_ino); |
102 | extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, | 101 | extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, |