@@ -584,9 +584,12 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
char *full_path = NULL;
char *s, *p;
char sep;
+ int rc;
+ unsigned int xid;
+ struct inode *rinode = NULL;
+ struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
- full_path = cifs_build_path_to_root(vol, cifs_sb,
- cifs_sb_master_tcon(cifs_sb));
+ full_path = cifs_build_path_to_root(vol, cifs_sb, tcon);
if (full_path == NULL)
return ERR_PTR(-ENOMEM);
@@ -627,6 +630,24 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
dput(dentry);
dentry = child;
} while (!IS_ERR(dentry));
+ if (IS_ERR(dentry) && (PTR_ERR(dentry) == -EACCES) && *s) {
+ xid = get_xid();
+ if (tcon->unix_ext) {
+ rc = cifs_get_inode_info_unix(&rinode, full_path,
+ sb, xid);
+ } else {
+ rc = cifs_get_inode_info(&rinode, full_path, NULL,
+ sb, xid, NULL);
+ }
+ free_xid(xid);
+
+ if ((rc == 0) && (rinode != NULL)) {
+ dentry = d_obtain_alias(rinode);
+ if (IS_ERR(dentry))
+ iput(rinode);
+ }
+ }
+
kfree(full_path);
return dentry;
}
@@ -702,6 +702,7 @@ 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;
xid = get_xid();
@@ -748,11 +749,19 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
}
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);
-
+ ret = d_splice_alias(newInode, direntry);
+ if (!ret)
+ renew_parental_timestamps(direntry);
+ else {
+ if (!IS_ERR(ret)) {
+ renew_parental_timestamps(direntry);
+ dput(ret);
+ goto lookup_out;
+ } else
+ rc = PTR_ERR(ret);
+ }
} else if (rc == -ENOENT) {
rc = 0;
direntry->d_time = jiffies;
@@ -764,12 +773,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 int
@@ -885,8 +885,10 @@ inode_has_hashed_dentries(struct inode *inode)
spin_lock(&inode->i_lock);
hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
- spin_unlock(&inode->i_lock);
- return true;
+ if (!(dentry->d_flags & DCACHE_DISCONNECTED)) {
+ spin_unlock(&inode->i_lock);
+ return true;
+ }
}
}
spin_unlock(&inode->i_lock);