Testing with the connectathon tests caused this panic:

[  388.266918] ------------[ cut here ]------------
[  388.267823] kernel BUG at fs/dcache.c:1358!

[...]

[  388.267823] RIP: 0010:[<ffffffff81129146>]  [<ffffffff81129146>] 
d_set_d_op+0x10/0x58

[...]

[  388.267823] Call Trace:
[  388.267823]  [<ffffffffa0147a3c>] cifs_create+0x5cd/0x6fe [cifs]
[  388.267823]  [<ffffffff81123c5d>] vfs_create+0x70/0x91
[  388.267823]  [<ffffffff8112499d>] do_last+0x15a/0x2ff
[  388.267823]  [<ffffffff81124e41>] do_filp_open+0x2ff/0x6db
[  388.267823]  [<ffffffff8110ca5f>] ? kmem_cache_free+0x76/0xb4
[  388.267823]  [<ffffffff81464c6b>] ? _cond_resched+0xe/0x22
[  388.267823]  [<ffffffff81229300>] ? might_fault+0x21/0x23
[  388.267823]  [<ffffffff81229400>] ? __strncpy_from_user+0x1f/0x4e
[  388.267823]  [<ffffffff8112eb70>] ? alloc_fd+0x74/0x11f
[  388.267823]  [<ffffffff81118808>] do_sys_open+0x60/0xf2
[  388.267823]  [<ffffffff810992e3>] ? audit_syscall_entry+0x11c/0x148
[  388.267823]  [<ffffffff811188ba>] sys_open+0x20/0x22
[  388.267823]  [<ffffffff811188e4>] sys_creat+0x15/0x17
[  388.267823]  [<ffffffff8100ac42>] system_call_fastpath+0x16/0x1b
[  388.436446] ---[ end trace a012e6143ebad719 ]---

The problem is that d_op is already set during the lookup. d_set_d_op
will BUG() if you try to set operations when they have already been set.

Remove all of the d_set_d_op calls except for during lookups and ensure
that it gets set on every lookup.

Signed-off-by: Jeff Layton <[email protected]>
---
 fs/cifs/dir.c   |   32 +++++++-------------------------
 fs/cifs/inode.c |    9 ---------
 fs/cifs/link.c  |    9 ++-------
 3 files changed, 9 insertions(+), 41 deletions(-)

diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 2e77382..1bb1729 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -130,17 +130,6 @@ cifs_bp_rename_retry:
        return full_path;
 }
 
-static void setup_cifs_dentry(struct cifsTconInfo *tcon,
-                             struct dentry *direntry,
-                             struct inode *newinode)
-{
-       if (tcon->nocase)
-               d_set_d_op(direntry, &cifs_ci_dentry_ops);
-       else
-               d_set_d_op(direntry, &cifs_dentry_ops);
-       d_instantiate(direntry, newinode);
-}
-
 /* Inode operations in similar order to how they appear in Linux file fs.h */
 
 int
@@ -327,7 +316,7 @@ cifs_create_get_file_info:
 
 cifs_create_set_dentry:
        if (rc == 0)
-               setup_cifs_dentry(tcon, direntry, newinode);
+               d_instantiate(direntry, newinode);
        else
                cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
 
@@ -418,11 +407,6 @@ int cifs_mknod(struct inode *inode, struct dentry 
*direntry, int mode,
 
                rc = cifs_get_inode_info_unix(&newinode, full_path,
                                                inode->i_sb, xid);
-               if (pTcon->nocase)
-                       d_set_d_op(direntry, &cifs_ci_dentry_ops);
-               else
-                       d_set_d_op(direntry, &cifs_dentry_ops);
-
                if (rc == 0)
                        d_instantiate(direntry, newinode);
                goto mknod_out;
@@ -522,6 +506,12 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry 
*direntry,
        }
        pTcon = tlink_tcon(tlink);
 
+       /* set dentry operations */
+       if (pTcon->nocase)
+               d_set_d_op(direntry, &cifs_ci_dentry_ops);
+       else
+               d_set_d_op(direntry, &cifs_dentry_ops);
+
        /*
         * Don't allow the separator character in a path component.
         * The VFS will not allow "/", but "\" is allowed by posix.
@@ -601,10 +591,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry 
*direntry,
                                parent_dir_inode->i_sb, xid, NULL);
 
        if ((rc == 0) && (newInode != NULL)) {
-               if (pTcon->nocase)
-                       d_set_d_op(direntry, &cifs_ci_dentry_ops);
-               else
-                       d_set_d_op(direntry, &cifs_dentry_ops);
                d_add(direntry, newInode);
                if (posix_open) {
                        filp = lookup_instantiate_filp(nd, direntry,
@@ -631,10 +617,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry 
*direntry,
        } else if (rc == -ENOENT) {
                rc = 0;
                direntry->d_time = jiffies;
-               if (pTcon->nocase)
-                       d_set_d_op(direntry, &cifs_ci_dentry_ops);
-               else
-                       d_set_d_op(direntry, &cifs_dentry_ops);
                d_add(direntry, NULL);
        /*      if it was once a directory (but how can we tell?) we could do
                shrink_dcache_parent(direntry); */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 0c7e369..74e1e82 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1324,11 +1324,6 @@ int cifs_mkdir(struct inode *inode, struct dentry 
*direntry, int mode)
 /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
        to set uid/gid */
                        inc_nlink(inode);
-                       if (pTcon->nocase)
-                               d_set_d_op(direntry, &cifs_ci_dentry_ops);
-                       else
-                               d_set_d_op(direntry, &cifs_dentry_ops);
-
                        cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
                        cifs_fill_uniqueid(inode->i_sb, &fattr);
                        newinode = cifs_iget(inode->i_sb, &fattr);
@@ -1368,10 +1363,6 @@ mkdir_get_info:
                        rc = cifs_get_inode_info(&newinode, full_path, NULL,
                                                 inode->i_sb, xid, NULL);
 
-               if (pTcon->nocase)
-                       d_set_d_op(direntry, &cifs_ci_dentry_ops);
-               else
-                       d_set_d_op(direntry, &cifs_dentry_ops);
                d_instantiate(direntry, newinode);
                 /* setting nlink not necessary except in cases where we
                  * failed to get it from the server or was set bogus */
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index fe2f6a9..486efc5 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -520,16 +520,11 @@ cifs_symlink(struct inode *inode, struct dentry 
*direntry, const char *symname)
                        rc = cifs_get_inode_info(&newinode, full_path, NULL,
                                                 inode->i_sb, xid, NULL);
 
-               if (rc != 0) {
+               if (rc != 0)
                        cFYI(1, "Create symlink ok, getinodeinfo fail rc = %d",
                              rc);
-               } else {
-                       if (pTcon->nocase)
-                               d_set_d_op(direntry, &cifs_ci_dentry_ops);
-                       else
-                               d_set_d_op(direntry, &cifs_dentry_ops);
+               else
                        d_instantiate(direntry, newinode);
-               }
        }
 symlink_exit:
        kfree(full_path);
-- 
1.7.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to