nfs_subr.c revision 42629
138494Sobrien/*
238494Sobrien * Copyright (c) 1997-1998 Erez Zadok
338494Sobrien * Copyright (c) 1990 Jan-Simon Pendry
438494Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
538494Sobrien * Copyright (c) 1990 The Regents of the University of California.
638494Sobrien * All rights reserved.
738494Sobrien *
838494Sobrien * This code is derived from software contributed to Berkeley by
938494Sobrien * Jan-Simon Pendry at Imperial College, London.
1038494Sobrien *
1138494Sobrien * Redistribution and use in source and binary forms, with or without
1238494Sobrien * modification, are permitted provided that the following conditions
1338494Sobrien * are met:
1438494Sobrien * 1. Redistributions of source code must retain the above copyright
1538494Sobrien *    notice, this list of conditions and the following disclaimer.
1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1738494Sobrien *    notice, this list of conditions and the following disclaimer in the
1838494Sobrien *    documentation and/or other materials provided with the distribution.
1938494Sobrien * 3. All advertising materials mentioning features or use of this software
2042629Sobrien *    must display the following acknowledgment:
2138494Sobrien *      This product includes software developed by the University of
2238494Sobrien *      California, Berkeley and its contributors.
2338494Sobrien * 4. Neither the name of the University nor the names of its contributors
2438494Sobrien *    may be used to endorse or promote products derived from this software
2538494Sobrien *    without specific prior written permission.
2638494Sobrien *
2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3038494Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3738494Sobrien * SUCH DAMAGE.
3838494Sobrien *
3938494Sobrien *      %W% (Berkeley) %G%
4038494Sobrien *
4142629Sobrien * $Id: nfs_subr.c,v 1.1.1.1 1998/11/05 02:04:48 ezk Exp $
4238494Sobrien *
4338494Sobrien */
4438494Sobrien
4538494Sobrien#ifdef HAVE_CONFIG_H
4638494Sobrien# include <config.h>
4738494Sobrien#endif /* HAVE_CONFIG_H */
4838494Sobrien#include <am_defs.h>
4938494Sobrien#include <amd.h>
5038494Sobrien
5138494Sobrien/*
5238494Sobrien * Convert from UN*X to NFS error code.
5338494Sobrien * Some systems like linux define their own (see
5438494Sobrien * conf/mount/mount_linux.h).
5538494Sobrien */
5638494Sobrien#ifndef nfs_error
5738494Sobrien# define nfs_error(e) ((nfsstat)(e))
5838494Sobrien#endif /* nfs_error */
5938494Sobrien
6038494Sobrien/* forward declarations */
6138494Sobrienstatic void count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail);
6238494Sobrien
6338494Sobrien
6438494Sobrienstatic char *
6538494Sobriendo_readlink(am_node *mp, int *error_return, nfsattrstat **attrpp)
6638494Sobrien{
6738494Sobrien  char *ln;
6838494Sobrien
6938494Sobrien  /*
7038494Sobrien   * If there is a readlink method, then use
7138494Sobrien   * that, otherwise if a link exists use
7238494Sobrien   * that, otherwise use the mount point.
7338494Sobrien   */
7438494Sobrien  if (mp->am_mnt->mf_ops->readlink) {
7538494Sobrien    int retry = 0;
7638494Sobrien    mp = (*mp->am_mnt->mf_ops->readlink) (mp, &retry);
7738494Sobrien    if (mp == 0) {
7838494Sobrien      *error_return = retry;
7938494Sobrien      return 0;
8038494Sobrien    }
8138494Sobrien    /* reschedule_timeout_mp(); */
8238494Sobrien  }
8338494Sobrien
8438494Sobrien  if (mp->am_link) {
8538494Sobrien    ln = mp->am_link;
8638494Sobrien  } else {
8738494Sobrien    ln = mp->am_mnt->mf_mount;
8838494Sobrien  }
8938494Sobrien  if (attrpp)
9038494Sobrien    *attrpp = &mp->am_attr;
9138494Sobrien
9238494Sobrien  return ln;
9338494Sobrien}
9438494Sobrien
9538494Sobrien
9638494Sobrienvoidp
9738494Sobriennfsproc_null_2_svc(voidp argp, struct svc_req *rqstp)
9838494Sobrien{
9938494Sobrien  static char res;
10038494Sobrien
10138494Sobrien  return (voidp) &res;
10238494Sobrien}
10338494Sobrien
10438494Sobrien
10538494Sobriennfsattrstat *
10638494Sobriennfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
10738494Sobrien{
10838494Sobrien  static nfsattrstat res;
10938494Sobrien  am_node *mp;
11038494Sobrien  int retry;
11138494Sobrien
11238494Sobrien#ifdef DEBUG
11338494Sobrien  amuDebug(D_TRACE)
11438494Sobrien    plog(XLOG_DEBUG, "getattr:");
11538494Sobrien#endif /* DEBUG */
11638494Sobrien
11738494Sobrien  mp = fh_to_mp2(argp, &retry);
11838494Sobrien  if (mp == 0) {
11938494Sobrien
12038494Sobrien#ifdef DEBUG
12138494Sobrien    amuDebug(D_TRACE)
12238494Sobrien      plog(XLOG_DEBUG, "\tretry=%d", retry);
12338494Sobrien#endif /* DEBUG */
12438494Sobrien
12538494Sobrien    if (retry < 0)
12638494Sobrien      return 0;
12738494Sobrien    res.ns_status = nfs_error(retry);
12838494Sobrien  } else {
12938494Sobrien    nfsattrstat *attrp = &mp->am_attr;
13038494Sobrien
13138494Sobrien#ifdef DEBUG
13238494Sobrien    amuDebug(D_TRACE)
13338494Sobrien      plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path,
13438494Sobrien	   attrp->ns_u.ns_attr_u.na_size);
13538494Sobrien#endif /* DEBUG */
13638494Sobrien
13738494Sobrien    mp->am_stats.s_getattr++;
13838494Sobrien    return attrp;
13938494Sobrien  }
14038494Sobrien
14138494Sobrien#ifndef MNT2_NFS_OPT_SYMTTL
14238494Sobrien  /*
14338494Sobrien   * This code is needed to defeat Solaris 2.4's (and newer) symlink values
14442629Sobrien   * cache.  It forces the last-modified time of the symlink to be current.
14538494Sobrien   * It is not needed if the O/S has an nfs flag to turn off the
14638494Sobrien   * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
14738494Sobrien   */
14838494Sobrien  if (++res.ns_u.ns_attr_u.na_mtime.nt_useconds == 0)
14938494Sobrien    ++res.ns_u.ns_attr_u.na_mtime.nt_seconds;
15038494Sobrien#endif /* not MNT2_NFS_OPT_SYMTTL */
15138494Sobrien
15238494Sobrien  return &res;
15338494Sobrien}
15438494Sobrien
15538494Sobrien
15638494Sobriennfsattrstat *
15738494Sobriennfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp)
15838494Sobrien{
15938494Sobrien  static nfsattrstat res;
16038494Sobrien
16138494Sobrien  if (!fh_to_mp(&argp->sag_fhandle))
16238494Sobrien    res.ns_status = nfs_error(ESTALE);
16338494Sobrien  else
16438494Sobrien    res.ns_status = nfs_error(EROFS);
16538494Sobrien
16638494Sobrien  return &res;
16738494Sobrien}
16838494Sobrien
16938494Sobrien
17038494Sobrienvoidp
17138494Sobriennfsproc_root_2_svc(voidp argp, struct svc_req *rqstp)
17238494Sobrien{
17338494Sobrien  static char res;
17438494Sobrien
17538494Sobrien  return (voidp) &res;
17638494Sobrien}
17738494Sobrien
17838494Sobrien
17938494Sobriennfsdiropres *
18038494Sobriennfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
18138494Sobrien{
18238494Sobrien  static nfsdiropres res;
18338494Sobrien  am_node *mp;
18438494Sobrien  int retry;
18538494Sobrien
18638494Sobrien#ifdef DEBUG
18738494Sobrien  amuDebug(D_TRACE)
18838494Sobrien    plog(XLOG_DEBUG, "lookup:");
18938494Sobrien#endif /* DEBUG */
19038494Sobrien
19138494Sobrien  mp = fh_to_mp2(&argp->da_fhandle, &retry);
19238494Sobrien  if (mp == 0) {
19338494Sobrien    if (retry < 0)
19438494Sobrien      return 0;
19538494Sobrien    res.dr_status = nfs_error(retry);
19638494Sobrien  } else {
19738494Sobrien    int error;
19838494Sobrien    am_node *ap;
19938494Sobrien#ifdef DEBUG
20038494Sobrien    amuDebug(D_TRACE)
20138494Sobrien      plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->da_name);
20238494Sobrien#endif /* DEBUG */
20338494Sobrien    ap = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &error, VLOOK_CREATE);
20438494Sobrien    if (ap == 0) {
20538494Sobrien      if (error < 0) {
20638494Sobrien#ifdef DEBUG
20738494Sobrien	dlog("Not sending RPC reply");
20838494Sobrien#endif /* DEBUG */
20938494Sobrien	amd_stats.d_drops++;
21038494Sobrien	return 0;
21138494Sobrien      }
21238494Sobrien      res.dr_status = nfs_error(error);
21338494Sobrien    } else {
21442629Sobrien      /*
21542629Sobrien       * XXX: EXPERIMENTAL! Delay unmount of what was looked up.  This
21642629Sobrien       * should reduce the chance for race condition between unmounting an
21742629Sobrien       * entry synchronously, and re-mounting it asynchronously.
21842629Sobrien       */
21942629Sobrien      if (ap->am_ttl < mp->am_ttl)
22042629Sobrien 	ap->am_ttl = mp->am_ttl;
22138494Sobrien      mp_to_fh(ap, &res.dr_u.dr_drok_u.drok_fhandle);
22238494Sobrien      res.dr_u.dr_drok_u.drok_attributes = ap->am_fattr;
22338494Sobrien      res.dr_status = NFS_OK;
22438494Sobrien    }
22538494Sobrien    mp->am_stats.s_lookup++;
22638494Sobrien    /* reschedule_timeout_mp(); */
22738494Sobrien  }
22838494Sobrien
22938494Sobrien  return &res;
23038494Sobrien}
23138494Sobrien
23238494Sobrien
23338494Sobrienvoid
23438494Sobrienquick_reply(am_node *mp, int error)
23538494Sobrien{
23638494Sobrien  SVCXPRT *transp = mp->am_transp;
23738494Sobrien  nfsdiropres res;
23838494Sobrien  xdrproc_t xdr_result = (xdrproc_t) xdr_diropres;
23938494Sobrien
24038494Sobrien  /*
24138494Sobrien   * If there's a transp structure then we can reply to the client's
24238494Sobrien   * nfs lookup request.
24338494Sobrien   */
24438494Sobrien  if (transp) {
24538494Sobrien    if (error == 0) {
24638494Sobrien      /*
24738494Sobrien       * Construct a valid reply to a lookup request.  Same
24838494Sobrien       * code as in nfsproc_lookup_2_svc() above.
24938494Sobrien       */
25038494Sobrien      mp_to_fh(mp, &res.dr_u.dr_drok_u.drok_fhandle);
25138494Sobrien      res.dr_u.dr_drok_u.drok_attributes = mp->am_fattr;
25238494Sobrien      res.dr_status = NFS_OK;
25338494Sobrien    } else
25438494Sobrien      /*
25538494Sobrien       * Return the error that was passed to us.
25638494Sobrien       */
25738494Sobrien      res.dr_status = nfs_error(error);
25838494Sobrien
25938494Sobrien    /*
26038494Sobrien     * Send off our reply
26138494Sobrien     */
26238494Sobrien    if (!svc_sendreply(transp, (XDRPROC_T_TYPE) xdr_result, (SVC_IN_ARG_TYPE) & res))
26338494Sobrien      svcerr_systemerr(transp);
26438494Sobrien
26538494Sobrien    /*
26638494Sobrien     * Free up transp.  It's only used for one reply.
26738494Sobrien     */
26838494Sobrien    XFREE(transp);
26938494Sobrien    mp->am_transp = NULL;
27038494Sobrien#ifdef DEBUG
27138494Sobrien    dlog("Quick reply sent for %s", mp->am_mnt->mf_mount);
27238494Sobrien#endif /* DEBUG */
27338494Sobrien  }
27438494Sobrien}
27538494Sobrien
27638494Sobrien
27738494Sobriennfsreadlinkres *
27838494Sobriennfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
27938494Sobrien{
28038494Sobrien  static nfsreadlinkres res;
28138494Sobrien  am_node *mp;
28238494Sobrien  int retry;
28338494Sobrien
28438494Sobrien#ifdef DEBUG
28538494Sobrien  amuDebug(D_TRACE)
28638494Sobrien    plog(XLOG_DEBUG, "readlink:");
28738494Sobrien#endif /* DEBUG */
28838494Sobrien
28938494Sobrien  mp = fh_to_mp2(argp, &retry);
29038494Sobrien  if (mp == 0) {
29138494Sobrien  readlink_retry:
29238494Sobrien    if (retry < 0)
29338494Sobrien      return 0;
29438494Sobrien    res.rlr_status = nfs_error(retry);
29538494Sobrien  } else {
29638494Sobrien    char *ln = do_readlink(mp, &retry, (nfsattrstat **) 0);
29738494Sobrien    if (ln == 0)
29838494Sobrien      goto readlink_retry;
29938494Sobrien    res.rlr_status = NFS_OK;
30038494Sobrien#ifdef DEBUG
30138494Sobrien    amuDebug(D_TRACE)
30238494Sobrien      if (ln)
30338494Sobrien	plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
30438494Sobrien#endif /* DEBUG */
30538494Sobrien    res.rlr_u.rlr_data_u = ln;
30638494Sobrien    mp->am_stats.s_readlink++;
30738494Sobrien  }
30838494Sobrien
30938494Sobrien  return &res;
31038494Sobrien}
31138494Sobrien
31238494Sobrien
31338494Sobriennfsreadres *
31438494Sobriennfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp)
31538494Sobrien{
31638494Sobrien  static nfsreadres res;
31738494Sobrien
31838494Sobrien  memset((char *) &res, 0, sizeof(res));
31938494Sobrien  res.rr_status = nfs_error(EACCES);
32038494Sobrien
32138494Sobrien  return &res;
32238494Sobrien}
32338494Sobrien
32438494Sobrien
32538494Sobrienvoidp
32638494Sobriennfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp)
32738494Sobrien{
32838494Sobrien  static char res;
32938494Sobrien
33038494Sobrien  return (voidp) &res;
33138494Sobrien}
33238494Sobrien
33338494Sobrien
33438494Sobriennfsattrstat *
33538494Sobriennfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp)
33638494Sobrien{
33738494Sobrien  static nfsattrstat res;
33838494Sobrien
33938494Sobrien  if (!fh_to_mp(&argp->wra_fhandle))
34038494Sobrien    res.ns_status = nfs_error(ESTALE);
34138494Sobrien  else
34238494Sobrien    res.ns_status = nfs_error(EROFS);
34338494Sobrien
34438494Sobrien  return &res;
34538494Sobrien}
34638494Sobrien
34738494Sobrien
34838494Sobriennfsdiropres *
34938494Sobriennfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
35038494Sobrien{
35138494Sobrien  static nfsdiropres res;
35238494Sobrien
35338494Sobrien  if (!fh_to_mp(&argp->ca_where.da_fhandle))
35438494Sobrien    res.dr_status = nfs_error(ESTALE);
35538494Sobrien  else
35638494Sobrien    res.dr_status = nfs_error(EROFS);
35738494Sobrien
35838494Sobrien  return &res;
35938494Sobrien}
36038494Sobrien
36138494Sobrien
36238494Sobrienstatic nfsstat *
36338494Sobrienunlink_or_rmdir(nfsdiropargs *argp, struct svc_req *rqstp, int unlinkp)
36438494Sobrien{
36538494Sobrien  static nfsstat res;
36638494Sobrien  int retry;
36738494Sobrien
36838494Sobrien  am_node *mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_DELETE);
36938494Sobrien  if (mp == 0) {
37038494Sobrien    if (retry < 0)
37138494Sobrien      return 0;
37238494Sobrien    res = nfs_error(retry);
37338494Sobrien    goto out;
37438494Sobrien  }
37538494Sobrien
37638494Sobrien  if (mp->am_fattr.na_type != NFDIR) {
37738494Sobrien    res = nfs_error(ENOTDIR);
37838494Sobrien    goto out;
37938494Sobrien  }
38038494Sobrien
38138494Sobrien#ifdef DEBUG
38238494Sobrien  amuDebug(D_TRACE)
38338494Sobrien    plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->da_name);
38438494Sobrien#endif /* DEBUG */
38538494Sobrien
38638494Sobrien  mp = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &retry, VLOOK_DELETE);
38738494Sobrien  if (mp == 0) {
38838494Sobrien    /*
38938494Sobrien     * Ignore retries...
39038494Sobrien     */
39138494Sobrien    if (retry < 0)
39238494Sobrien      retry = 0;
39338494Sobrien    /*
39438494Sobrien     * Usual NFS workaround...
39538494Sobrien     */
39638494Sobrien    else if (retry == ENOENT)
39738494Sobrien      retry = 0;
39838494Sobrien    res = nfs_error(retry);
39938494Sobrien  } else {
40038494Sobrien    forcibly_timeout_mp(mp);
40138494Sobrien    res = NFS_OK;
40238494Sobrien  }
40338494Sobrien
40438494Sobrienout:
40538494Sobrien  return &res;
40638494Sobrien}
40738494Sobrien
40838494Sobrien
40938494Sobriennfsstat *
41038494Sobriennfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
41138494Sobrien{
41238494Sobrien  return unlink_or_rmdir(argp, rqstp, TRUE);
41338494Sobrien}
41438494Sobrien
41538494Sobrien
41638494Sobriennfsstat *
41738494Sobriennfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp)
41838494Sobrien{
41938494Sobrien  static nfsstat res;
42038494Sobrien
42138494Sobrien  if (!fh_to_mp(&argp->rna_from.da_fhandle) || !fh_to_mp(&argp->rna_to.da_fhandle))
42238494Sobrien    res = nfs_error(ESTALE);
42338494Sobrien  /*
42438494Sobrien   * If the kernel is doing clever things with referenced files
42538494Sobrien   * then let it pretend...
42638494Sobrien   */
42738494Sobrien  else if (NSTREQ(argp->rna_to.da_name, ".nfs", 4))
42838494Sobrien    res = NFS_OK;
42938494Sobrien  /*
43038494Sobrien   * otherwise a failure
43138494Sobrien   */
43238494Sobrien  else
43338494Sobrien    res = nfs_error(EROFS);
43438494Sobrien
43538494Sobrien  return &res;
43638494Sobrien}
43738494Sobrien
43838494Sobrien
43938494Sobriennfsstat *
44038494Sobriennfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp)
44138494Sobrien{
44238494Sobrien  static nfsstat res;
44338494Sobrien
44438494Sobrien  if (!fh_to_mp(&argp->la_fhandle) || !fh_to_mp(&argp->la_to.da_fhandle))
44538494Sobrien    res = nfs_error(ESTALE);
44638494Sobrien  else
44738494Sobrien    res = nfs_error(EROFS);
44838494Sobrien
44938494Sobrien  return &res;
45038494Sobrien}
45138494Sobrien
45238494Sobrien
45338494Sobriennfsstat *
45438494Sobriennfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp)
45538494Sobrien{
45638494Sobrien  static nfsstat res;
45738494Sobrien
45838494Sobrien  if (!fh_to_mp(&argp->sla_from.da_fhandle))
45938494Sobrien    res = nfs_error(ESTALE);
46038494Sobrien  else
46138494Sobrien    res = nfs_error(EROFS);
46238494Sobrien
46338494Sobrien  return &res;
46438494Sobrien}
46538494Sobrien
46638494Sobrien
46738494Sobriennfsdiropres *
46838494Sobriennfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
46938494Sobrien{
47038494Sobrien  static nfsdiropres res;
47138494Sobrien
47238494Sobrien  if (!fh_to_mp(&argp->ca_where.da_fhandle))
47338494Sobrien    res.dr_status = nfs_error(ESTALE);
47438494Sobrien  else
47538494Sobrien    res.dr_status = nfs_error(EROFS);
47638494Sobrien
47738494Sobrien  return &res;
47838494Sobrien}
47938494Sobrien
48038494Sobrien
48138494Sobriennfsstat *
48238494Sobriennfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
48338494Sobrien{
48438494Sobrien  return unlink_or_rmdir(argp, rqstp, FALSE);
48538494Sobrien}
48638494Sobrien
48738494Sobrien
48838494Sobriennfsreaddirres *
48938494Sobriennfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp)
49038494Sobrien{
49138494Sobrien  static nfsreaddirres res;
49238494Sobrien  static nfsentry e_res[MAX_READDIR_ENTRIES];
49338494Sobrien  am_node *mp;
49438494Sobrien  int retry;
49538494Sobrien
49638494Sobrien#ifdef DEBUG
49738494Sobrien  amuDebug(D_TRACE)
49838494Sobrien    plog(XLOG_DEBUG, "readdir:");
49938494Sobrien#endif /* DEBUG */
50038494Sobrien
50138494Sobrien  mp = fh_to_mp2(&argp->rda_fhandle, &retry);
50238494Sobrien  if (mp == 0) {
50338494Sobrien    if (retry < 0)
50438494Sobrien      return 0;
50538494Sobrien    res.rdr_status = nfs_error(retry);
50638494Sobrien  } else {
50738494Sobrien#ifdef DEBUG
50838494Sobrien    amuDebug(D_TRACE)
50938494Sobrien      plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
51038494Sobrien#endif /* DEBUG */
51138494Sobrien    res.rdr_status = nfs_error((*mp->am_mnt->mf_ops->readdir)
51238494Sobrien			   (mp, argp->rda_cookie,
51338494Sobrien			    &res.rdr_u.rdr_reply_u, e_res, argp->rda_count));
51438494Sobrien    mp->am_stats.s_readdir++;
51538494Sobrien  }
51638494Sobrien
51738494Sobrien  return &res;
51838494Sobrien}
51938494Sobrien
52038494Sobrien
52138494Sobriennfsstatfsres *
52238494Sobriennfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
52338494Sobrien{
52438494Sobrien  static nfsstatfsres res;
52538494Sobrien  am_node *mp;
52638494Sobrien  int retry;
52738494Sobrien  mntent_t mnt;
52838494Sobrien
52938494Sobrien#ifdef DEBUG
53038494Sobrien  amuDebug(D_TRACE)
53138494Sobrien    plog(XLOG_DEBUG, "statfs:");
53238494Sobrien#endif /* DEBUG */
53338494Sobrien
53438494Sobrien  mp = fh_to_mp2(argp, &retry);
53538494Sobrien  if (mp == 0) {
53638494Sobrien    if (retry < 0)
53738494Sobrien      return 0;
53838494Sobrien    res.sfr_status = nfs_error(retry);
53938494Sobrien  } else {
54038494Sobrien    nfsstatfsokres *fp;
54138494Sobrien#ifdef DEBUG
54238494Sobrien    amuDebug(D_TRACE)
54338494Sobrien      plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
54438494Sobrien#endif /* DEBUG */
54538494Sobrien
54638494Sobrien    /*
54738494Sobrien     * just return faked up file system information
54838494Sobrien     */
54938494Sobrien    fp = &res.sfr_u.sfr_reply_u;
55038494Sobrien
55138494Sobrien    fp->sfrok_tsize = 1024;
55238494Sobrien    fp->sfrok_bsize = 1024;
55338494Sobrien
55438494Sobrien    /* check if map is browsable and show_statfs_entries=yes  */
55538494Sobrien    if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) &&
55638494Sobrien	mp->am_mnt && mp->am_mnt->mf_mopts) {
55738494Sobrien      mnt.mnt_opts = mp->am_mnt->mf_mopts;
55838494Sobrien      if (hasmntopt(&mnt, "browsable")) {
55938494Sobrien	count_map_entries(mp,
56038494Sobrien			  &fp->sfrok_blocks,
56138494Sobrien			  &fp->sfrok_bfree,
56238494Sobrien			  &fp->sfrok_bavail);
56338494Sobrien      }
56438494Sobrien    } else {
56538494Sobrien      fp->sfrok_blocks = 0; /* set to 1 if you don't want empty automounts */
56638494Sobrien      fp->sfrok_bfree = 0;
56738494Sobrien      fp->sfrok_bavail = 0;
56838494Sobrien    }
56938494Sobrien
57038494Sobrien    res.sfr_status = NFS_OK;
57138494Sobrien    mp->am_stats.s_statfs++;
57238494Sobrien  }
57338494Sobrien
57438494Sobrien  return &res;
57538494Sobrien}
57638494Sobrien
57738494Sobrien
57838494Sobrien/*
57938494Sobrien * count how many total entries there are in a map, and how many
58038494Sobrien * of them are in use.
58138494Sobrien */
58238494Sobrienstatic void
58338494Sobriencount_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail)
58438494Sobrien{
58538494Sobrien  u_int blocks, bfree, bavail, i;
58638494Sobrien  mntfs *mf;
58738494Sobrien  mnt_map *mmp;
58838494Sobrien  kv *k;
58938494Sobrien
59038494Sobrien  blocks = bfree = bavail = 0;
59138494Sobrien  if (!mp)
59238494Sobrien    goto out;
59338494Sobrien  mf = mp->am_mnt;
59438494Sobrien  if (!mf)
59538494Sobrien    goto out;
59638494Sobrien  mmp = (mnt_map *) mf->mf_private;
59738494Sobrien  if (!mmp)
59838494Sobrien    goto out;
59938494Sobrien
60038494Sobrien  /* iterate over keys */
60138494Sobrien  for (i = 0; i < NKVHASH; i++) {
60238494Sobrien    for (k = mmp->kvhash[i]; k ; k = k->next) {
60338494Sobrien      if (!k->key)
60438494Sobrien	continue;
60538494Sobrien      blocks++;
60638494Sobrien      /*
60738494Sobrien       * XXX: Need to count how many are actively in use and recompute
60838494Sobrien       * bfree and bavail based on it.
60938494Sobrien       */
61038494Sobrien    }
61138494Sobrien  }
61238494Sobrien
61338494Sobrienout:
61438494Sobrien  *out_blocks = blocks;
61538494Sobrien  *out_bfree = bfree;
61638494Sobrien  *out_bavail = bavail;
61738494Sobrien}
618