2 * Copyright (c) 1997-2004 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.6.2.6 2004/01/06 03:15:16 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;
111 time_t now = clocktime();
115 plog(XLOG_DEBUG, "getattr:");
118 mp = fh_to_mp2(argp, &retry);
123 plog(XLOG_DEBUG, "\tretry=%d", retry);
130 res.ns_status = nfs_error(retry);
132 nfsattrstat *attrp = &mp->am_attr;
136 plog(XLOG_DEBUG, "\tstat(%s), size = %d, mtime=%ld",
138 (int) attrp->ns_u.ns_attr_u.na_size,
139 (long) attrp->ns_u.ns_attr_u.na_mtime.nt_seconds);
142 /* Delay unmount of what was looked up */
143 if (mp->am_timeo_w < 4 * gopt.am_timeo_w)
144 mp->am_timeo_w += gopt.am_timeo_w;
145 mp->am_ttl = now + mp->am_timeo_w;
147 mp->am_stats.s_getattr++;
156 nfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp)
158 static nfsattrstat res;
160 if (!fh_to_mp(&argp->sag_fhandle))
161 res.ns_status = nfs_error(ESTALE);
163 res.ns_status = nfs_error(EROFS);
170 nfsproc_root_2_svc(voidp argp, struct svc_req *rqstp)
179 nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
181 static nfsdiropres res;
189 plog(XLOG_DEBUG, "lookup:");
192 /* finally, find the effective uid/gid from RPC request */
193 if (getcreds(rqstp, &uid, &gid, nfsxprt) < 0)
194 plog(XLOG_ERROR, "cannot get uid/gid from RPC credentials");
195 sprintf(opt_uid, "%d", (int) uid);
196 sprintf(opt_gid, "%d", (int) gid);
198 mp = fh_to_mp2(&argp->da_fhandle, &retry);
204 res.dr_status = nfs_error(retry);
210 plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->da_name);
212 ap = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &error, VLOOK_CREATE);
218 res.dr_status = nfs_error(error);
221 * XXX: EXPERIMENTAL! Delay unmount of what was looked up. This
222 * should reduce the chance for race condition between unmounting an
223 * entry synchronously, and re-mounting it asynchronously.
225 if (ap->am_ttl < mp->am_ttl)
226 ap->am_ttl = mp->am_ttl;
227 mp_to_fh(ap, &res.dr_u.dr_drok_u.drok_fhandle);
228 res.dr_u.dr_drok_u.drok_attributes = ap->am_fattr;
229 res.dr_status = NFS_OK;
231 mp->am_stats.s_lookup++;
232 /* reschedule_timeout_mp(); */
240 quick_reply(am_node *mp, int error)
242 SVCXPRT *transp = mp->am_transp;
244 xdrproc_t xdr_result = (xdrproc_t) xdr_diropres;
247 * If there's a transp structure then we can reply to the client's
248 * nfs lookup request.
253 * Construct a valid reply to a lookup request. Same
254 * code as in nfsproc_lookup_2_svc() above.
256 mp_to_fh(mp, &res.dr_u.dr_drok_u.drok_fhandle);
257 res.dr_u.dr_drok_u.drok_attributes = mp->am_fattr;
258 res.dr_status = NFS_OK;
261 * Return the error that was passed to us.
263 res.dr_status = nfs_error(error);
268 if (!svc_sendreply(transp, (XDRPROC_T_TYPE) xdr_result, (SVC_IN_ARG_TYPE) & res))
269 svcerr_systemerr(transp);
272 * Free up transp. It's only used for one reply.
275 mp->am_transp = NULL;
277 dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
284 nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
286 static nfsreadlinkres res;
292 plog(XLOG_DEBUG, "readlink:");
295 mp = fh_to_mp2(argp, &retry);
302 res.rlr_status = nfs_error(retry);
304 char *ln = do_readlink(mp, &retry, (nfsattrstat **) 0);
307 res.rlr_status = NFS_OK;
311 plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
313 res.rlr_u.rlr_data_u = ln;
314 mp->am_stats.s_readlink++;
322 nfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp)
324 static nfsreadres res;
326 memset((char *) &res, 0, sizeof(res));
327 res.rr_status = nfs_error(EACCES);
334 nfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp)
343 nfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp)
345 static nfsattrstat res;
347 if (!fh_to_mp(&argp->wra_fhandle))
348 res.ns_status = nfs_error(ESTALE);
350 res.ns_status = nfs_error(EROFS);
357 nfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
359 static nfsdiropres res;
361 if (!fh_to_mp(&argp->ca_where.da_fhandle))
362 res.dr_status = nfs_error(ESTALE);
364 res.dr_status = nfs_error(EROFS);
371 unlink_or_rmdir(nfsdiropargs *argp, struct svc_req *rqstp, int unlinkp)
376 am_node *mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_DELETE);
382 res = nfs_error(retry);
386 if (mp->am_fattr.na_type != NFDIR) {
387 res = nfs_error(ENOTDIR);
393 plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->da_name);
396 mp = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &retry, VLOOK_DELETE);
404 * Usual NFS workaround...
406 else if (retry == ENOENT)
408 res = nfs_error(retry);
410 forcibly_timeout_mp(mp);
420 nfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
422 return unlink_or_rmdir(argp, rqstp, TRUE);
427 nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp)
431 if (!fh_to_mp(&argp->rna_from.da_fhandle) || !fh_to_mp(&argp->rna_to.da_fhandle))
432 res = nfs_error(ESTALE);
434 * If the kernel is doing clever things with referenced files
435 * then let it pretend...
437 else if (NSTREQ(argp->rna_to.da_name, ".nfs", 4))
440 * otherwise a failure
443 res = nfs_error(EROFS);
450 nfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp)
454 if (!fh_to_mp(&argp->la_fhandle) || !fh_to_mp(&argp->la_to.da_fhandle))
455 res = nfs_error(ESTALE);
457 res = nfs_error(EROFS);
464 nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp)
468 if (!fh_to_mp(&argp->sla_from.da_fhandle))
469 res = nfs_error(ESTALE);
471 res = nfs_error(EROFS);
478 nfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
480 static nfsdiropres res;
482 if (!fh_to_mp(&argp->ca_where.da_fhandle))
483 res.dr_status = nfs_error(ESTALE);
485 res.dr_status = nfs_error(EROFS);
492 nfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
494 return unlink_or_rmdir(argp, rqstp, FALSE);
499 nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp)
501 static nfsreaddirres res;
502 static nfsentry e_res[MAX_READDIR_ENTRIES];
508 plog(XLOG_DEBUG, "readdir:");
511 mp = fh_to_mp2(&argp->rda_fhandle, &retry);
517 res.rdr_status = nfs_error(retry);
521 plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
523 res.rdr_status = nfs_error((*mp->am_mnt->mf_ops->readdir)
524 (mp, argp->rda_cookie,
525 &res.rdr_u.rdr_reply_u, e_res, argp->rda_count));
526 mp->am_stats.s_readdir++;
534 nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
536 static nfsstatfsres res;
543 plog(XLOG_DEBUG, "statfs:");
546 mp = fh_to_mp2(argp, &retry);
552 res.sfr_status = nfs_error(retry);
557 plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
561 * just return faked up file system information
563 fp = &res.sfr_u.sfr_reply_u;
565 fp->sfrok_tsize = 1024;
566 fp->sfrok_bsize = 1024;
568 /* check if map is browsable and show_statfs_entries=yes */
569 if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) &&
570 mp->am_mnt && mp->am_mnt->mf_mopts) {
571 mnt.mnt_opts = mp->am_mnt->mf_mopts;
572 if (hasmntopt(&mnt, "browsable")) {
573 count_map_entries(mp,
579 fp->sfrok_blocks = 0; /* set to 1 if you don't want empty automounts */
581 fp->sfrok_bavail = 0;
584 res.sfr_status = NFS_OK;
585 mp->am_stats.s_statfs++;
593 * count how many total entries there are in a map, and how many
594 * of them are in use.
597 count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail)
599 u_int blocks, bfree, bavail, i;
604 blocks = bfree = bavail = 0;
610 mmp = (mnt_map *) mf->mf_private;
614 /* iterate over keys */
615 for (i = 0; i < NKVHASH; i++) {
616 for (k = mmp->kvhash[i]; k ; k = k->next) {
621 * XXX: Need to count how many are actively in use and recompute
622 * bfree and bavail based on it.
628 *out_blocks = blocks;
630 *out_bavail = bavail;