static void* cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) { struct dfs_info3_param *referrals = NULL; unsigned int num_referrals = 0; struct cifs_sb_info *cifs_sb; struct cifsSesInfo *ses; char *full_path = NULL; int xid, i; int rc = 0; struct vfsmount *mnt = ERR_PTR(-ENOENT); cFYI(1, "in %s", __func__); BUG_ON(IS_ROOT(dentry)); xid = GetXid(); dput(nd->path.dentry); nd->path.dentry = dget(dentry); cifs_sb = CIFS_SB(dentry->d_inode->i_sb); ses = cifs_sb->tcon->ses; if (!ses) { rc = -EINVAL; goto out_err; } /* * The MSDFS spec states that paths in DFS referral requests and * responses must be prefixed by a single '\' character instead of * the double backslashes usually used in the UNC. This function * gives us the latter, so we must adjust the result. */ full_path = build_path_from_dentry(dentry); if (full_path == NULL) { rc = -ENOMEM; goto out_err; } rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb->local_nls, &num_referrals, &referrals, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); for (i = 0; i < num_referrals; i++) { int len; dump_referral(referrals+i); /* connect to a node */ len = strlen(referrals[i].node_name); if (len < 2) { cERROR(1, "%s: Net Address path too short: %s", __func__, referrals[i].node_name); rc = -EINVAL; goto out_err; } mnt = cifs_dfs_do_refmount(cifs_sb, full_path, referrals + i); cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, referrals[i].node_name, mnt); /* complete mount procedure if we accured submount */ if (!IS_ERR(mnt)) break; } /* we need it cause for() above could exit without valid submount */ rc = PTR_ERR(mnt); if (IS_ERR(mnt)) goto out_err; rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list); out: FreeXid(xid); free_dfs_info_array(referrals, num_referrals); kfree(full_path); cFYI(1, "leaving %s" , __func__); return ERR_PTR(rc); out_err: path_put(&nd->path); goto out; }
static void* cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) { struct dfs_info3_param *referrals = NULL; unsigned int num_referrals = 0; struct cifs_sb_info *cifs_sb; struct cifsSesInfo *ses; char *full_path = NULL; int xid, i; int rc = 0; struct vfsmount *mnt = ERR_PTR(-ENOENT); cFYI(1, ("in %s", __func__)); BUG_ON(IS_ROOT(dentry)); xid = GetXid(); dput(nd->path.dentry); nd->path.dentry = dget(dentry); cifs_sb = CIFS_SB(dentry->d_inode->i_sb); ses = cifs_sb->tcon->ses; if (!ses) { rc = -EINVAL; goto out_err; } full_path = build_path_from_dentry(dentry); if (full_path == NULL) { rc = -ENOMEM; goto out_err; } rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls, &num_referrals, &referrals, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); for (i = 0; i < num_referrals; i++) { dump_referral(referrals+i); /* connect to a storage node */ if (referrals[i].flags & DFSREF_STORAGE_SERVER) { int len; len = strlen(referrals[i].node_name); if (len < 2) { cERROR(1, ("%s: Net Address path too short: %s", __func__, referrals[i].node_name)); rc = -EINVAL; goto out_err; } mnt = cifs_dfs_do_refmount(nd->path.mnt, nd->path.dentry, referrals + i); cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, referrals[i].node_name, mnt)); /* complete mount procedure if we accured submount */ if (!IS_ERR(mnt)) break; } } /* we need it cause for() above could exit without valid submount */ rc = PTR_ERR(mnt); if (IS_ERR(mnt)) goto out_err; nd->path.mnt->mnt_flags |= MNT_SHRINKABLE; rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list); out: FreeXid(xid); free_dfs_info_array(referrals, num_referrals); kfree(full_path); cFYI(1, ("leaving %s" , __func__)); return ERR_PTR(rc); out_err: path_put(&nd->path); goto out; }