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