1 |
|
|
/* $OpenBSD: nfs_ops.c,v 1.26 2014/10/26 03:28:41 guenther Exp $ */ |
2 |
|
|
|
3 |
|
|
/*- |
4 |
|
|
* Copyright (c) 1990 Jan-Simon Pendry |
5 |
|
|
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine |
6 |
|
|
* Copyright (c) 1990, 1993 |
7 |
|
|
* The Regents of the University of California. All rights reserved. |
8 |
|
|
* |
9 |
|
|
* This code is derived from software contributed to Berkeley by |
10 |
|
|
* Jan-Simon Pendry at Imperial College, London. |
11 |
|
|
* |
12 |
|
|
* Redistribution and use in source and binary forms, with or without |
13 |
|
|
* modification, are permitted provided that the following conditions |
14 |
|
|
* are met: |
15 |
|
|
* 1. Redistributions of source code must retain the above copyright |
16 |
|
|
* notice, this list of conditions and the following disclaimer. |
17 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
18 |
|
|
* notice, this list of conditions and the following disclaimer in the |
19 |
|
|
* documentation and/or other materials provided with the distribution. |
20 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
21 |
|
|
* may be used to endorse or promote products derived from this software |
22 |
|
|
* without specific prior written permission. |
23 |
|
|
* |
24 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
25 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
26 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
27 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
28 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
29 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
30 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
31 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
32 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
33 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
34 |
|
|
* SUCH DAMAGE. |
35 |
|
|
*/ |
36 |
|
|
|
37 |
|
|
#include "am.h" |
38 |
|
|
#include <sys/stat.h> |
39 |
|
|
|
40 |
|
|
#ifdef HAS_NFS |
41 |
|
|
|
42 |
|
|
#define NFS |
43 |
|
|
#define NFSCLIENT |
44 |
|
|
|
45 |
|
|
#include "mount.h" |
46 |
|
|
|
47 |
|
|
/* |
48 |
|
|
* Network file system |
49 |
|
|
*/ |
50 |
|
|
|
51 |
|
|
/* |
52 |
|
|
* Convert from nfsstat to UN*X error code |
53 |
|
|
*/ |
54 |
|
|
#define unx_error(e) ((int)(e)) |
55 |
|
|
|
56 |
|
|
/* |
57 |
|
|
* The NFS layer maintains a cache of file handles. |
58 |
|
|
* This is *fundamental* to the implementation and |
59 |
|
|
* also allows quick remounting when a filesystem |
60 |
|
|
* is accessed soon after timing out. |
61 |
|
|
* |
62 |
|
|
* The NFS server layer knows to flush this cache |
63 |
|
|
* when a server goes down so avoiding stale handles. |
64 |
|
|
* |
65 |
|
|
* Each cache entry keeps a hard reference to |
66 |
|
|
* the corresponding server. This ensures that |
67 |
|
|
* the server keepalive information is maintained. |
68 |
|
|
* |
69 |
|
|
* The copy of the sockaddr_in here is taken so |
70 |
|
|
* that the port can be twiddled to talk to mountd |
71 |
|
|
* instead of portmap or the NFS server as used |
72 |
|
|
* elsewhere. |
73 |
|
|
* The port# is flushed if a server goes down. |
74 |
|
|
* The IP address is never flushed - we assume |
75 |
|
|
* that the address of a mounted machine never |
76 |
|
|
* changes. If it does, then you have other |
77 |
|
|
* problems... |
78 |
|
|
*/ |
79 |
|
|
typedef struct fh_cache fh_cache; |
80 |
|
|
struct fh_cache { |
81 |
|
|
qelem fh_q; /* List header */ |
82 |
|
|
void *fh_wchan; /* Wait channel */ |
83 |
|
|
int fh_error; /* Valid data? */ |
84 |
|
|
int fh_id; /* Unique id */ |
85 |
|
|
int fh_cid; /* Callout id */ |
86 |
|
|
fhstatus fh_handle; /* Handle on filesystem */ |
87 |
|
|
struct sockaddr_in fh_sin; /* Address of mountd */ |
88 |
|
|
fserver *fh_fs; /* Server holding filesystem */ |
89 |
|
|
char *fh_path; /* Filesystem on host */ |
90 |
|
|
}; |
91 |
|
|
|
92 |
|
|
/* |
93 |
|
|
* FH_TTL is the time a file handle will remain in the cache since |
94 |
|
|
* last being used. If the file handle becomes invalid, then it |
95 |
|
|
* will be flushed anyway. |
96 |
|
|
*/ |
97 |
|
|
#define FH_TTL (5 * 60) /* five minutes */ |
98 |
|
|
#define FH_TTL_ERROR (30) /* 30 seconds */ |
99 |
|
|
|
100 |
|
|
static int fh_id = 0; |
101 |
|
|
#define FHID_ALLOC() (++fh_id) |
102 |
|
|
extern qelem fh_head; |
103 |
|
|
qelem fh_head = { &fh_head, &fh_head }; |
104 |
|
|
|
105 |
|
|
static int call_mountd(fh_cache*, unsigned long, fwd_fun, void *); |
106 |
|
|
|
107 |
|
|
AUTH *nfs_auth; |
108 |
|
|
|
109 |
|
|
static fh_cache * |
110 |
|
|
find_nfs_fhandle_cache(void *idv, int done) |
111 |
|
|
{ |
112 |
|
|
fh_cache *fp, *fp2 = 0; |
113 |
|
|
/* XXX EVIL XXX */ |
114 |
|
|
int id = (int) ((long)idv); |
115 |
|
|
|
116 |
|
|
ITER(fp, fh_cache, &fh_head) { |
117 |
|
|
if (fp->fh_id == id) { |
118 |
|
|
fp2 = fp; |
119 |
|
|
break; |
120 |
|
|
} |
121 |
|
|
} |
122 |
|
|
|
123 |
|
|
#ifdef DEBUG |
124 |
|
|
if (fp2) { |
125 |
|
|
dlog("fh cache gives fp %#x, fs %s", fp2, fp2->fh_path); |
126 |
|
|
} else { |
127 |
|
|
dlog("fh cache search failed"); |
128 |
|
|
} |
129 |
|
|
#endif /* DEBUG */ |
130 |
|
|
|
131 |
|
|
if (fp2 && !done) { |
132 |
|
|
fp2->fh_error = ETIMEDOUT; |
133 |
|
|
return 0; |
134 |
|
|
} |
135 |
|
|
|
136 |
|
|
return fp2; |
137 |
|
|
} |
138 |
|
|
|
139 |
|
|
/* |
140 |
|
|
* Called when a filehandle appears |
141 |
|
|
*/ |
142 |
|
|
static void |
143 |
|
|
got_nfs_fh(void *pkt, int len, struct sockaddr_in *sa, |
144 |
|
|
struct sockaddr_in *ia, void *idv, int done) |
145 |
|
|
{ |
146 |
|
|
fh_cache *fp = find_nfs_fhandle_cache(idv, done); |
147 |
|
|
if (fp) { |
148 |
|
|
fp->fh_handle.fhs_vers = MOUNTVERS; |
149 |
|
|
fp->fh_error = pickup_rpc_reply(pkt, len, &fp->fh_handle, |
150 |
|
|
xdr_fhstatus); |
151 |
|
|
if (!fp->fh_error) { |
152 |
|
|
#ifdef DEBUG |
153 |
|
|
dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); |
154 |
|
|
#endif /* DEBUG */ |
155 |
|
|
/* |
156 |
|
|
* Wakeup anything sleeping on this filehandle |
157 |
|
|
*/ |
158 |
|
|
if (fp->fh_wchan) { |
159 |
|
|
#ifdef DEBUG |
160 |
|
|
dlog("Calling wakeup on %#x", fp->fh_wchan); |
161 |
|
|
#endif /* DEBUG */ |
162 |
|
|
wakeup(fp->fh_wchan); |
163 |
|
|
} |
164 |
|
|
} |
165 |
|
|
} |
166 |
|
|
} |
167 |
|
|
|
168 |
|
|
void |
169 |
|
|
flush_nfs_fhandle_cache(fserver *fs) |
170 |
|
|
{ |
171 |
|
|
fh_cache *fp; |
172 |
|
|
ITER(fp, fh_cache, &fh_head) { |
173 |
|
|
if (fp->fh_fs == fs || fs == 0) { |
174 |
|
|
fp->fh_sin.sin_port = (u_short) 0; |
175 |
|
|
fp->fh_error = -1; |
176 |
|
|
} |
177 |
|
|
} |
178 |
|
|
} |
179 |
|
|
|
180 |
|
|
static void |
181 |
|
|
discard_fh(void *arg) |
182 |
|
|
{ |
183 |
|
|
fh_cache *fp = arg; |
184 |
|
|
|
185 |
|
|
rem_que(&fp->fh_q); |
186 |
|
|
#ifdef DEBUG |
187 |
|
|
dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); |
188 |
|
|
#endif /* DEBUG */ |
189 |
|
|
free_srvr(fp->fh_fs); |
190 |
|
|
free(fp->fh_path); |
191 |
|
|
free(fp); |
192 |
|
|
} |
193 |
|
|
|
194 |
|
|
/* |
195 |
|
|
* Determine the file handle for a node |
196 |
|
|
*/ |
197 |
|
|
static int |
198 |
|
|
prime_nfs_fhandle_cache(char *path, fserver *fs, fhstatus *fhbuf, void *wchan) |
199 |
|
|
{ |
200 |
|
|
fh_cache *fp, *fp_save = 0; |
201 |
|
|
int error; |
202 |
|
|
int reuse_id = FALSE; |
203 |
|
|
|
204 |
|
|
#ifdef DEBUG |
205 |
|
|
dlog("Searching cache for %s:%s", fs->fs_host, path); |
206 |
|
|
#endif /* DEBUG */ |
207 |
|
|
|
208 |
|
|
/* |
209 |
|
|
* First search the cache |
210 |
|
|
*/ |
211 |
|
|
ITER(fp, fh_cache, &fh_head) { |
212 |
|
|
if (fs == fp->fh_fs && strcmp(path, fp->fh_path) == 0) { |
213 |
|
|
switch (fp->fh_error) { |
214 |
|
|
case 0: |
215 |
|
|
error = fp->fh_error = unx_error(fp->fh_handle.fhs_stat); |
216 |
|
|
if (error == 0) { |
217 |
|
|
if (fhbuf) |
218 |
|
|
bcopy(&fp->fh_handle, fhbuf, |
219 |
|
|
sizeof(fp->fh_handle)); |
220 |
|
|
if (fp->fh_cid) |
221 |
|
|
untimeout(fp->fh_cid); |
222 |
|
|
fp->fh_cid = timeout(FH_TTL, |
223 |
|
|
discard_fh, fp); |
224 |
|
|
} else if (error == EACCES) { |
225 |
|
|
/* |
226 |
|
|
* Now decode the file handle return code. |
227 |
|
|
*/ |
228 |
|
|
plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"", |
229 |
|
|
fs->fs_host, path); |
230 |
|
|
} else { |
231 |
|
|
errno = error; /* XXX */ |
232 |
|
|
plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m", |
233 |
|
|
fs->fs_host, path); |
234 |
|
|
} |
235 |
|
|
|
236 |
|
|
/* |
237 |
|
|
* The error was returned from the remote mount daemon. |
238 |
|
|
* Policy: this error will be cached for now... |
239 |
|
|
*/ |
240 |
|
|
return error; |
241 |
|
|
|
242 |
|
|
case -1: |
243 |
|
|
/* |
244 |
|
|
* Still thinking about it, but we can re-use. |
245 |
|
|
*/ |
246 |
|
|
fp_save = fp; |
247 |
|
|
reuse_id = TRUE; |
248 |
|
|
break; |
249 |
|
|
|
250 |
|
|
default: |
251 |
|
|
/* |
252 |
|
|
* Return the error. |
253 |
|
|
* Policy: make sure we recompute if required again |
254 |
|
|
* in case this was caused by a network failure. |
255 |
|
|
* This can thrash mountd's though... If you find |
256 |
|
|
* your mountd going slowly then: |
257 |
|
|
* 1. Add a fork() loop to main. |
258 |
|
|
* 2. Remove the call to innetgr() and don't use |
259 |
|
|
* netgroups, especially if you don't use YP. |
260 |
|
|
*/ |
261 |
|
|
error = fp->fh_error; |
262 |
|
|
fp->fh_error = -1; |
263 |
|
|
return error; |
264 |
|
|
} |
265 |
|
|
break; |
266 |
|
|
} |
267 |
|
|
} |
268 |
|
|
|
269 |
|
|
/* |
270 |
|
|
* Not in cache |
271 |
|
|
*/ |
272 |
|
|
if (fp_save) { |
273 |
|
|
fp = fp_save; |
274 |
|
|
/* |
275 |
|
|
* Re-use existing slot |
276 |
|
|
*/ |
277 |
|
|
untimeout(fp->fh_cid); |
278 |
|
|
free_srvr(fp->fh_fs); |
279 |
|
|
free(fp->fh_path); |
280 |
|
|
} else { |
281 |
|
|
fp = ALLOC(fh_cache); |
282 |
|
|
bzero(fp, sizeof(*fp)); |
283 |
|
|
ins_que(&fp->fh_q, &fh_head); |
284 |
|
|
} |
285 |
|
|
if (!reuse_id) |
286 |
|
|
fp->fh_id = FHID_ALLOC(); |
287 |
|
|
fp->fh_wchan = wchan; |
288 |
|
|
fp->fh_error = -1; |
289 |
|
|
fp->fh_cid = timeout(FH_TTL, discard_fh, fp); |
290 |
|
|
|
291 |
|
|
/* |
292 |
|
|
* If the address has changed then don't try to re-use the |
293 |
|
|
* port information |
294 |
|
|
*/ |
295 |
|
|
if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) { |
296 |
|
|
fp->fh_sin = *fs->fs_ip; |
297 |
|
|
fp->fh_sin.sin_port = 0; |
298 |
|
|
} |
299 |
|
|
fp->fh_fs = dup_srvr(fs); |
300 |
|
|
fp->fh_path = strdup(path); |
301 |
|
|
|
302 |
|
|
error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan); |
303 |
|
|
if (error) { |
304 |
|
|
/* |
305 |
|
|
* Local error - cache for a short period |
306 |
|
|
* just to prevent thrashing. |
307 |
|
|
*/ |
308 |
|
|
untimeout(fp->fh_cid); |
309 |
|
|
fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR, |
310 |
|
|
discard_fh, fp); |
311 |
|
|
fp->fh_error = error; |
312 |
|
|
} else { |
313 |
|
|
error = fp->fh_error; |
314 |
|
|
} |
315 |
|
|
return error; |
316 |
|
|
} |
317 |
|
|
|
318 |
|
|
int |
319 |
|
|
make_nfs_auth(void) |
320 |
|
|
{ |
321 |
|
|
/* |
322 |
|
|
* From: Chris Metcalf <metcalf@masala.lcs.mit.edu> |
323 |
|
|
* Use hostd, not just hostname. Note that uids |
324 |
|
|
* and gids and the gidlist are type *int* and not the |
325 |
|
|
* system uid_t and gid_t types. |
326 |
|
|
*/ |
327 |
|
|
static int group_wheel = 0; |
328 |
|
|
nfs_auth = authunix_create(hostd, 0, 0, 1, &group_wheel); |
329 |
|
|
if (!nfs_auth) |
330 |
|
|
return ENOBUFS; |
331 |
|
|
return 0; |
332 |
|
|
} |
333 |
|
|
|
334 |
|
|
static int |
335 |
|
|
call_mountd(fh_cache *fp, u_long proc, fwd_fun f, void *wchan) |
336 |
|
|
{ |
337 |
|
|
struct rpc_msg mnt_msg; |
338 |
|
|
int len; |
339 |
|
|
char iobuf[8192]; |
340 |
|
|
int error; |
341 |
|
|
|
342 |
|
|
if (!nfs_auth) { |
343 |
|
|
error = make_nfs_auth(); |
344 |
|
|
if (error) |
345 |
|
|
return error; |
346 |
|
|
} |
347 |
|
|
|
348 |
|
|
if (fp->fh_sin.sin_port == 0) { |
349 |
|
|
u_short port; |
350 |
|
|
error = nfs_srvr_port(fp->fh_fs, &port, wchan); |
351 |
|
|
if (error) |
352 |
|
|
return error; |
353 |
|
|
fp->fh_sin.sin_port = port; |
354 |
|
|
} |
355 |
|
|
|
356 |
|
|
rpc_msg_init(&mnt_msg, MOUNTPROG, MOUNTVERS, (unsigned long) 0); |
357 |
|
|
len = make_rpc_packet(iobuf, sizeof(iobuf), proc, |
358 |
|
|
&mnt_msg, &fp->fh_path, xdr_nfspath, nfs_auth); |
359 |
|
|
|
360 |
|
|
/* |
361 |
|
|
* XXX EVIL! We cast fh_id to a pointer, then back to an int |
362 |
|
|
* XXX later. |
363 |
|
|
*/ |
364 |
|
|
if (len > 0) { |
365 |
|
|
error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id), |
366 |
|
|
iobuf, len, &fp->fh_sin, &fp->fh_sin, |
367 |
|
|
(void *)((long)fp->fh_id), f); |
368 |
|
|
} else { |
369 |
|
|
error = -len; |
370 |
|
|
} |
371 |
|
|
/* |
372 |
|
|
* It may be the case that we're sending to the wrong MOUNTD port. This |
373 |
|
|
* occurs if mountd is restarted on the server after the port has been |
374 |
|
|
* looked up and stored in the filehandle cache somewhere. The correct |
375 |
|
|
* solution, if we're going to cache port numbers is to catch the ICMP |
376 |
|
|
* port unreachable reply from the server and cause the portmap request |
377 |
|
|
* to be redone. The quick solution here is to invalidate the MOUNTD |
378 |
|
|
* port. |
379 |
|
|
*/ |
380 |
|
|
fp->fh_sin.sin_port = 0; |
381 |
|
|
|
382 |
|
|
return error; |
383 |
|
|
} |
384 |
|
|
|
385 |
|
|
/*-------------------------------------------------------------------------*/ |
386 |
|
|
|
387 |
|
|
/* |
388 |
|
|
* NFS needs the local filesystem, remote filesystem |
389 |
|
|
* remote hostname. |
390 |
|
|
* Local filesystem defaults to remote and vice-versa. |
391 |
|
|
*/ |
392 |
|
|
static char * |
393 |
|
|
nfs_match(am_opts *fo) |
394 |
|
|
{ |
395 |
|
|
char *xmtab; |
396 |
|
|
if (fo->opt_fs && !fo->opt_rfs) |
397 |
|
|
fo->opt_rfs = fo->opt_fs; |
398 |
|
|
if (!fo->opt_rfs) { |
399 |
|
|
plog(XLOG_USER, "nfs: no remote filesystem specified"); |
400 |
|
|
return FALSE; |
401 |
|
|
} |
402 |
|
|
if (!fo->opt_rhost) { |
403 |
|
|
plog(XLOG_USER, "nfs: no remote host specified"); |
404 |
|
|
return FALSE; |
405 |
|
|
} |
406 |
|
|
/* |
407 |
|
|
* Determine magic cookie to put in mtab |
408 |
|
|
*/ |
409 |
|
|
xmtab = xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2); |
410 |
|
|
snprintf(xmtab, strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2, |
411 |
|
|
"%s:%s", fo->opt_rhost, fo->opt_rfs); |
412 |
|
|
#ifdef DEBUG |
413 |
|
|
dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"", |
414 |
|
|
fo->opt_rhost, fo->opt_rfs, fo->opt_fs); |
415 |
|
|
#endif /* DEBUG */ |
416 |
|
|
|
417 |
|
|
return xmtab; |
418 |
|
|
} |
419 |
|
|
|
420 |
|
|
/* |
421 |
|
|
* Initialise am structure for nfs |
422 |
|
|
*/ |
423 |
|
|
static int |
424 |
|
|
nfs_init(mntfs *mf) |
425 |
|
|
{ |
426 |
|
|
if (!mf->mf_private) { |
427 |
|
|
int error; |
428 |
|
|
fhstatus fhs; |
429 |
|
|
|
430 |
|
|
char *colon = strchr(mf->mf_info, ':'); |
431 |
|
|
if (colon == 0) |
432 |
|
|
return ENOENT; |
433 |
|
|
|
434 |
|
|
error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, |
435 |
|
|
&fhs, mf); |
436 |
|
|
if (!error) { |
437 |
|
|
mf->mf_private = ALLOC(fhstatus); |
438 |
|
|
mf->mf_prfree = free; |
439 |
|
|
bcopy(&fhs, mf->mf_private, sizeof(fhs)); |
440 |
|
|
} |
441 |
|
|
return error; |
442 |
|
|
} |
443 |
|
|
|
444 |
|
|
return 0; |
445 |
|
|
} |
446 |
|
|
|
447 |
|
|
int |
448 |
|
|
mount_nfs_fh(fhstatus *fhp, char *dir, char *fs_name, char *opts, |
449 |
|
|
mntfs *mf) |
450 |
|
|
{ |
451 |
|
|
struct nfs_args nfs_args; |
452 |
|
|
struct mntent mnt; |
453 |
|
|
int retry; |
454 |
|
|
char *colon; |
455 |
|
|
/*char *path;*/ |
456 |
|
|
char host[MAXHOSTNAMELEN + MAXPATHLEN + 2]; |
457 |
|
|
fserver *fs = mf->mf_server; |
458 |
|
|
int flags; |
459 |
|
|
char *xopts; |
460 |
|
|
int error; |
461 |
|
|
#ifdef notdef |
462 |
|
|
unsigned short port; |
463 |
|
|
#endif /* notdef */ |
464 |
|
|
|
465 |
|
|
const char *type = MOUNT_NFS; |
466 |
|
|
|
467 |
|
|
bzero(&nfs_args, sizeof(nfs_args)); /* Paranoid */ |
468 |
|
|
|
469 |
|
|
/* |
470 |
|
|
* Extract host name to give to kernel |
471 |
|
|
*/ |
472 |
|
|
if (!(colon = strchr(fs_name, ':'))) |
473 |
|
|
return ENOENT; |
474 |
|
|
strlcpy(host, fs_name, sizeof(host)); |
475 |
|
|
/*path = colon + 1;*/ |
476 |
|
|
|
477 |
|
|
if (mf->mf_remopts && *mf->mf_remopts && !islocalnet(fs->fs_ip->sin_addr.s_addr)) |
478 |
|
|
xopts = strdup(mf->mf_remopts); |
479 |
|
|
else |
480 |
|
|
xopts = strdup(opts); |
481 |
|
|
|
482 |
|
|
bzero(&nfs_args, sizeof(nfs_args)); |
483 |
|
|
|
484 |
|
|
mnt.mnt_dir = dir; |
485 |
|
|
mnt.mnt_fsname = fs_name; |
486 |
|
|
mnt.mnt_type = "nfs"; |
487 |
|
|
mnt.mnt_opts = xopts; |
488 |
|
|
mnt.mnt_freq = 0; |
489 |
|
|
mnt.mnt_passno = 0; |
490 |
|
|
|
491 |
|
|
retry = hasmntval(&mnt, "retry"); |
492 |
|
|
if (retry <= 0) |
493 |
|
|
retry = 1; /* XXX */ |
494 |
|
|
|
495 |
|
|
/*again:*/ |
496 |
|
|
|
497 |
|
|
/* |
498 |
|
|
* set mount args |
499 |
|
|
*/ |
500 |
|
|
nfs_args.fh = (void *)fhp->fhs_fhandle; |
501 |
|
|
nfs_args.fhsize = fhp->fhs_size; |
502 |
|
|
nfs_args.version = NFS_ARGSVERSION; |
503 |
|
|
|
504 |
|
|
nfs_args.hostname = host; |
505 |
|
|
#ifdef HOSTNAMESZ |
506 |
|
|
/* |
507 |
|
|
* Most kernels have a name length restriction. |
508 |
|
|
*/ |
509 |
|
|
if (strlen(host) >= HOSTNAMESZ) |
510 |
|
|
strlcpy(host + HOSTNAMESZ - 3, "..", sizeof host - HOSTNAMESZ + 3); |
511 |
|
|
#endif /* HOSTNAMESZ */ |
512 |
|
|
|
513 |
|
|
if ((nfs_args.rsize = hasmntval(&mnt, "rsize"))) |
514 |
|
|
nfs_args.flags |= NFSMNT_RSIZE; |
515 |
|
|
|
516 |
|
|
#ifdef NFSMNT_READDIRSIZE |
517 |
|
|
if ((nfs_args.readdirsize = hasmntval(&mnt, "readdirsize"))) { |
518 |
|
|
nfs_args.flags |= NFSMNT_READDIRSIZE; |
519 |
|
|
} else if (nfs_args.rsize) { |
520 |
|
|
nfs_args.readdirsize = nfs_args.rsize; |
521 |
|
|
nfs_args.flags |= NFSMNT_READDIRSIZE; |
522 |
|
|
} |
523 |
|
|
#endif |
524 |
|
|
|
525 |
|
|
if ((nfs_args.wsize = hasmntval(&mnt, "wsize"))) |
526 |
|
|
nfs_args.flags |= NFSMNT_WSIZE; |
527 |
|
|
|
528 |
|
|
if ((nfs_args.timeo = hasmntval(&mnt, "timeo"))) |
529 |
|
|
nfs_args.flags |= NFSMNT_TIMEO; |
530 |
|
|
|
531 |
|
|
if ((nfs_args.retrans = hasmntval(&mnt, "retrans"))) |
532 |
|
|
nfs_args.flags |= NFSMNT_RETRANS; |
533 |
|
|
|
534 |
|
|
#ifdef NFSMNT_BIODS |
535 |
|
|
if ((nfs_args.biods = hasmntval(&mnt, "biods"))) |
536 |
|
|
nfs_args.flags |= NFSMNT_BIODS; |
537 |
|
|
|
538 |
|
|
#endif /* NFSMNT_BIODS */ |
539 |
|
|
|
540 |
|
|
#ifdef NFSMNT_MAXGRPS |
541 |
|
|
if ((nfs_args.maxgrouplist = hasmntval(&mnt, "maxgroups"))) |
542 |
|
|
nfs_args.flags |= NFSMNT_MAXGRPS; |
543 |
|
|
#endif /* NFSMNT_MAXGRPS */ |
544 |
|
|
|
545 |
|
|
#ifdef NFSMNT_READAHEAD |
546 |
|
|
if ((nfs_args.readahead = hasmntval(&mnt, "readahead"))) |
547 |
|
|
nfs_args.flags |= NFSMNT_READAHEAD; |
548 |
|
|
#endif /* NFSMNT_READAHEAD */ |
549 |
|
|
|
550 |
|
|
#ifdef notdef |
551 |
|
|
/* |
552 |
|
|
* This isn't supported by the ping algorithm yet. |
553 |
|
|
* In any case, it is all done in nfs_init(). |
554 |
|
|
*/ |
555 |
|
|
if ((port = hasmntval(&mnt, "port"))) |
556 |
|
|
sin.sin_port = htons(port); |
557 |
|
|
else |
558 |
|
|
sin.sin_port = htons(NFS_PORT); /* XXX should use portmapper */ |
559 |
|
|
#endif /* notdef */ |
560 |
|
|
|
561 |
|
|
if (hasmntopt(&mnt, "soft") != NULL) |
562 |
|
|
nfs_args.flags |= NFSMNT_SOFT; |
563 |
|
|
|
564 |
|
|
#ifdef NFSMNT_SPONGY |
565 |
|
|
if (hasmntopt(&mnt, "spongy") != NULL) { |
566 |
|
|
nfs_args.flags |= NFSMNT_SPONGY; |
567 |
|
|
if (nfs_args.flags & NFSMNT_SOFT) { |
568 |
|
|
plog(XLOG_USER, "Mount opts soft and spongy are incompatible - soft ignored"); |
569 |
|
|
nfs_args.flags &= ~NFSMNT_SOFT; |
570 |
|
|
} |
571 |
|
|
} |
572 |
|
|
#endif /* MNTOPT_SPONGY */ |
573 |
|
|
|
574 |
|
|
if (hasmntopt(&mnt, "intr") != NULL) |
575 |
|
|
nfs_args.flags |= NFSMNT_INT; |
576 |
|
|
|
577 |
|
|
#ifdef MNTOPT_NODEVS |
578 |
|
|
if (hasmntopt(&mnt, MNTOPT_NODEVS) != NULL) |
579 |
|
|
nfs_args.flags |= NFSMNT_NODEVS; |
580 |
|
|
#endif /* MNTOPT_NODEVS */ |
581 |
|
|
|
582 |
|
|
|
583 |
|
|
if (hasmntopt(&mnt, "noconn") != NULL) |
584 |
|
|
nfs_args.flags |= NFSMNT_NOCONN; |
585 |
|
|
|
586 |
|
|
if (hasmntopt(&mnt, "resvport") != NULL) |
587 |
|
|
nfs_args.flags |= NFSMNT_RESVPORT; |
588 |
|
|
|
589 |
|
|
#ifdef NFSMNT_PGTHRESH |
590 |
|
|
if ((nfs_args.pg_thresh = hasmntval(&mnt, "pgthresh"))) |
591 |
|
|
nfs_args.flags |= NFSMNT_PGTHRESH; |
592 |
|
|
#endif /* NFSMNT_PGTHRESH */ |
593 |
|
|
|
594 |
|
|
nfs_args.addr = (struct sockaddr *)fs->fs_ip; |
595 |
|
|
nfs_args.addrlen = sizeof(*fs->fs_ip); |
596 |
|
|
nfs_args.sotype = SOCK_DGRAM; |
597 |
|
|
nfs_args.proto = 0; |
598 |
|
|
|
599 |
|
|
flags = compute_mount_flags(&mnt); |
600 |
|
|
|
601 |
|
|
#ifdef NFSMNT_NOCTO |
602 |
|
|
if (hasmntopt(&mnt, "nocto") != NULL) |
603 |
|
|
nfs_args.flags |= NFSMNT_NOCTO; |
604 |
|
|
#endif /* NFSMNT_NOCTO */ |
605 |
|
|
|
606 |
|
|
if (hasmntopt(&mnt, "tcp") != NULL) |
607 |
|
|
nfs_args.sotype = SOCK_STREAM; |
608 |
|
|
|
609 |
|
|
|
610 |
|
|
|
611 |
|
|
error = mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type); |
612 |
|
|
free(xopts); |
613 |
|
|
return error; |
614 |
|
|
} |
615 |
|
|
|
616 |
|
|
static int |
617 |
|
|
mount_nfs(char *dir, char *fs_name, char *opts, mntfs *mf) |
618 |
|
|
{ |
619 |
|
|
#ifdef notdef |
620 |
|
|
int error; |
621 |
|
|
fhstatus fhs; |
622 |
|
|
char *colon; |
623 |
|
|
|
624 |
|
|
if (!(colon = strchr(fs_name, ':'))) |
625 |
|
|
return ENOENT; |
626 |
|
|
|
627 |
|
|
#ifdef DEBUG |
628 |
|
|
dlog("locating fhandle for %s", fs_name); |
629 |
|
|
#endif /* DEBUG */ |
630 |
|
|
error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, NULL); |
631 |
|
|
|
632 |
|
|
if (error) |
633 |
|
|
return error; |
634 |
|
|
|
635 |
|
|
return mount_nfs_fh(&fhs, dir, fs_name, opts, mf); |
636 |
|
|
#endif |
637 |
|
|
if (!mf->mf_private) { |
638 |
|
|
plog(XLOG_ERROR, "Missing filehandle for %s", fs_name); |
639 |
|
|
return EINVAL; |
640 |
|
|
} |
641 |
|
|
|
642 |
|
|
return mount_nfs_fh((fhstatus *) mf->mf_private, dir, fs_name, opts, mf); |
643 |
|
|
} |
644 |
|
|
|
645 |
|
|
static int |
646 |
|
|
nfs_fmount(mntfs *mf) |
647 |
|
|
{ |
648 |
|
|
int error; |
649 |
|
|
|
650 |
|
|
error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf); |
651 |
|
|
|
652 |
|
|
#ifdef DEBUG |
653 |
|
|
if (error) { |
654 |
|
|
errno = error; |
655 |
|
|
dlog("mount_nfs: %m"); |
656 |
|
|
} |
657 |
|
|
#endif /* DEBUG */ |
658 |
|
|
return error; |
659 |
|
|
} |
660 |
|
|
|
661 |
|
|
static int |
662 |
|
|
nfs_fumount(mntfs *mf) |
663 |
|
|
{ |
664 |
|
|
return (umount_fs(mf->mf_mount)); |
665 |
|
|
} |
666 |
|
|
|
667 |
|
|
static void |
668 |
|
|
nfs_umounted(am_node *mp) |
669 |
|
|
{ |
670 |
|
|
|
671 |
|
|
#ifdef KICK_KERNEL |
672 |
|
|
/* This should go into the mainline code, not in nfs_ops... */ |
673 |
|
|
|
674 |
|
|
/* |
675 |
|
|
* Run lstat over the underlying directory in |
676 |
|
|
* case this was a direct mount. This will |
677 |
|
|
* get the kernel back in sync with reality. |
678 |
|
|
*/ |
679 |
|
|
if (mp->am_parent && mp->am_parent->am_path && |
680 |
|
|
STREQ(mp->am_parent->am_mnt->mf_ops->fs_type, "direct")) { |
681 |
|
|
struct stat stb; |
682 |
|
|
pid_t pid; |
683 |
|
|
if ((pid = background()) == 0) { |
684 |
|
|
if (lstat(mp->am_parent->am_path, &stb) < 0) { |
685 |
|
|
plog(XLOG_ERROR, "lstat(%s) after unmount: %m", mp->am_parent->am_path); |
686 |
|
|
#ifdef DEBUG |
687 |
|
|
} else { |
688 |
|
|
dlog("hack lstat(%s): ok", mp->am_parent->am_path); |
689 |
|
|
#endif /* DEBUG */ |
690 |
|
|
} |
691 |
|
|
_exit(0); |
692 |
|
|
} |
693 |
|
|
} |
694 |
|
|
#endif /* KICK_KERNEL */ |
695 |
|
|
} |
696 |
|
|
|
697 |
|
|
/* |
698 |
|
|
* Network file system |
699 |
|
|
*/ |
700 |
|
|
am_ops nfs_ops = { |
701 |
|
|
"nfs", |
702 |
|
|
nfs_match, |
703 |
|
|
nfs_init, |
704 |
|
|
auto_fmount, |
705 |
|
|
nfs_fmount, |
706 |
|
|
auto_fumount, |
707 |
|
|
nfs_fumount, |
708 |
|
|
efs_lookuppn, |
709 |
|
|
efs_readdir, |
710 |
|
|
0, /* nfs_readlink */ |
711 |
|
|
0, /* nfs_mounted */ |
712 |
|
|
nfs_umounted, |
713 |
|
|
find_nfs_srvr, |
714 |
|
|
FS_MKMNT|FS_BACKGROUND|FS_AMQINFO |
715 |
|
|
}; |
716 |
|
|
|
717 |
|
|
#endif /* HAS_NFS */ |