diff options
author | Jeff Layton <jlayton@redhat.com> | 2008-07-12 16:47:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-12 17:33:42 -0400 |
commit | e911d0cc877ff027d5bd09fc33148ab76f0fdf0e (patch) | |
tree | c2549fb1caa266f17d25c20e0c499db823578372 /fs/cifs | |
parent | d3297a644a0ab784e0c810ceca6bf35a67868ad9 (diff) |
cifs: fix inode leak in cifs_get_inode_info_unix
Try this:
mount a share with unix extensions
create a file on it
umount the share
You'll get the following message in the ring buffer:
VFS: Busy inodes after unmount of cifs. Self-destruct in 5 seconds. Have a
nice day...
...the problem is that cifs_get_inode_info_unix is creating and hashing
a new inode even when it's going to return error anyway. The first
lookup when creating a file returns an error so we end up leaking this
inode before we do the actual create. This appears to be a regression
caused by commit 0e4bbde94fdc33f5b3d793166b21bf768ca3e098.
The following patch seems to fix it for me, and fixes a minor
formatting nit as well.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Acked-by: Steven French <sfrench@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/inode.c | 20 |
1 files changed, 10 insertions, 10 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 722be543ceec..2e904bd111c8 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -219,15 +219,15 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
219 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data, | 219 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data, |
220 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 220 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
221 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 221 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
222 | if (rc) { | 222 | if (rc == -EREMOTE && !is_dfs_referral) { |
223 | if (rc == -EREMOTE && !is_dfs_referral) { | 223 | is_dfs_referral = true; |
224 | is_dfs_referral = true; | 224 | cFYI(DBG2, ("DFS ref")); |
225 | cFYI(DBG2, ("DFS ref")); | 225 | /* for DFS, server does not give us real inode data */ |
226 | /* for DFS, server does not give us real inode data */ | 226 | fill_fake_finddataunix(&find_data, sb); |
227 | fill_fake_finddataunix(&find_data, sb); | 227 | rc = 0; |
228 | rc = 0; | 228 | } else if (rc) |
229 | } | 229 | goto cgiiu_exit; |
230 | } | 230 | |
231 | num_of_bytes = le64_to_cpu(find_data.NumOfBytes); | 231 | num_of_bytes = le64_to_cpu(find_data.NumOfBytes); |
232 | end_of_file = le64_to_cpu(find_data.EndOfFile); | 232 | end_of_file = le64_to_cpu(find_data.EndOfFile); |
233 | 233 | ||
@@ -236,7 +236,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
236 | *pinode = new_inode(sb); | 236 | *pinode = new_inode(sb); |
237 | if (*pinode == NULL) { | 237 | if (*pinode == NULL) { |
238 | rc = -ENOMEM; | 238 | rc = -ENOMEM; |
239 | goto cgiiu_exit; | 239 | goto cgiiu_exit; |
240 | } | 240 | } |
241 | /* Is an i_ino of zero legal? */ | 241 | /* Is an i_ino of zero legal? */ |
242 | /* note ino incremented to unique num in new_inode */ | 242 | /* note ino incremented to unique num in new_inode */ |