MFC r1.27:
[dragonfly.git] / contrib / amd / amd / nfs_subr.c
blobd06d0085e3422cb5d7c621ca37ff7d393eafc24d
1 /*
2 * Copyright (c) 1997-1999 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.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
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.
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.
39 * %W% (Berkeley) %G%
41 * $Id: nfs_subr.c,v 1.3 1999/01/13 23:31:00 ezk Exp $
45 #ifdef HAVE_CONFIG_H
46 # include <config.h>
47 #endif /* HAVE_CONFIG_H */
48 #include <am_defs.h>
49 #include <amd.h>
52 * Convert from UN*X to NFS error code.
53 * Some systems like linux define their own (see
54 * conf/mount/mount_linux.h).
56 #ifndef nfs_error
57 # define nfs_error(e) ((nfsstat)(e))
58 #endif /* nfs_error */
60 /* forward declarations */
61 static void count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail);
64 static char *
65 do_readlink(am_node *mp, int *error_return, nfsattrstat **attrpp)
67 char *ln;
70 * If there is a readlink method, then use
71 * that, otherwise if a link exists use
72 * that, otherwise use the mount point.
74 if (mp->am_mnt->mf_ops->readlink) {
75 int retry = 0;
76 mp = (*mp->am_mnt->mf_ops->readlink) (mp, &retry);
77 if (mp == 0) {
78 *error_return = retry;
79 return 0;
81 /* reschedule_timeout_mp(); */
84 if (mp->am_link) {
85 ln = mp->am_link;
86 } else {
87 ln = mp->am_mnt->mf_mount;
89 if (attrpp)
90 *attrpp = &mp->am_attr;
92 return ln;
96 voidp
97 nfsproc_null_2_svc(voidp argp, struct svc_req *rqstp)
99 static char res;
101 return (voidp) &res;
105 nfsattrstat *
106 nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
108 static nfsattrstat res;
109 am_node *mp;
110 int retry;
112 #ifdef DEBUG
113 amuDebug(D_TRACE)
114 plog(XLOG_DEBUG, "getattr:");
115 #endif /* DEBUG */
117 mp = fh_to_mp2(argp, &retry);
118 if (mp == 0) {
120 #ifdef DEBUG
121 amuDebug(D_TRACE)
122 plog(XLOG_DEBUG, "\tretry=%d", retry);
123 #endif /* DEBUG */
125 if (retry < 0)
126 return 0;
127 res.ns_status = nfs_error(retry);
128 } else {
129 nfsattrstat *attrp = &mp->am_attr;
131 #ifdef DEBUG
132 amuDebug(D_TRACE)
133 plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path,
134 (int) attrp->ns_u.ns_attr_u.na_size);
135 #endif /* DEBUG */
137 mp->am_stats.s_getattr++;
138 return attrp;
141 #ifndef MNT2_NFS_OPT_SYMTTL
143 * This code is needed to defeat Solaris 2.4's (and newer) symlink values
144 * cache. It forces the last-modified time of the symlink to be current.
145 * It is not needed if the O/S has an nfs flag to turn off the
146 * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
148 if (++res.ns_u.ns_attr_u.na_mtime.nt_useconds == 0)
149 ++res.ns_u.ns_attr_u.na_mtime.nt_seconds;
150 #endif /* not MNT2_NFS_OPT_SYMTTL */
152 return &res;
156 nfsattrstat *
157 nfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp)
159 static nfsattrstat res;
161 if (!fh_to_mp(&argp->sag_fhandle))
162 res.ns_status = nfs_error(ESTALE);
163 else
164 res.ns_status = nfs_error(EROFS);
166 return &res;
170 voidp
171 nfsproc_root_2_svc(voidp argp, struct svc_req *rqstp)
173 static char res;
175 return (voidp) &res;
179 nfsdiropres *
180 nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
182 static nfsdiropres res;
183 am_node *mp;
184 int retry;
186 #ifdef DEBUG
187 amuDebug(D_TRACE)
188 plog(XLOG_DEBUG, "lookup:");
189 #endif /* DEBUG */
191 mp = fh_to_mp2(&argp->da_fhandle, &retry);
192 if (mp == 0) {
193 if (retry < 0)
194 return 0;
195 res.dr_status = nfs_error(retry);
196 } else {
197 int error;
198 am_node *ap;
199 #ifdef DEBUG
200 amuDebug(D_TRACE)
201 plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->da_name);
202 #endif /* DEBUG */
203 ap = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &error, VLOOK_CREATE);
204 if (ap == 0) {
205 if (error < 0) {
206 #ifdef DEBUG
207 dlog("Not sending RPC reply");
208 #endif /* DEBUG */
209 amd_stats.d_drops++;
210 return 0;
212 res.dr_status = nfs_error(error);
213 } else {
215 * XXX: EXPERIMENTAL! Delay unmount of what was looked up. This
216 * should reduce the chance for race condition between unmounting an
217 * entry synchronously, and re-mounting it asynchronously.
219 if (ap->am_ttl < mp->am_ttl)
220 ap->am_ttl = mp->am_ttl;
221 mp_to_fh(ap, &res.dr_u.dr_drok_u.drok_fhandle);
222 res.dr_u.dr_drok_u.drok_attributes = ap->am_fattr;
223 res.dr_status = NFS_OK;
225 mp->am_stats.s_lookup++;
226 /* reschedule_timeout_mp(); */
229 return &res;
233 void
234 quick_reply(am_node *mp, int error)
236 SVCXPRT *transp = mp->am_transp;
237 nfsdiropres res;
238 xdrproc_t xdr_result = (xdrproc_t) xdr_diropres;
241 * If there's a transp structure then we can reply to the client's
242 * nfs lookup request.
244 if (transp) {
245 if (error == 0) {
247 * Construct a valid reply to a lookup request. Same
248 * code as in nfsproc_lookup_2_svc() above.
250 mp_to_fh(mp, &res.dr_u.dr_drok_u.drok_fhandle);
251 res.dr_u.dr_drok_u.drok_attributes = mp->am_fattr;
252 res.dr_status = NFS_OK;
253 } else
255 * Return the error that was passed to us.
257 res.dr_status = nfs_error(error);
260 * Send off our reply
262 if (!svc_sendreply(transp, (XDRPROC_T_TYPE) xdr_result, (SVC_IN_ARG_TYPE) & res))
263 svcerr_systemerr(transp);
266 * Free up transp. It's only used for one reply.
268 XFREE(transp);
269 mp->am_transp = NULL;
270 #ifdef DEBUG
271 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
272 #endif /* DEBUG */
277 nfsreadlinkres *
278 nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
280 static nfsreadlinkres res;
281 am_node *mp;
282 int retry;
284 #ifdef DEBUG
285 amuDebug(D_TRACE)
286 plog(XLOG_DEBUG, "readlink:");
287 #endif /* DEBUG */
289 mp = fh_to_mp2(argp, &retry);
290 if (mp == 0) {
291 readlink_retry:
292 if (retry < 0)
293 return 0;
294 res.rlr_status = nfs_error(retry);
295 } else {
296 char *ln = do_readlink(mp, &retry, (nfsattrstat **) 0);
297 if (ln == 0)
298 goto readlink_retry;
299 res.rlr_status = NFS_OK;
300 #ifdef DEBUG
301 amuDebug(D_TRACE)
302 if (ln)
303 plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
304 #endif /* DEBUG */
305 res.rlr_u.rlr_data_u = ln;
306 mp->am_stats.s_readlink++;
309 return &res;
313 nfsreadres *
314 nfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp)
316 static nfsreadres res;
318 memset((char *) &res, 0, sizeof(res));
319 res.rr_status = nfs_error(EACCES);
321 return &res;
325 voidp
326 nfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp)
328 static char res;
330 return (voidp) &res;
334 nfsattrstat *
335 nfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp)
337 static nfsattrstat res;
339 if (!fh_to_mp(&argp->wra_fhandle))
340 res.ns_status = nfs_error(ESTALE);
341 else
342 res.ns_status = nfs_error(EROFS);
344 return &res;
348 nfsdiropres *
349 nfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
351 static nfsdiropres res;
353 if (!fh_to_mp(&argp->ca_where.da_fhandle))
354 res.dr_status = nfs_error(ESTALE);
355 else
356 res.dr_status = nfs_error(EROFS);
358 return &res;
362 static nfsstat *
363 unlink_or_rmdir(nfsdiropargs *argp, struct svc_req *rqstp, int unlinkp)
365 static nfsstat res;
366 int retry;
368 am_node *mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_DELETE);
369 if (mp == 0) {
370 if (retry < 0)
371 return 0;
372 res = nfs_error(retry);
373 goto out;
376 if (mp->am_fattr.na_type != NFDIR) {
377 res = nfs_error(ENOTDIR);
378 goto out;
381 #ifdef DEBUG
382 amuDebug(D_TRACE)
383 plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->da_name);
384 #endif /* DEBUG */
386 mp = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &retry, VLOOK_DELETE);
387 if (mp == 0) {
389 * Ignore retries...
391 if (retry < 0)
392 retry = 0;
394 * Usual NFS workaround...
396 else if (retry == ENOENT)
397 retry = 0;
398 res = nfs_error(retry);
399 } else {
400 forcibly_timeout_mp(mp);
401 res = NFS_OK;
404 out:
405 return &res;
409 nfsstat *
410 nfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
412 return unlink_or_rmdir(argp, rqstp, TRUE);
416 nfsstat *
417 nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp)
419 static nfsstat res;
421 if (!fh_to_mp(&argp->rna_from.da_fhandle) || !fh_to_mp(&argp->rna_to.da_fhandle))
422 res = nfs_error(ESTALE);
424 * If the kernel is doing clever things with referenced files
425 * then let it pretend...
427 else if (NSTREQ(argp->rna_to.da_name, ".nfs", 4))
428 res = NFS_OK;
430 * otherwise a failure
432 else
433 res = nfs_error(EROFS);
435 return &res;
439 nfsstat *
440 nfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp)
442 static nfsstat res;
444 if (!fh_to_mp(&argp->la_fhandle) || !fh_to_mp(&argp->la_to.da_fhandle))
445 res = nfs_error(ESTALE);
446 else
447 res = nfs_error(EROFS);
449 return &res;
453 nfsstat *
454 nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp)
456 static nfsstat res;
458 if (!fh_to_mp(&argp->sla_from.da_fhandle))
459 res = nfs_error(ESTALE);
460 else
461 res = nfs_error(EROFS);
463 return &res;
467 nfsdiropres *
468 nfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
470 static nfsdiropres res;
472 if (!fh_to_mp(&argp->ca_where.da_fhandle))
473 res.dr_status = nfs_error(ESTALE);
474 else
475 res.dr_status = nfs_error(EROFS);
477 return &res;
481 nfsstat *
482 nfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
484 return unlink_or_rmdir(argp, rqstp, FALSE);
488 nfsreaddirres *
489 nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp)
491 static nfsreaddirres res;
492 static nfsentry e_res[MAX_READDIR_ENTRIES];
493 am_node *mp;
494 int retry;
496 #ifdef DEBUG
497 amuDebug(D_TRACE)
498 plog(XLOG_DEBUG, "readdir:");
499 #endif /* DEBUG */
501 mp = fh_to_mp2(&argp->rda_fhandle, &retry);
502 if (mp == 0) {
503 if (retry < 0)
504 return 0;
505 res.rdr_status = nfs_error(retry);
506 } else {
507 #ifdef DEBUG
508 amuDebug(D_TRACE)
509 plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
510 #endif /* DEBUG */
511 res.rdr_status = nfs_error((*mp->am_mnt->mf_ops->readdir)
512 (mp, argp->rda_cookie,
513 &res.rdr_u.rdr_reply_u, e_res, argp->rda_count));
514 mp->am_stats.s_readdir++;
517 return &res;
521 nfsstatfsres *
522 nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
524 static nfsstatfsres res;
525 am_node *mp;
526 int retry;
527 mntent_t mnt;
529 #ifdef DEBUG
530 amuDebug(D_TRACE)
531 plog(XLOG_DEBUG, "statfs:");
532 #endif /* DEBUG */
534 mp = fh_to_mp2(argp, &retry);
535 if (mp == 0) {
536 if (retry < 0)
537 return 0;
538 res.sfr_status = nfs_error(retry);
539 } else {
540 nfsstatfsokres *fp;
541 #ifdef DEBUG
542 amuDebug(D_TRACE)
543 plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
544 #endif /* DEBUG */
547 * just return faked up file system information
549 fp = &res.sfr_u.sfr_reply_u;
551 fp->sfrok_tsize = 1024;
552 fp->sfrok_bsize = 1024;
554 /* check if map is browsable and show_statfs_entries=yes */
555 if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) &&
556 mp->am_mnt && mp->am_mnt->mf_mopts) {
557 mnt.mnt_opts = mp->am_mnt->mf_mopts;
558 if (hasmntopt(&mnt, "browsable")) {
559 count_map_entries(mp,
560 &fp->sfrok_blocks,
561 &fp->sfrok_bfree,
562 &fp->sfrok_bavail);
564 } else {
565 fp->sfrok_blocks = 0; /* set to 1 if you don't want empty automounts */
566 fp->sfrok_bfree = 0;
567 fp->sfrok_bavail = 0;
570 res.sfr_status = NFS_OK;
571 mp->am_stats.s_statfs++;
574 return &res;
579 * count how many total entries there are in a map, and how many
580 * of them are in use.
582 static void
583 count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail)
585 u_int blocks, bfree, bavail, i;
586 mntfs *mf;
587 mnt_map *mmp;
588 kv *k;
590 blocks = bfree = bavail = 0;
591 if (!mp)
592 goto out;
593 mf = mp->am_mnt;
594 if (!mf)
595 goto out;
596 mmp = (mnt_map *) mf->mf_private;
597 if (!mmp)
598 goto out;
600 /* iterate over keys */
601 for (i = 0; i < NKVHASH; i++) {
602 for (k = mmp->kvhash[i]; k ; k = k->next) {
603 if (!k->key)
604 continue;
605 blocks++;
607 * XXX: Need to count how many are actively in use and recompute
608 * bfree and bavail based on it.
613 out:
614 *out_blocks = blocks;
615 *out_bfree = bfree;
616 *out_bavail = bavail;