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.
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
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
41 * $Id: nfs_subr.c,v 1.3 1999/01/13 23:31:00 ezk Exp $
47 #endif /* HAVE_CONFIG_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).
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);
65 do_readlink(am_node *mp, int *error_return, nfsattrstat **attrpp)
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) {
76 mp = (*mp->am_mnt->mf_ops->readlink) (mp, &retry);
78 *error_return = retry;
81 /* reschedule_timeout_mp(); */
87 ln = mp->am_mnt->mf_mount;
90 *attrpp = &mp->am_attr;
97 nfsproc_null_2_svc(voidp argp, struct svc_req *rqstp)
106 nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
108 static nfsattrstat res;
114 plog(XLOG_DEBUG, "getattr:");
117 mp = fh_to_mp2(argp, &retry);
122 plog(XLOG_DEBUG, "\tretry=%d", retry);
127 res.ns_status = nfs_error(retry);
129 nfsattrstat *attrp = &mp->am_attr;
133 plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path,
134 (int) attrp->ns_u.ns_attr_u.na_size);
137 mp->am_stats.s_getattr++;
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 */
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);
164 res.ns_status = nfs_error(EROFS);
171 nfsproc_root_2_svc(voidp argp, struct svc_req *rqstp)
180 nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
182 static nfsdiropres res;
188 plog(XLOG_DEBUG, "lookup:");
191 mp = fh_to_mp2(&argp->da_fhandle, &retry);
195 res.dr_status = nfs_error(retry);
201 plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->da_name);
203 ap = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &error, VLOOK_CREATE);
207 dlog("Not sending RPC reply");
212 res.dr_status = nfs_error(error);
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(); */
234 quick_reply(am_node *mp, int error)
236 SVCXPRT *transp = mp->am_transp;
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.
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;
255 * Return the error that was passed to us.
257 res.dr_status = nfs_error(error);
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.
269 mp->am_transp = NULL;
271 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
278 nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
280 static nfsreadlinkres res;
286 plog(XLOG_DEBUG, "readlink:");
289 mp = fh_to_mp2(argp, &retry);
294 res.rlr_status = nfs_error(retry);
296 char *ln = do_readlink(mp, &retry, (nfsattrstat **) 0);
299 res.rlr_status = NFS_OK;
303 plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
305 res.rlr_u.rlr_data_u = ln;
306 mp->am_stats.s_readlink++;
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);
326 nfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp)
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);
342 res.ns_status = nfs_error(EROFS);
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);
356 res.dr_status = nfs_error(EROFS);
363 unlink_or_rmdir(nfsdiropargs *argp, struct svc_req *rqstp, int unlinkp)
368 am_node *mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_DELETE);
372 res = nfs_error(retry);
376 if (mp->am_fattr.na_type != NFDIR) {
377 res = nfs_error(ENOTDIR);
383 plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->da_name);
386 mp = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &retry, VLOOK_DELETE);
394 * Usual NFS workaround...
396 else if (retry == ENOENT)
398 res = nfs_error(retry);
400 forcibly_timeout_mp(mp);
410 nfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
412 return unlink_or_rmdir(argp, rqstp, TRUE);
417 nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp)
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))
430 * otherwise a failure
433 res = nfs_error(EROFS);
440 nfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp)
444 if (!fh_to_mp(&argp->la_fhandle) || !fh_to_mp(&argp->la_to.da_fhandle))
445 res = nfs_error(ESTALE);
447 res = nfs_error(EROFS);
454 nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp)
458 if (!fh_to_mp(&argp->sla_from.da_fhandle))
459 res = nfs_error(ESTALE);
461 res = nfs_error(EROFS);
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);
475 res.dr_status = nfs_error(EROFS);
482 nfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
484 return unlink_or_rmdir(argp, rqstp, FALSE);
489 nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp)
491 static nfsreaddirres res;
492 static nfsentry e_res[MAX_READDIR_ENTRIES];
498 plog(XLOG_DEBUG, "readdir:");
501 mp = fh_to_mp2(&argp->rda_fhandle, &retry);
505 res.rdr_status = nfs_error(retry);
509 plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
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++;
522 nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
524 static nfsstatfsres res;
531 plog(XLOG_DEBUG, "statfs:");
534 mp = fh_to_mp2(argp, &retry);
538 res.sfr_status = nfs_error(retry);
543 plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
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,
565 fp->sfrok_blocks = 0; /* set to 1 if you don't want empty automounts */
567 fp->sfrok_bavail = 0;
570 res.sfr_status = NFS_OK;
571 mp->am_stats.s_statfs++;
579 * count how many total entries there are in a map, and how many
580 * of them are in use.
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;
590 blocks = bfree = bavail = 0;
596 mmp = (mnt_map *) mf->mf_private;
600 /* iterate over keys */
601 for (i = 0; i < NKVHASH; i++) {
602 for (k = mmp->kvhash[i]; k ; k = k->next) {
607 * XXX: Need to count how many are actively in use and recompute
608 * bfree and bavail based on it.
614 *out_blocks = blocks;
616 *out_bavail = bavail;