| From d67362d7f09db555297d609330c876e3bc37bb32 Mon Sep 17 00:00:00 2001 |
| From: Jeff Layton <jlayton@redhat.com> |
| Date: Thu, 23 Feb 2012 09:37:45 -0500 |
| Subject: [PATCH] cifs: fix dentry refcount leak when opening a FIFO on lookup |
| |
| commit 5bccda0ebc7c0331b81ac47d39e4b920b198b2cd upstream. |
| |
| The cifs code will attempt to open files on lookup under certain |
| circumstances. What happens though if we find that the file we opened |
| was actually a FIFO or other special file? |
| |
| Currently, the open filehandle just ends up being leaked leading to |
| a dentry refcount mismatch and oops on umount. Fix this by having the |
| code close the filehandle on the server if it turns out not to be a |
| regular file. While we're at it, change this spaghetti if statement |
| into a switch too. |
| |
| Reported-by: CAI Qian <caiqian@redhat.com> |
| Tested-by: CAI Qian <caiqian@redhat.com> |
| Reviewed-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> |
| Signed-off-by: Jeff Layton <jlayton@redhat.com> |
| Signed-off-by: Steve French <smfrench@gmail.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c |
| index ff3d891..fc79b95 100644 |
| --- a/fs/cifs/dir.c |
| +++ b/fs/cifs/dir.c |
| @@ -692,10 +692,26 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, |
| * If either that or op not supported returned, follow |
| * the normal lookup. |
| */ |
| - if ((rc == 0) || (rc == -ENOENT)) |
| + switch (rc) { |
| + case 0: |
| + /* |
| + * The server may allow us to open things like |
| + * FIFOs, but the client isn't set up to deal |
| + * with that. If it's not a regular file, just |
| + * close it and proceed as if it were a normal |
| + * lookup. |
| + */ |
| + if (newInode && !S_ISREG(newInode->i_mode)) { |
| + CIFSSMBClose(xid, pTcon, fileHandle); |
| + break; |
| + } |
| + case -ENOENT: |
| posix_open = true; |
| - else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP)) |
| + case -EOPNOTSUPP: |
| + break; |
| + default: |
| pTcon->broken_posix_open = true; |
| + } |
| } |
| if (!posix_open) |
| rc = cifs_get_inode_info_unix(&newInode, full_path, |
| -- |
| 1.7.9.7 |
| |