From: shirish <[email protected]>

splice the dentry during lookup.  In case of servers who do not provide
uniqueids, look in the linked list off of superblock before sending
out a query on the wire and also do a dentry search before splicing
and free the entry in the linked list.

Signed-off-by: Shirish Pargaonkar <[email protected]>
---
 fs/cifs/dir.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 57 insertions(+), 11 deletions(-)

diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index d835ae2..b6ebb8c 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -691,7 +691,7 @@ mknod_out:
        return rc;
 }
 
-struct cifs_rdelem *
+static struct cifs_rdelem *
 find_rdelem_by_inode(struct inode *rdinode, struct cifs_sb_info * cifs_sb)
 {
        struct cifs_rdelem *rdelem;
@@ -726,7 +726,7 @@ find_rdelem_by_dentry(const struct dentry *rdentry,
        return NULL;
 }
 
-void
+static void
 find_rdelem_by_path(char *full_path, struct inode **newInode,
                        struct cifs_sb_info * cifs_sb)
 {
@@ -754,6 +754,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry 
*direntry,
        struct cifs_tcon *pTcon;
        struct inode *newInode = NULL;
        char *full_path = NULL;
+       struct dentry *ret = NULL;
+       struct cifs_rdelem *rdelem;
+       struct qstr dname;
 
        xid = get_xid();
 
@@ -791,20 +794,62 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry 
*direntry,
        cifs_dbg(FYI, "Full path: %s inode = 0x%p\n",
                 full_path, direntry->d_inode);
 
-       if (pTcon->unix_ext) {
-               rc = cifs_get_inode_info_unix(&newInode, full_path,
-                                             parent_dir_inode->i_sb, xid);
-       } else {
-               rc = cifs_get_inode_info(&newInode, full_path, NULL,
-                               parent_dir_inode->i_sb, xid, NULL);
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
+               /*
+                * Looking for an existing disconnected root dentry if any,
+                * before sending out a lookup on the wire.
+                */
+               find_rdelem_by_path(full_path, &newInode, cifs_sb);
        }
 
+       if (!newInode) {
+               if (pTcon->unix_ext) {
+                       rc = cifs_get_inode_info_unix(&newInode, full_path,
+                                       parent_dir_inode->i_sb, xid);
+               } else
+                       rc = cifs_get_inode_info(&newInode, full_path, NULL,
+                                       parent_dir_inode->i_sb, xid, NULL);
+       }
+       /* else, found an anonymous root dentry with an inode */
+
        if ((rc == 0) && (newInode != NULL)) {
-               d_add(direntry, newInode);
                /* since paths are not looked up by component - the parent
                   directories are presumed to be good here */
-               renew_parental_timestamps(direntry);
+               if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
+                       dname.name = direntry->d_name.name;
+                       dname.len = strlen(direntry->d_name.name) + 1;
+                       /*
+                        * Perhaps another lookup beat us to this.
+                        */
+                       spin_lock(&cifs_sb->rtdislock);
+                       ret = d_lookup(direntry->d_parent, &dname);
+                       if (ret && !IS_ERR(ret)) {
+                               dput(ret);
+                               spin_unlock(&cifs_sb->rtdislock);
+                               goto lookup_out;
+                       } else
+                               ret = d_splice_alias(newInode, direntry);
+                       spin_unlock(&cifs_sb->rtdislock);
+               } else
+                       ret = d_splice_alias(newInode, direntry);
 
+               if (!ret)
+                       renew_parental_timestamps(direntry);
+               else {
+                       if (!IS_ERR(ret)) {
+                               if (!(cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_SERVER_INUM)) {
+                                       rdelem =
+                                       find_rdelem_by_inode(newInode, cifs_sb);
+                                       if (rdelem)
+                                               cifs_free_rdelem(rdelem);
+                               }
+                               renew_parental_timestamps(ret);
+                               dput(ret);
+                               goto lookup_out;
+                       } else
+                               rc = PTR_ERR(ret);
+               }
        } else if (rc == -ENOENT) {
                rc = 0;
                direntry->d_time = jiffies;
@@ -816,12 +861,13 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry 
*direntry,
                /* We special case check for Access Denied - since that
                is a common return code */
        }
+       ret = ERR_PTR(rc);
 
 lookup_out:
        kfree(full_path);
        cifs_put_tlink(tlink);
        free_xid(xid);
-       return ERR_PTR(rc);
+       return ret;
 }
 
 static void
-- 
1.8.4.5

--
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