diff options
Diffstat (limited to 'fs/nfs/nfs4namespace.c')
-rw-r--r-- | fs/nfs/nfs4namespace.c | 105 |
1 files changed, 49 insertions, 56 deletions
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index b112857301f7..30befc39b3c6 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -93,21 +93,52 @@ static int nfs4_validate_fspath(const struct vfsmount *mnt_parent, | |||
93 | return 0; | 93 | return 0; |
94 | } | 94 | } |
95 | 95 | ||
96 | /* | 96 | static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, |
97 | * Check if the string represents a "valid" IPv4 address | 97 | char *page, char *page2, |
98 | */ | 98 | const struct nfs4_fs_location *location) |
99 | static inline int valid_ipaddr4(const char *buf) | ||
100 | { | 99 | { |
101 | int rc, count, in[4]; | 100 | struct vfsmount *mnt = ERR_PTR(-ENOENT); |
102 | 101 | char *mnt_path; | |
103 | rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); | 102 | int page2len; |
104 | if (rc != 4) | 103 | unsigned int s; |
105 | return -EINVAL; | 104 | |
106 | for (count = 0; count < 4; count++) { | 105 | mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); |
107 | if (in[count] > 255) | 106 | if (IS_ERR(mnt_path)) |
108 | return -EINVAL; | 107 | return mnt; |
108 | mountdata->mnt_path = mnt_path; | ||
109 | page2 += strlen(mnt_path) + 1; | ||
110 | page2len = PAGE_SIZE - strlen(mnt_path) - 1; | ||
111 | |||
112 | for (s = 0; s < location->nservers; s++) { | ||
113 | const struct nfs4_string *buf = &location->servers[s]; | ||
114 | struct sockaddr_storage addr; | ||
115 | |||
116 | if (buf->len <= 0 || buf->len >= PAGE_SIZE) | ||
117 | continue; | ||
118 | |||
119 | mountdata->addr = (struct sockaddr *)&addr; | ||
120 | |||
121 | if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) | ||
122 | continue; | ||
123 | nfs_parse_ip_address(buf->data, buf->len, | ||
124 | mountdata->addr, &mountdata->addrlen); | ||
125 | if (mountdata->addr->sa_family == AF_UNSPEC) | ||
126 | continue; | ||
127 | nfs_set_port(mountdata->addr, NFS_PORT); | ||
128 | |||
129 | strncpy(page2, buf->data, page2len); | ||
130 | page2[page2len] = '\0'; | ||
131 | mountdata->hostname = page2; | ||
132 | |||
133 | snprintf(page, PAGE_SIZE, "%s:%s", | ||
134 | mountdata->hostname, | ||
135 | mountdata->mnt_path); | ||
136 | |||
137 | mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, page, mountdata); | ||
138 | if (!IS_ERR(mnt)) | ||
139 | break; | ||
109 | } | 140 | } |
110 | return 0; | 141 | return mnt; |
111 | } | 142 | } |
112 | 143 | ||
113 | /** | 144 | /** |
@@ -128,7 +159,6 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
128 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, | 159 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, |
129 | }; | 160 | }; |
130 | char *page = NULL, *page2 = NULL; | 161 | char *page = NULL, *page2 = NULL; |
131 | unsigned int s; | ||
132 | int loc, error; | 162 | int loc, error; |
133 | 163 | ||
134 | if (locations == NULL || locations->nlocations <= 0) | 164 | if (locations == NULL || locations->nlocations <= 0) |
@@ -152,53 +182,16 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
152 | goto out; | 182 | goto out; |
153 | } | 183 | } |
154 | 184 | ||
155 | loc = 0; | 185 | for (loc = 0; loc < locations->nlocations; loc++) { |
156 | while (loc < locations->nlocations && IS_ERR(mnt)) { | ||
157 | const struct nfs4_fs_location *location = &locations->locations[loc]; | 186 | const struct nfs4_fs_location *location = &locations->locations[loc]; |
158 | char *mnt_path; | ||
159 | 187 | ||
160 | if (location == NULL || location->nservers <= 0 || | 188 | if (location == NULL || location->nservers <= 0 || |
161 | location->rootpath.ncomponents == 0) { | 189 | location->rootpath.ncomponents == 0) |
162 | loc++; | ||
163 | continue; | 190 | continue; |
164 | } | ||
165 | 191 | ||
166 | mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); | 192 | mnt = try_location(&mountdata, page, page2, location); |
167 | if (IS_ERR(mnt_path)) { | 193 | if (!IS_ERR(mnt)) |
168 | loc++; | 194 | break; |
169 | continue; | ||
170 | } | ||
171 | mountdata.mnt_path = mnt_path; | ||
172 | |||
173 | s = 0; | ||
174 | while (s < location->nservers) { | ||
175 | struct sockaddr_in addr = { | ||
176 | .sin_family = AF_INET, | ||
177 | .sin_port = htons(NFS_PORT), | ||
178 | }; | ||
179 | |||
180 | if (location->servers[s].len <= 0 || | ||
181 | valid_ipaddr4(location->servers[s].data) < 0) { | ||
182 | s++; | ||
183 | continue; | ||
184 | } | ||
185 | |||
186 | mountdata.hostname = location->servers[s].data; | ||
187 | addr.sin_addr.s_addr = in_aton(mountdata.hostname), | ||
188 | mountdata.addr = (struct sockaddr *)&addr; | ||
189 | mountdata.addrlen = sizeof(addr); | ||
190 | |||
191 | snprintf(page, PAGE_SIZE, "%s:%s", | ||
192 | mountdata.hostname, | ||
193 | mountdata.mnt_path); | ||
194 | |||
195 | mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, page, &mountdata); | ||
196 | if (!IS_ERR(mnt)) { | ||
197 | break; | ||
198 | } | ||
199 | s++; | ||
200 | } | ||
201 | loc++; | ||
202 | } | 195 | } |
203 | 196 | ||
204 | out: | 197 | out: |