cifs_get_root shouldn't use path with tree name

When a server returns the optional flag SMB_SHARE_IS_IN_DFS in response
to a tree connect, cifs_build_path_to_root() will return a pathname
which includes the hostname. This causes problems with cifs_get_root()
which separates each component and does a lookup for each component of
the path which in this case will incorrectly include looking up the
hostname component as a path component.

We encountered a problem with dfs shares hosted by a Netapp. When
connecting to nodes pointed to by the DFS share. The tree connect for
these nodes return SMB_SHARE_IS_IN_DFS resulting failures in lookup
in cifs_get_root().

RH bz: 1373153
The patch was tested against a Netapp simulator and by a user using an
actual Netapp server.

Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
Reported-by: Pierguido Lambri <plambri@redhat.com>
Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>

authored by Sachin Prabhu and committed by Steve French 374402a2 39566443

+7 -5
+1 -1
fs/cifs/cifsfs.c
··· 615 return dget(sb->s_root); 616 617 full_path = cifs_build_path_to_root(vol, cifs_sb, 618 - cifs_sb_master_tcon(cifs_sb)); 619 if (full_path == NULL) 620 return ERR_PTR(-ENOMEM); 621
··· 615 return dget(sb->s_root); 616 617 full_path = cifs_build_path_to_root(vol, cifs_sb, 618 + cifs_sb_master_tcon(cifs_sb), 0); 619 if (full_path == NULL) 620 return ERR_PTR(-ENOMEM); 621
+2 -1
fs/cifs/cifsproto.h
··· 63 extern char *build_path_from_dentry(struct dentry *); 64 extern char *cifs_build_path_to_root(struct smb_vol *vol, 65 struct cifs_sb_info *cifs_sb, 66 - struct cifs_tcon *tcon); 67 extern char *build_wildcard_path_from_dentry(struct dentry *direntry); 68 extern char *cifs_compose_mount_options(const char *sb_mountdata, 69 const char *fullpath, const struct dfs_info3_param *ref,
··· 63 extern char *build_path_from_dentry(struct dentry *); 64 extern char *cifs_build_path_to_root(struct smb_vol *vol, 65 struct cifs_sb_info *cifs_sb, 66 + struct cifs_tcon *tcon, 67 + int add_treename); 68 extern char *build_wildcard_path_from_dentry(struct dentry *direntry); 69 extern char *cifs_compose_mount_options(const char *sb_mountdata, 70 const char *fullpath, const struct dfs_info3_param *ref,
+2 -1
fs/cifs/connect.c
··· 3765 /* 3766 * cifs_build_path_to_root works only when we have a valid tcon 3767 */ 3768 - full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon); 3769 if (full_path == NULL) { 3770 rc = -ENOMEM; 3771 goto mount_fail_check;
··· 3765 /* 3766 * cifs_build_path_to_root works only when we have a valid tcon 3767 */ 3768 + full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon, 3769 + tcon->Flags & SMB_SHARE_IS_IN_DFS); 3770 if (full_path == NULL) { 3771 rc = -ENOMEM; 3772 goto mount_fail_check;
+2 -2
fs/cifs/dir.c
··· 47 48 char * 49 cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, 50 - struct cifs_tcon *tcon) 51 { 52 int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0; 53 int dfsplen; ··· 59 return full_path; 60 } 61 62 - if (tcon->Flags & SMB_SHARE_IS_IN_DFS) 63 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); 64 else 65 dfsplen = 0;
··· 47 48 char * 49 cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, 50 + struct cifs_tcon *tcon, int add_treename) 51 { 52 int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0; 53 int dfsplen; ··· 59 return full_path; 60 } 61 62 + if (add_treename) 63 dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); 64 else 65 dfsplen = 0;