 |
|
|
| |
1 /*
2 * Copyright (c) 1997-2005 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 *
40 * File: am-utils/amd/nfs_subr.c
41 *
42 */
43
44 #ifdef HAVE_CONFIG_H
45 # include <config.h>
46 #endif /* HAVE_CONFIG_H */
47 #include <am_defs.h>
48 #include <amd.h>
49
50 /*
51 * Convert from UN*X to NFS error code.
52 * Some systems like linux define their own (see
53 * conf/mount/mount_linux.h).
54 */
55 #ifndef nfs_error
56 # define nfs_error(e) ((nfsstat)(e))
57 #endif /* nfs_error */
58
59 /*
60 * File Handle structure
61 *
62 * This is interpreted by indexing the exported array
63 * by fhh_id (for old-style filehandles), or by retrieving
64 * the node name from fhh_path (for new-style filehandles).
65 *
66 * The whole structure is mapped onto a standard fhandle_t
67 * when transmitted.
68 */
69 struct am_fh {
70 u_int fhh_gen; /* generation number */
71 union {
72 struct {
73 int fhh_type; /* old or new am_fh */
74 int fhh_pid; /* process id */
75 int fhh_id; /* map id */
76 } s;
77 char fhh_path[NFS_FHSIZE-sizeof(u_int)]; /* path to am_node */
78 } u;
79 };
80
81
82 /* forward declarations */
83 /* converting am-filehandles to mount-points */
84 static am_node *fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop);
85 static am_node *fh_to_mp(am_nfs_fh *fhp);
86 static void count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail);
87
88
89 static char *
90 do_readlink(am_node *mp, int *error_return)
91 {
92 char *ln;
93
94 /*
95 * If there is a readlink method then use it,
96 * otherwise if a link exists use that,
97 * otherwise use the mount point.
98 */
99 if (mp->am_mnt->mf_ops->readlink) {
100 int retry = 0;
101 mp = (*mp->am_mnt->mf_ops->readlink) (mp, &retry);
102 if (mp == 0) {
103 *error_return = retry;
104 return 0;
105 }
106 /* reschedule_timeout_mp(); */
107 }
108
109 if (mp->am_link) {
110 ln = mp->am_link;
111 } else {
112 ln = mp->am_mnt->mf_mount;
113 }
114
115 return ln;
116 }
117
118
119 voidp
120 nfsproc_null_2_svc(voidp argp, struct svc_req *rqstp)
121 {
122 static char res;
123
124 return (voidp) &res;
125 }
126
127
128 nfsattrstat *
129 nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
130 {
131 static nfsattrstat res;
132 am_node *mp;
133 int retry;
134 time_t now = clocktime();
135
136 if (amuDebug(D_TRACE))
137 plog(XLOG_DEBUG, "getattr:");
138
139 mp = fh_to_mp3(argp, &retry, VLOOK_CREATE);
140 if (mp == 0) {
141 if (amuDebug(D_TRACE))
142 plog(XLOG_DEBUG, "\tretry=%d", retry);
143
144 if (retry < 0) {
145 amd_stats.d_drops++;
146 return 0;
147 }
148 res.ns_status = nfs_error(retry);
149 return &res;
150 }
151
152 res = mp->am_attr;
153 if (amuDebug(D_TRACE))
154 plog(XLOG_DEBUG, "\tstat(%s), size = %d, mtime=%ld",
155 mp->am_path,
156 (int) res.ns_u.ns_attr_u.na_size,
157 (long) res.ns_u.ns_attr_u.na_mtime.nt_seconds);
158
159 /* Delay unmount of what was looked up */
160 if (mp->am_timeo_w < 4 * gopt.am_timeo_w)
161 mp->am_timeo_w += gopt.am_timeo_w;
162 mp->am_ttl = now + mp->am_timeo_w;
163
164 mp->am_stats.s_getattr++;
165 return &res;
166 }
167
168
169 nfsattrstat *
170 nfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp)
171 {
172 static nfsattrstat res;
173
174 if (!fh_to_mp(&argp->sag_fhandle))
175 res.ns_status = nfs_error(ESTALE);
176 else
177 res.ns_status = nfs_error(EROFS);
178
179 return &res;
180 }
181
182
183 voidp
184 nfsproc_root_2_svc(voidp argp, struct svc_req *rqstp)
185 {
186 static char res;
187
188 return (voidp) &res;
189 }
190
191
192 nfsdiropres *
193 nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
194 {
195 static nfsdiropres res;
196 am_node *mp;
197 int retry;
198 uid_t uid;
199 gid_t gid;
200
201 if (amuDebug(D_TRACE))
202 plog(XLOG_DEBUG, "lookup:");
203
204 /* finally, find the effective uid/gid from RPC request */
205 if (getcreds(rqstp, &uid, &gid, nfsxprt) < 0)
206 plog(XLOG_ERROR, "cannot get uid/gid from RPC credentials");
207 sprintf(opt_uid, "%d", (int) uid);
208 sprintf(opt_gid, "%d", (int) gid);
209
210 mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_CREATE);
211 if (mp == 0) {
212 if (retry < 0) {
213 amd_stats.d_drops++;
214 return 0;
215 }
216 res.dr_status = nfs_error(retry);
217 } else {
218 int error;
219 am_node *ap;
220 if (amuDebug(D_TRACE))
221 plog(XLOG_DEBUG, "\tlookup(%s, %s)", mp->am_path, argp->da_name);
222 ap = mp->am_mnt->mf_ops->lookup_child(mp, argp->da_name, &error, VLOOK_CREATE);
223 if (ap && error < 0)
224 ap = mp->am_mnt->mf_ops->mount_child(ap, &error);
225 if (ap == 0) {
226 if (error < 0) {
227 amd_stats.d_drops++;
228 return 0;
229 }
230 res.dr_status = nfs_error(error);
231 } else {
232 /*
233 * XXX: EXPERIMENTAL! Delay unmount of what was looked up. This
234 * should reduce the chance for race condition between unmounting an
235 * entry synchronously, and re-mounting it asynchronously.
236 */
237 if (ap->am_ttl < mp->am_ttl)
238 ap->am_ttl = mp->am_ttl;
239 mp_to_fh(ap, &res.dr_u.dr_drok_u.drok_fhandle);
240 res.dr_u.dr_drok_u.drok_attributes = ap->am_fattr;
241 res.dr_status = NFS_OK;
242 }
243 mp->am_stats.s_lookup++;
244 /* reschedule_timeout_mp(); */
245 }
246
247 return &res;
248 }
249
250
251 void
252 nfs_quick_reply(am_node *mp, int error)
253 {
254 SVCXPRT *transp = mp->am_transp;
255 nfsdiropres res;
256 xdrproc_t xdr_result = (xdrproc_t) xdr_diropres;
257
258 /*
259 * If there's a transp structure then we can reply to the client's
260 * nfs lookup request.
261 */
262 if (transp) {
263 if (error == 0) {
264 /*
265 * Construct a valid reply to a lookup request. Same
266 * code as in nfsproc_lookup_2_svc() above.
267 */
268 mp_to_fh(mp, &res.dr_u.dr_drok_u.drok_fhandle);
269 res.dr_u.dr_drok_u.drok_attributes = mp->am_fattr;
270 res.dr_status = NFS_OK;
271 } else
272 /*
273 * Return the error that was passed to us.
274 */
275 res.dr_status = nfs_error(error);
276
277 /*
278 * Send off our reply
279 */
280 if (!svc_sendreply(transp, (XDRPROC_T_TYPE) xdr_result, (SVC_IN_ARG_TYPE) & res))
281 svcerr_systemerr(transp);
282
283 /*
284 * Free up transp. It's only used for one reply.
285 */
286 XFREE(mp->am_transp);
287 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
288 }
289 }
290
291
292 nfsreadlinkres *
293 nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
294 {
295 static nfsreadlinkres res;
296 am_node *mp;
297 int retry;
298
299 if (amuDebug(D_TRACE))
300 plog(XLOG_DEBUG, "readlink:");
301
302 mp = fh_to_mp3(argp, &retry, VLOOK_CREATE);
303 if (mp == 0) {
304 readlink_retry:
305 if (retry < 0) {
306 amd_stats.d_drops++;
307 return 0;
308 }
309 res.rlr_status = nfs_error(retry);
310 } else {
311 char *ln = do_readlink(mp, &retry);
312 if (ln == 0)
313 goto readlink_retry;
314 res.rlr_status = NFS_OK;
315 if (amuDebug(D_TRACE) && ln)
316 plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
317 res.rlr_u.rlr_data_u = ln;
318 mp->am_stats.s_readlink++;
319 }
320
321 return &res;
322 }
323
324
325 nfsreadres *
326 nfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp)
327 {
328 static nfsreadres res;
329
330 memset((char *) &res, 0, sizeof(res));
331 res.rr_status = nfs_error(EACCES);
332
333 return &res;
334 }
335
336
337 voidp
338 nfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp)
339 {
340 static char res;
341
342 return (voidp) &res;
343 }
344
345
346 nfsattrstat *
347 nfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp)
348 {
349 static nfsattrstat res;
350
351 if (!fh_to_mp(&argp->wra_fhandle))
352 res.ns_status = nfs_error(ESTALE);
353 else
354 res.ns_status = nfs_error(EROFS);
355
356 return &res;
357 }
358
359
360 nfsdiropres *
361 nfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
362 {
363 static nfsdiropres res;
364
365 if (!fh_to_mp(&argp->ca_where.da_fhandle))
366 res.dr_status = nfs_error(ESTALE);
367 else
368 res.dr_status = nfs_error(EROFS);
369
370 return &res;
371 }
372
373
374 static nfsstat *
375 unlink_or_rmdir(nfsdiropargs *argp, struct svc_req *rqstp, int unlinkp)
376 {
377 static nfsstat res;
378 int retry;
379
380 am_node *mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_DELETE);
381 if (mp == 0) {
382 if (retry < 0) {
383 amd_stats.d_drops++;
384 return 0;
385 }
386 res = nfs_error(retry);
387 goto out;
388 }
389
390 if (mp->am_fattr.na_type != NFDIR) {
391 res = nfs_error(ENOTDIR);
392 goto out;
393 }
394
395 if (amuDebug(D_TRACE))
396 plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->da_name);
397
398 mp = mp->am_mnt->mf_ops->lookup_child(mp, argp->da_name, &retry, VLOOK_DELETE);
399 if (mp == 0) {
400 /*
401 * Ignore retries...
402 */
403 if (retry < 0)
404 retry = 0;
405 /*
406 * Usual NFS workaround...
407 */
408 else if (retry == ENOENT)
409 retry = 0;
410 res = nfs_error(retry);
411 } else {
412 forcibly_timeout_mp(mp);
413 res = NFS_OK;
414 }
415
416 out:
417 return &res;
418 }
419
420
421 nfsstat *
422 nfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
423 {
424 return unlink_or_rmdir(argp, rqstp, TRUE);
425 }
426
427
428 nfsstat *
429 nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp)
430 {
431 static nfsstat res;
432
433 if (!fh_to_mp(&argp->rna_from.da_fhandle) || !fh_to_mp(&argp->rna_to.da_fhandle))
434 res = nfs_error(ESTALE);
435 /*
436 * If the kernel is doing clever things with referenced files
437 * then let it pretend...
438 */
439 else if (NSTREQ(argp->rna_to.da_name, ".nfs", 4))
440 res = NFS_OK;
441 /*
442 * otherwise a failure
443 */
444 else
445 res = nfs_error(EROFS);
446
447 return &res;
448 }
449
450
451 nfsstat *
452 nfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp)
453 {
454 static nfsstat res;
455
456 if (!fh_to_mp(&argp->la_fhandle) || !fh_to_mp(&argp->la_to.da_fhandle))
457 res = nfs_error(ESTALE);
458 else
459 res = nfs_error(EROFS);
460
461 return &res;
462 }
463
464
465 nfsstat *
466 nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp)
467 {
468 static nfsstat res;
469
470 if (!fh_to_mp(&argp->sla_from.da_fhandle))
471 res = nfs_error(ESTALE);
472 else
473 res = nfs_error(EROFS);
474
475 return &res;
476 }
477
478
479 nfsdiropres *
480 nfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
481 {
482 static nfsdiropres res;
483
484 if (!fh_to_mp(&argp->ca_where.da_fhandle))
485 res.dr_status = nfs_error(ESTALE);
486 else
487 res.dr_status = nfs_error(EROFS);
488
489 return &res;
490 }
491
492
493 nfsstat *
494 nfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
495 {
496 return unlink_or_rmdir(argp, rqstp, FALSE);
497 }
498
499
500 nfsreaddirres *
501 nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp)
502 {
503 static nfsreaddirres res;
504 static nfsentry e_res[MAX_READDIR_ENTRIES];
505 am_node *mp;
506 int retry;
507
508 if (amuDebug(D_TRACE))
509 plog(XLOG_DEBUG, "readdir:");
510
511 mp = fh_to_mp3(&argp->rda_fhandle, &retry, VLOOK_CREATE);
512 if (mp == 0) {
513 if (retry < 0) {
514 amd_stats.d_drops++;
515 return 0;
516 }
517 res.rdr_status = nfs_error(retry);
518 } else {
519 if (amuDebug(D_TRACE))
520 plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
521 res.rdr_status = nfs_error((*mp->am_mnt->mf_ops->readdir)
522 (mp, argp->rda_cookie,
523 &res.rdr_u.rdr_reply_u, e_res, argp->rda_count));
524 mp->am_stats.s_readdir++;
525 }
526
527 return &res;
528 }
529
530
531 nfsstatfsres *
532 nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
533 {
534 static nfsstatfsres res;
535 am_node *mp;
536 int retry;
537 mntent_t mnt;
538
539 if (amuDebug(D_TRACE))
540 plog(XLOG_DEBUG, "statfs:");
541
542 mp = fh_to_mp3(argp, &retry, VLOOK_CREATE);
543 if (mp == 0) {
544 if (retry < 0) {
545 amd_stats.d_drops++;
546 return 0;
547 }
548 res.sfr_status = nfs_error(retry);
549 } else {
550 nfsstatfsokres *fp;
551 if (amuDebug(D_TRACE))
552 plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
553
554 /*
555 * just return faked up file system information
556 */
557 fp = &res.sfr_u.sfr_reply_u;
558
559 fp->sfrok_tsize = 1024;
560 fp->sfrok_bsize = 1024;
561
562 /* check if map is browsable and show_statfs_entries=yes */
563 if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) &&
564 mp->am_mnt && mp->am_mnt->mf_mopts) {
565 mnt.mnt_opts = mp->am_mnt->mf_mopts;
566 if (amu_hasmntopt(&mnt, "browsable")) {
567 count_map_entries(mp,
568 &fp->sfrok_blocks,
569 &fp->sfrok_bfree,
570 &fp->sfrok_bavail);
571 }
572 } else {
573 fp->sfrok_blocks = 0; /* set to 1 if you don't want empty automounts */
574 fp->sfrok_bfree = 0;
575 fp->sfrok_bavail = 0;
576 }
577
578 res.sfr_status = NFS_OK;
579 mp->am_stats.s_statfs++;
580 }
581
582 return &res;
583 }
584
585
586 /*
587 * count how many total entries there are in a map, and how many
588 * of them are in use.
589 */
590 static void
591 count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail)
592 {
593 u_int blocks, bfree, bavail, i;
594 mntfs *mf;
595 mnt_map *mmp;
596 kv *k;
597
598 blocks = bfree = bavail = 0;
599 if (!mp)
600 goto out;
601 mf = mp->am_mnt;
602 if (!mf)
603 goto out;
604 mmp = (mnt_map *) mf->mf_private;
605 if (!mmp)
606 goto out;
607
608 /* iterate over keys */
609 for (i = 0; i < NKVHASH; i++) {
610 for (k = mmp->kvhash[i]; k ; k = k->next) {
611 if (!k->key)
612 continue;
613 blocks++;
614 /*
615 * XXX: Need to count how many are actively in use and recompute
616 * bfree and bavail based on it.
617 */
618 }
619 }
620
621 out:
622 *out_blocks = blocks;
623 *out_bfree = bfree;
624 *out_bavail = bavail;
625 }
626
627
628 /*
629 * Convert from file handle to automount node.
630 */
631 static am_node *
632 fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop)
633 {
634 struct am_fh *fp = (struct am_fh *) fhp;
635 am_node *ap = 0;
636
637 if (fp->u.s.fhh_type != 0) {
638 /* New filehandle type */
639 int len = sizeof(*fhp) - sizeof(fp->fhh_gen);
640 char *path = xmalloc(len+1);
641 /*
642 * Because fhp is treated as a filehandle we use memcpy
643 * instead of xstrlcpy.
644 */
645 memcpy(path, (char *) fp->u.fhh_path, len);
646 path[len] = '\0';
647 /* dlog("fh_to_mp3: new filehandle: %s", path); */
648
649 ap = path_to_exported_ap(path);
650 XFREE(path);
651 } else {
652 /* dlog("fh_to_mp3: old filehandle: %d", fp->fhh_id); */
653 /*
654 * Check process id matches
655 * If it doesn't then it is probably
656 * from an old kernel-cached filehandle
657 * which is now out of date.
658 */
659 if (fp->u.s.fhh_pid != am_mypid)
660 goto drop;
661
662 /*
663 * Get hold of the supposed mount node
664 */
665 ap = get_exported_ap(fp->u.s.fhh_id);
666 }
667
668 /*
669 * Check the generation number in the node
670 * matches the one from the kernel. If not
671 * then the old node has been timed out and
672 * a new one allocated.
673 */
674 if (ap != NULL && ap->am_gen != fp->fhh_gen)
675 ap = 0;
676
677 /*
678 * If it doesn't exists then drop the request
679 */
680 if (!ap)
681 goto drop;
682
683 #if 0
684 /*
685 * If the node is hung then locate a new node
686 * for it. This implements the replicated filesystem
687 * retries.
688 */
689 if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) {
690 int error;
691 am_node *orig_ap = ap;
692
693 dlog("fh_to_mp3: %s (%s) is hung: lookup alternative file server",
694 orig_ap->am_path, orig_ap->am_mnt->mf_info);
695
696 /*
697 * Update modify time of parent node.
698 * With any luck the kernel will re-stat
699 * the child node and get new information.
700 */
701 orig_ap->am_fattr.na_mtime.nt_seconds = clocktime();
702
703 /*
704 * Call the parent's lookup routine for an object
705 * with the same name. This may return -1 in error
706 * if a mount is in progress. In any case, if no
707 * mount node is returned the error code is propagated
708 * to the caller.
709 */
710 if (vop == VLOOK_CREATE) {
711 ap = orig_ap->am_parent->am_mnt->mf_ops->lookup_child(orig_ap->am_parent, orig_ap->am_name, &error, vop);
712 if (ap && error < 0)
713 ap = orig_ap->am_parent->am_mnt->mf_ops->mount_child(ap, &error);
714 } else {
715 ap = 0;
716 error = ESTALE;
717 }
718 if (ap == 0) {
719 if (error < 0 && amd_state == Finishing)
720 error = ENOENT;
721 *rp = error;
722 return 0;
723 }
724
725 /*
726 * Update last access to original node. This
727 * avoids timing it out and so sending ESTALE
728 * back to the kernel.
729 * XXX - Not sure we need this anymore (jsp, 90/10/6).
730 */
731 new_ttl(orig_ap);
732
733 }
734 #endif
735
736 /*
737 * Disallow references to objects being unmounted, unless
738 * they are automount points.
739 */
740 if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) &&
741 !(ap->am_flags & AMF_ROOT)) {
742 if (amd_state == Finishing)
743 *rp = ENOENT;
744 else
745 *rp = -1;
746 return 0;
747 }
748 new_ttl(ap);
749
750 drop:
751 if (!ap || !ap->am_mnt) {
752 /*
753 * If we are shutting down then it is likely
754 * that this node has disappeared because of
755 * a fast timeout. To avoid things thrashing
756 * just pretend it doesn't exist at all. If
757 * ESTALE is returned, some NFS clients just
758 * keep retrying (stupid or what - if it's
759 * stale now, what's it going to be in 5 minutes?)
760 */
761 if (amd_state == Finishing)
762 *rp = ENOENT;
763 else
764 *rp = ESTALE;
765 amd_stats.d_stale++;
766 }
767
768 return ap;
769 }
770
771
772 static am_node *
773 fh_to_mp(am_nfs_fh *fhp)
774 {
775 int dummy;
776
777 return fh_to_mp3(fhp, &dummy, VLOOK_CREATE);
778 }
779
780
781 /*
782 * Convert from automount node to file handle.
783 */
784 void
785 mp_to_fh(am_node *mp, am_nfs_fh *fhp)
786 {
787 u_int pathlen;
788 struct am_fh *fp = (struct am_fh *) fhp;
789
790 memset((char *) fhp, 0, sizeof(am_nfs_fh));
791
792 /* Store the generation number */
793 fp->fhh_gen = mp->am_gen;
794
795 pathlen = strlen(mp->am_path);
796 if (pathlen <= sizeof(*fhp) - sizeof(fp->fhh_gen)) {
797 /* dlog("mp_to_fh: new filehandle: %s", mp->am_path); */
798
799 /*
800 * Because fhp is treated as a filehandle we use memcpy instead of
801 * xstrlcpy.
802 */
803 memcpy(fp->u.fhh_path, mp->am_path, pathlen); /* making a filehandle */
804 } else {
805 /*
806 * Take the process id
807 */
808 fp->u.s.fhh_pid = am_mypid;
809
810 /*
811 * ... the map number
812 */
813 fp->u.s.fhh_id = mp->am_mapno;
814
815 /*
816 * ... and the generation number (previously stored)
817 * to make a "unique" triple that will never
818 * be reallocated except across reboots (which doesn't matter)
819 * or if we are unlucky enough to be given the same
820 * pid as a previous amd (very unlikely).
821 */
822 /* dlog("mp_to_fh: old filehandle: %d", fp->fhh_id); */
823 }
824 }
825