138494Sobrien/*
2310490Scy * Copyright (c) 1997-2014 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.
19310490Scy * 3. Neither the name of the University nor the names of its contributors
2038494Sobrien *    may be used to endorse or promote products derived from this software
2138494Sobrien *    without specific prior written permission.
2238494Sobrien *
2338494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2438494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2538494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2638494Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2738494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2838494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2938494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3038494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3138494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3238494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3338494Sobrien * SUCH DAMAGE.
3438494Sobrien *
3538494Sobrien *
36174294Sobrien * File: am-utils/amd/nfs_subr.c
3738494Sobrien *
3838494Sobrien */
3938494Sobrien
4038494Sobrien#ifdef HAVE_CONFIG_H
4138494Sobrien# include <config.h>
4238494Sobrien#endif /* HAVE_CONFIG_H */
4338494Sobrien#include <am_defs.h>
4438494Sobrien#include <amd.h>
4538494Sobrien
4638494Sobrien/*
4738494Sobrien * Convert from UN*X to NFS error code.
4838494Sobrien * Some systems like linux define their own (see
4938494Sobrien * conf/mount/mount_linux.h).
5038494Sobrien */
5138494Sobrien#ifndef nfs_error
5238494Sobrien# define nfs_error(e) ((nfsstat)(e))
5338494Sobrien#endif /* nfs_error */
5438494Sobrien
55174294Sobrien/*
56174294Sobrien * File Handle structure
57174294Sobrien *
58174294Sobrien * This is interpreted by indexing the exported array
59174294Sobrien * by fhh_id (for old-style filehandles), or by retrieving
60174294Sobrien * the node name from fhh_path (for new-style filehandles).
61174294Sobrien *
62174294Sobrien * The whole structure is mapped onto a standard fhandle_t
63174294Sobrien * when transmitted.
64174294Sobrien */
65174294Sobrienstruct am_fh {
66174294Sobrien  u_int fhh_gen;				/* generation number */
67174294Sobrien  union {
68174294Sobrien    struct {
69174294Sobrien      int fhh_type;				/* old or new am_fh */
70174294Sobrien      pid_t fhh_pid;				/* process id */
71174294Sobrien      int fhh_id;				/* map id */
72174294Sobrien    } s;
73174294Sobrien    char fhh_path[NFS_FHSIZE-sizeof(u_int)];	/* path to am_node */
74174294Sobrien  } u;
75174294Sobrien};
76174294Sobrien
77310490Scystruct am_fh3 {
78310490Scy  u_int fhh_gen;				/* generation number */
79310490Scy  union {
80310490Scy    struct {
81310490Scy      int fhh_type;				/* old or new am_fh */
82310490Scy      pid_t fhh_pid;				/* process id */
83310490Scy      int fhh_id;				/* map id */
84310490Scy    } s;
85310490Scy    char fhh_path[AM_FHSIZE3-sizeof(u_int)];	/* path to am_node */
86310490Scy  } u;
87310490Scy};
88174294Sobrien
8938494Sobrien/* forward declarations */
90174294Sobrien/* converting am-filehandles to mount-points */
91174294Sobrienstatic am_node *fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop);
92174294Sobrienstatic am_node *fh_to_mp(am_nfs_fh *fhp);
9338494Sobrienstatic void count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail);
9438494Sobrien
9538494Sobrien
9638494Sobrienstatic char *
97174294Sobriendo_readlink(am_node *mp, int *error_return)
9838494Sobrien{
9938494Sobrien  char *ln;
10038494Sobrien
10138494Sobrien  /*
102174294Sobrien   * If there is a readlink method then use it,
103174294Sobrien   * otherwise if a link exists use that,
104174294Sobrien   * otherwise use the mount point.
10538494Sobrien   */
106310490Scy  if (mp->am_al->al_mnt->mf_ops->readlink) {
10738494Sobrien    int retry = 0;
108310490Scy    mp = (*mp->am_al->al_mnt->mf_ops->readlink) (mp, &retry);
109310490Scy    if (mp == NULL) {
11038494Sobrien      *error_return = retry;
11138494Sobrien      return 0;
11238494Sobrien    }
11338494Sobrien    /* reschedule_timeout_mp(); */
11438494Sobrien  }
11538494Sobrien
11638494Sobrien  if (mp->am_link) {
11738494Sobrien    ln = mp->am_link;
11838494Sobrien  } else {
119310490Scy    ln = mp->am_al->al_mnt->mf_mount;
12038494Sobrien  }
12138494Sobrien
12238494Sobrien  return ln;
12338494Sobrien}
12438494Sobrien
12538494Sobrien
12638494Sobrienvoidp
12738494Sobriennfsproc_null_2_svc(voidp argp, struct svc_req *rqstp)
12838494Sobrien{
12938494Sobrien  static char res;
13038494Sobrien
13138494Sobrien  return (voidp) &res;
13238494Sobrien}
13338494Sobrien
13438494Sobrien
13538494Sobriennfsattrstat *
13638494Sobriennfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
13738494Sobrien{
13838494Sobrien  static nfsattrstat res;
13938494Sobrien  am_node *mp;
140310490Scy  int retry = 0;
141174294Sobrien  time_t now = clocktime(NULL);
14238494Sobrien
143174294Sobrien  if (amuDebug(D_TRACE))
14438494Sobrien    plog(XLOG_DEBUG, "getattr:");
14538494Sobrien
146174294Sobrien  mp = fh_to_mp3(argp, &retry, VLOOK_CREATE);
147310490Scy  if (mp == NULL) {
148174294Sobrien    if (amuDebug(D_TRACE))
14938494Sobrien      plog(XLOG_DEBUG, "\tretry=%d", retry);
15038494Sobrien
15182794Sobrien    if (retry < 0) {
15282794Sobrien      amd_stats.d_drops++;
15338494Sobrien      return 0;
15482794Sobrien    }
15538494Sobrien    res.ns_status = nfs_error(retry);
156174294Sobrien    return &res;
157174294Sobrien  }
15838494Sobrien
159174294Sobrien  res = mp->am_attr;
160174294Sobrien  if (amuDebug(D_TRACE))
161174294Sobrien    plog(XLOG_DEBUG, "\tstat(%s), size = %d, mtime=%ld.%ld",
162174294Sobrien	 mp->am_path,
163174294Sobrien	 (int) res.ns_u.ns_attr_u.na_size,
164174294Sobrien	 (long) res.ns_u.ns_attr_u.na_mtime.nt_seconds,
165174294Sobrien	 (long) res.ns_u.ns_attr_u.na_mtime.nt_useconds);
16638494Sobrien
167174294Sobrien  /* Delay unmount of what was looked up */
168174294Sobrien  if (mp->am_timeo_w < 4 * gopt.am_timeo_w)
169174294Sobrien    mp->am_timeo_w += gopt.am_timeo_w;
170174294Sobrien  mp->am_ttl = now + mp->am_timeo_w;
17182794Sobrien
172174294Sobrien  mp->am_stats.s_getattr++;
17338494Sobrien  return &res;
17438494Sobrien}
17538494Sobrien
17638494Sobrien
17738494Sobriennfsattrstat *
17838494Sobriennfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp)
17938494Sobrien{
18038494Sobrien  static nfsattrstat res;
18138494Sobrien
18238494Sobrien  if (!fh_to_mp(&argp->sag_fhandle))
18338494Sobrien    res.ns_status = nfs_error(ESTALE);
18438494Sobrien  else
18538494Sobrien    res.ns_status = nfs_error(EROFS);
18638494Sobrien
18738494Sobrien  return &res;
18838494Sobrien}
18938494Sobrien
19038494Sobrien
19138494Sobrienvoidp
19238494Sobriennfsproc_root_2_svc(voidp argp, struct svc_req *rqstp)
19338494Sobrien{
19438494Sobrien  static char res;
19538494Sobrien
19638494Sobrien  return (voidp) &res;
19738494Sobrien}
19838494Sobrien
19938494Sobrien
20038494Sobriennfsdiropres *
20138494Sobriennfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
20238494Sobrien{
20338494Sobrien  static nfsdiropres res;
20438494Sobrien  am_node *mp;
20538494Sobrien  int retry;
20682794Sobrien  uid_t uid;
20782794Sobrien  gid_t gid;
20838494Sobrien
209174294Sobrien  if (amuDebug(D_TRACE))
21038494Sobrien    plog(XLOG_DEBUG, "lookup:");
21138494Sobrien
21282794Sobrien  /* finally, find the effective uid/gid from RPC request */
21382794Sobrien  if (getcreds(rqstp, &uid, &gid, nfsxprt) < 0)
21482794Sobrien    plog(XLOG_ERROR, "cannot get uid/gid from RPC credentials");
215174294Sobrien  xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) uid);
216174294Sobrien  xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) gid);
21782794Sobrien
218174294Sobrien  mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_CREATE);
219310490Scy  if (mp == NULL) {
22082794Sobrien    if (retry < 0) {
22182794Sobrien      amd_stats.d_drops++;
22238494Sobrien      return 0;
22382794Sobrien    }
22438494Sobrien    res.dr_status = nfs_error(retry);
22538494Sobrien  } else {
22638494Sobrien    int error;
22738494Sobrien    am_node *ap;
228174294Sobrien    if (amuDebug(D_TRACE))
229174294Sobrien      plog(XLOG_DEBUG, "\tlookup(%s, %s)", mp->am_path, argp->da_name);
230310490Scy    ap = mp->am_al->al_mnt->mf_ops->lookup_child(mp, argp->da_name, &error, VLOOK_CREATE);
231174294Sobrien    if (ap && error < 0)
232310490Scy      ap = mp->am_al->al_mnt->mf_ops->mount_child(ap, &error);
23338494Sobrien    if (ap == 0) {
23438494Sobrien      if (error < 0) {
23538494Sobrien	amd_stats.d_drops++;
23638494Sobrien	return 0;
23738494Sobrien      }
23838494Sobrien      res.dr_status = nfs_error(error);
23938494Sobrien    } else {
24042629Sobrien      /*
24142629Sobrien       * XXX: EXPERIMENTAL! Delay unmount of what was looked up.  This
24242629Sobrien       * should reduce the chance for race condition between unmounting an
24342629Sobrien       * entry synchronously, and re-mounting it asynchronously.
24442629Sobrien       */
24542629Sobrien      if (ap->am_ttl < mp->am_ttl)
24642629Sobrien 	ap->am_ttl = mp->am_ttl;
24738494Sobrien      mp_to_fh(ap, &res.dr_u.dr_drok_u.drok_fhandle);
24838494Sobrien      res.dr_u.dr_drok_u.drok_attributes = ap->am_fattr;
24938494Sobrien      res.dr_status = NFS_OK;
25038494Sobrien    }
25138494Sobrien    mp->am_stats.s_lookup++;
25238494Sobrien    /* reschedule_timeout_mp(); */
25338494Sobrien  }
25438494Sobrien
25538494Sobrien  return &res;
25638494Sobrien}
25738494Sobrien
25838494Sobrien
25938494Sobrienvoid
260174294Sobriennfs_quick_reply(am_node *mp, int error)
26138494Sobrien{
26238494Sobrien  SVCXPRT *transp = mp->am_transp;
26338494Sobrien  nfsdiropres res;
26438494Sobrien  xdrproc_t xdr_result = (xdrproc_t) xdr_diropres;
26538494Sobrien
26638494Sobrien  /*
26738494Sobrien   * If there's a transp structure then we can reply to the client's
26838494Sobrien   * nfs lookup request.
26938494Sobrien   */
27038494Sobrien  if (transp) {
27138494Sobrien    if (error == 0) {
27238494Sobrien      /*
27338494Sobrien       * Construct a valid reply to a lookup request.  Same
27438494Sobrien       * code as in nfsproc_lookup_2_svc() above.
27538494Sobrien       */
27638494Sobrien      mp_to_fh(mp, &res.dr_u.dr_drok_u.drok_fhandle);
27738494Sobrien      res.dr_u.dr_drok_u.drok_attributes = mp->am_fattr;
27838494Sobrien      res.dr_status = NFS_OK;
27938494Sobrien    } else
28038494Sobrien      /*
28138494Sobrien       * Return the error that was passed to us.
28238494Sobrien       */
28338494Sobrien      res.dr_status = nfs_error(error);
28438494Sobrien
28538494Sobrien    /*
28638494Sobrien     * Send off our reply
28738494Sobrien     */
28838494Sobrien    if (!svc_sendreply(transp, (XDRPROC_T_TYPE) xdr_result, (SVC_IN_ARG_TYPE) & res))
28938494Sobrien      svcerr_systemerr(transp);
29038494Sobrien
29138494Sobrien    /*
29238494Sobrien     * Free up transp.  It's only used for one reply.
29338494Sobrien     */
294174294Sobrien    XFREE(mp->am_transp);
295310490Scy    dlog("Quick reply sent for %s", mp->am_al->al_mnt->mf_mount);
29638494Sobrien  }
29738494Sobrien}
29838494Sobrien
29938494Sobrien
30038494Sobriennfsreadlinkres *
30138494Sobriennfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
30238494Sobrien{
30338494Sobrien  static nfsreadlinkres res;
30438494Sobrien  am_node *mp;
30538494Sobrien  int retry;
30638494Sobrien
307174294Sobrien  if (amuDebug(D_TRACE))
30838494Sobrien    plog(XLOG_DEBUG, "readlink:");
30938494Sobrien
310174294Sobrien  mp = fh_to_mp3(argp, &retry, VLOOK_CREATE);
311310490Scy  if (mp == NULL) {
31238494Sobrien  readlink_retry:
31382794Sobrien    if (retry < 0) {
31482794Sobrien      amd_stats.d_drops++;
31538494Sobrien      return 0;
31682794Sobrien    }
31738494Sobrien    res.rlr_status = nfs_error(retry);
31838494Sobrien  } else {
319174294Sobrien    char *ln = do_readlink(mp, &retry);
32038494Sobrien    if (ln == 0)
32138494Sobrien      goto readlink_retry;
32238494Sobrien    res.rlr_status = NFS_OK;
323174294Sobrien    if (amuDebug(D_TRACE) && ln)
324174294Sobrien      plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
32538494Sobrien    res.rlr_u.rlr_data_u = ln;
32638494Sobrien    mp->am_stats.s_readlink++;
32738494Sobrien  }
32838494Sobrien
32938494Sobrien  return &res;
33038494Sobrien}
33138494Sobrien
33238494Sobrien
33338494Sobriennfsreadres *
33438494Sobriennfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp)
33538494Sobrien{
33638494Sobrien  static nfsreadres res;
33738494Sobrien
33838494Sobrien  memset((char *) &res, 0, sizeof(res));
33938494Sobrien  res.rr_status = nfs_error(EACCES);
34038494Sobrien
34138494Sobrien  return &res;
34238494Sobrien}
34338494Sobrien
34438494Sobrien
34538494Sobrienvoidp
34638494Sobriennfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp)
34738494Sobrien{
34838494Sobrien  static char res;
34938494Sobrien
35038494Sobrien  return (voidp) &res;
35138494Sobrien}
35238494Sobrien
35338494Sobrien
35438494Sobriennfsattrstat *
35538494Sobriennfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp)
35638494Sobrien{
35738494Sobrien  static nfsattrstat res;
35838494Sobrien
35938494Sobrien  if (!fh_to_mp(&argp->wra_fhandle))
36038494Sobrien    res.ns_status = nfs_error(ESTALE);
36138494Sobrien  else
36238494Sobrien    res.ns_status = nfs_error(EROFS);
36338494Sobrien
36438494Sobrien  return &res;
36538494Sobrien}
36638494Sobrien
36738494Sobrien
36838494Sobriennfsdiropres *
36938494Sobriennfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
37038494Sobrien{
37138494Sobrien  static nfsdiropres res;
37238494Sobrien
37338494Sobrien  if (!fh_to_mp(&argp->ca_where.da_fhandle))
37438494Sobrien    res.dr_status = nfs_error(ESTALE);
37538494Sobrien  else
37638494Sobrien    res.dr_status = nfs_error(EROFS);
37738494Sobrien
37838494Sobrien  return &res;
37938494Sobrien}
38038494Sobrien
38138494Sobrien
38238494Sobrienstatic nfsstat *
38338494Sobrienunlink_or_rmdir(nfsdiropargs *argp, struct svc_req *rqstp, int unlinkp)
38438494Sobrien{
38538494Sobrien  static nfsstat res;
38638494Sobrien  int retry;
38738494Sobrien
38838494Sobrien  am_node *mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_DELETE);
389310490Scy  if (mp == NULL) {
39082794Sobrien    if (retry < 0) {
39182794Sobrien      amd_stats.d_drops++;
39238494Sobrien      return 0;
39382794Sobrien    }
39438494Sobrien    res = nfs_error(retry);
39538494Sobrien    goto out;
39638494Sobrien  }
39738494Sobrien
39838494Sobrien  if (mp->am_fattr.na_type != NFDIR) {
39938494Sobrien    res = nfs_error(ENOTDIR);
40038494Sobrien    goto out;
40138494Sobrien  }
40238494Sobrien
403174294Sobrien  if (amuDebug(D_TRACE))
40438494Sobrien    plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->da_name);
40538494Sobrien
406310490Scy  mp = mp->am_al->al_mnt->mf_ops->lookup_child(mp, argp->da_name, &retry, VLOOK_DELETE);
407310490Scy  if (mp == NULL) {
40838494Sobrien    /*
40938494Sobrien     * Ignore retries...
41038494Sobrien     */
41138494Sobrien    if (retry < 0)
41238494Sobrien      retry = 0;
41338494Sobrien    /*
41438494Sobrien     * Usual NFS workaround...
41538494Sobrien     */
41638494Sobrien    else if (retry == ENOENT)
41738494Sobrien      retry = 0;
41838494Sobrien    res = nfs_error(retry);
41938494Sobrien  } else {
42038494Sobrien    forcibly_timeout_mp(mp);
42138494Sobrien    res = NFS_OK;
42238494Sobrien  }
42338494Sobrien
42438494Sobrienout:
42538494Sobrien  return &res;
42638494Sobrien}
42738494Sobrien
42838494Sobrien
42938494Sobriennfsstat *
43038494Sobriennfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
43138494Sobrien{
43238494Sobrien  return unlink_or_rmdir(argp, rqstp, TRUE);
43338494Sobrien}
43438494Sobrien
43538494Sobrien
43638494Sobriennfsstat *
43738494Sobriennfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp)
43838494Sobrien{
43938494Sobrien  static nfsstat res;
44038494Sobrien
44138494Sobrien  if (!fh_to_mp(&argp->rna_from.da_fhandle) || !fh_to_mp(&argp->rna_to.da_fhandle))
44238494Sobrien    res = nfs_error(ESTALE);
44338494Sobrien  /*
44438494Sobrien   * If the kernel is doing clever things with referenced files
44538494Sobrien   * then let it pretend...
44638494Sobrien   */
44738494Sobrien  else if (NSTREQ(argp->rna_to.da_name, ".nfs", 4))
44838494Sobrien    res = NFS_OK;
44938494Sobrien  /*
45038494Sobrien   * otherwise a failure
45138494Sobrien   */
45238494Sobrien  else
45338494Sobrien    res = nfs_error(EROFS);
45438494Sobrien
45538494Sobrien  return &res;
45638494Sobrien}
45738494Sobrien
45838494Sobrien
45938494Sobriennfsstat *
46038494Sobriennfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp)
46138494Sobrien{
46238494Sobrien  static nfsstat res;
46338494Sobrien
46438494Sobrien  if (!fh_to_mp(&argp->la_fhandle) || !fh_to_mp(&argp->la_to.da_fhandle))
46538494Sobrien    res = nfs_error(ESTALE);
46638494Sobrien  else
46738494Sobrien    res = nfs_error(EROFS);
46838494Sobrien
46938494Sobrien  return &res;
47038494Sobrien}
47138494Sobrien
47238494Sobrien
47338494Sobriennfsstat *
47438494Sobriennfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp)
47538494Sobrien{
47638494Sobrien  static nfsstat res;
47738494Sobrien
47838494Sobrien  if (!fh_to_mp(&argp->sla_from.da_fhandle))
47938494Sobrien    res = nfs_error(ESTALE);
48038494Sobrien  else
48138494Sobrien    res = nfs_error(EROFS);
48238494Sobrien
48338494Sobrien  return &res;
48438494Sobrien}
48538494Sobrien
48638494Sobrien
48738494Sobriennfsdiropres *
48838494Sobriennfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
48938494Sobrien{
49038494Sobrien  static nfsdiropres res;
49138494Sobrien
49238494Sobrien  if (!fh_to_mp(&argp->ca_where.da_fhandle))
49338494Sobrien    res.dr_status = nfs_error(ESTALE);
49438494Sobrien  else
49538494Sobrien    res.dr_status = nfs_error(EROFS);
49638494Sobrien
49738494Sobrien  return &res;
49838494Sobrien}
49938494Sobrien
50038494Sobrien
50138494Sobriennfsstat *
50238494Sobriennfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
50338494Sobrien{
50438494Sobrien  return unlink_or_rmdir(argp, rqstp, FALSE);
50538494Sobrien}
50638494Sobrien
50738494Sobrien
50838494Sobriennfsreaddirres *
50938494Sobriennfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp)
51038494Sobrien{
51138494Sobrien  static nfsreaddirres res;
51238494Sobrien  static nfsentry e_res[MAX_READDIR_ENTRIES];
51338494Sobrien  am_node *mp;
51438494Sobrien  int retry;
51538494Sobrien
516174294Sobrien  if (amuDebug(D_TRACE))
51738494Sobrien    plog(XLOG_DEBUG, "readdir:");
51838494Sobrien
519174294Sobrien  mp = fh_to_mp3(&argp->rda_fhandle, &retry, VLOOK_CREATE);
520310490Scy  if (mp == NULL) {
52182794Sobrien    if (retry < 0) {
52282794Sobrien      amd_stats.d_drops++;
52338494Sobrien      return 0;
52482794Sobrien    }
52538494Sobrien    res.rdr_status = nfs_error(retry);
52638494Sobrien  } else {
527174294Sobrien    if (amuDebug(D_TRACE))
52838494Sobrien      plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
529310490Scy    res.rdr_status = nfs_error((*mp->am_al->al_mnt->mf_ops->readdir)
53038494Sobrien			   (mp, argp->rda_cookie,
53138494Sobrien			    &res.rdr_u.rdr_reply_u, e_res, argp->rda_count));
53238494Sobrien    mp->am_stats.s_readdir++;
53338494Sobrien  }
53438494Sobrien
53538494Sobrien  return &res;
53638494Sobrien}
53738494Sobrien
53838494Sobrien
53938494Sobriennfsstatfsres *
54038494Sobriennfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
54138494Sobrien{
54238494Sobrien  static nfsstatfsres res;
54338494Sobrien  am_node *mp;
54438494Sobrien  int retry;
54538494Sobrien  mntent_t mnt;
54638494Sobrien
547174294Sobrien  if (amuDebug(D_TRACE))
54838494Sobrien    plog(XLOG_DEBUG, "statfs:");
54938494Sobrien
550174294Sobrien  mp = fh_to_mp3(argp, &retry, VLOOK_CREATE);
551310490Scy  if (mp == NULL) {
55282794Sobrien    if (retry < 0) {
55382794Sobrien      amd_stats.d_drops++;
55438494Sobrien      return 0;
55582794Sobrien    }
55638494Sobrien    res.sfr_status = nfs_error(retry);
55738494Sobrien  } else {
55838494Sobrien    nfsstatfsokres *fp;
559174294Sobrien    if (amuDebug(D_TRACE))
56038494Sobrien      plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
56138494Sobrien
56238494Sobrien    /*
56338494Sobrien     * just return faked up file system information
56438494Sobrien     */
56538494Sobrien    fp = &res.sfr_u.sfr_reply_u;
56638494Sobrien
56738494Sobrien    fp->sfrok_tsize = 1024;
56838494Sobrien    fp->sfrok_bsize = 1024;
56938494Sobrien
57038494Sobrien    /* check if map is browsable and show_statfs_entries=yes  */
57138494Sobrien    if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) &&
572310490Scy	mp->am_al->al_mnt && mp->am_al->al_mnt->mf_mopts) {
573310490Scy      mnt.mnt_opts = mp->am_al->al_mnt->mf_mopts;
574174294Sobrien      if (amu_hasmntopt(&mnt, "browsable")) {
57538494Sobrien	count_map_entries(mp,
57638494Sobrien			  &fp->sfrok_blocks,
57738494Sobrien			  &fp->sfrok_bfree,
57838494Sobrien			  &fp->sfrok_bavail);
57938494Sobrien      }
58038494Sobrien    } else {
58138494Sobrien      fp->sfrok_blocks = 0; /* set to 1 if you don't want empty automounts */
58238494Sobrien      fp->sfrok_bfree = 0;
58338494Sobrien      fp->sfrok_bavail = 0;
58438494Sobrien    }
58538494Sobrien
58638494Sobrien    res.sfr_status = NFS_OK;
58738494Sobrien    mp->am_stats.s_statfs++;
58838494Sobrien  }
58938494Sobrien
59038494Sobrien  return &res;
59138494Sobrien}
59238494Sobrien
59338494Sobrien
59438494Sobrien/*
59538494Sobrien * count how many total entries there are in a map, and how many
59638494Sobrien * of them are in use.
59738494Sobrien */
59838494Sobrienstatic void
59938494Sobriencount_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail)
60038494Sobrien{
60138494Sobrien  u_int blocks, bfree, bavail, i;
60238494Sobrien  mntfs *mf;
60338494Sobrien  mnt_map *mmp;
60438494Sobrien  kv *k;
60538494Sobrien
60638494Sobrien  blocks = bfree = bavail = 0;
60738494Sobrien  if (!mp)
60838494Sobrien    goto out;
609310490Scy  mf = mp->am_al->al_mnt;
61038494Sobrien  if (!mf)
61138494Sobrien    goto out;
61238494Sobrien  mmp = (mnt_map *) mf->mf_private;
61338494Sobrien  if (!mmp)
61438494Sobrien    goto out;
61538494Sobrien
61638494Sobrien  /* iterate over keys */
61738494Sobrien  for (i = 0; i < NKVHASH; i++) {
61838494Sobrien    for (k = mmp->kvhash[i]; k ; k = k->next) {
61938494Sobrien      if (!k->key)
62038494Sobrien	continue;
62138494Sobrien      blocks++;
62238494Sobrien      /*
62338494Sobrien       * XXX: Need to count how many are actively in use and recompute
62438494Sobrien       * bfree and bavail based on it.
62538494Sobrien       */
62638494Sobrien    }
62738494Sobrien  }
62838494Sobrien
62938494Sobrienout:
63038494Sobrien  *out_blocks = blocks;
63138494Sobrien  *out_bfree = bfree;
63238494Sobrien  *out_bavail = bavail;
63338494Sobrien}
634174294Sobrien
635174294Sobrienstatic am_node *
636310490Scyvalidate_ap(am_node *node, int *rp, u_int fhh_gen)
637174294Sobrien{
638310490Scy  am_node *ap = node;
639174294Sobrien  /*
640174294Sobrien   * Check the generation number in the node
641174294Sobrien   * matches the one from the kernel.  If not
642174294Sobrien   * then the old node has been timed out and
643174294Sobrien   * a new one allocated.
644174294Sobrien   */
645310490Scy  if (node != NULL && node->am_gen != fhh_gen)
646310490Scy    ap = NULL;
647174294Sobrien
648174294Sobrien  /*
649174294Sobrien   * If it doesn't exists then drop the request
650174294Sobrien   */
651174294Sobrien  if (!ap)
652174294Sobrien    goto drop;
653174294Sobrien
654174294Sobrien#if 0
655174294Sobrien  /*
656174294Sobrien   * If the node is hung then locate a new node
657174294Sobrien   * for it.  This implements the replicated filesystem
658174294Sobrien   * retries.
659174294Sobrien   */
660310490Scy  if (ap->am_al->al_mnt && FSRV_ISDOWN(ap->am_al->al_mnt->mf_server) && ap->am_parent) {
661174294Sobrien    int error;
662174294Sobrien    am_node *orig_ap = ap;
663174294Sobrien
664310490Scy    dlog("%s: %s (%s) is hung: lookup alternative file server", __func__,
665310490Scy	 orig_ap->am_path, orig_ap->am_al->al_mnt->mf_info);
666174294Sobrien
667174294Sobrien    /*
668174294Sobrien     * Update modify time of parent node.
669174294Sobrien     * With any luck the kernel will re-stat
670174294Sobrien     * the child node and get new information.
671174294Sobrien     */
672174294Sobrien    clocktime(&orig_ap->am_fattr.na_mtime);
673174294Sobrien
674174294Sobrien    /*
675174294Sobrien     * Call the parent's lookup routine for an object
676174294Sobrien     * with the same name.  This may return -1 in error
677174294Sobrien     * if a mount is in progress.  In any case, if no
678174294Sobrien     * mount node is returned the error code is propagated
679174294Sobrien     * to the caller.
680174294Sobrien     */
681174294Sobrien    if (vop == VLOOK_CREATE) {
682310490Scy      ap = orig_ap->am_parent->am_al->al_mnt->mf_ops->lookup_child(orig_ap->am_parent, orig_ap->am_name, &error, vop);
683174294Sobrien      if (ap && error < 0)
684310490Scy	ap = orig_ap->am_parent->am_al->al_mnt->mf_ops->mount_child(ap, &error);
685174294Sobrien    } else {
686310490Scy      ap = NULL;
687174294Sobrien      error = ESTALE;
688174294Sobrien    }
689174294Sobrien    if (ap == 0) {
690174294Sobrien      if (error < 0 && amd_state == Finishing)
691174294Sobrien	error = ENOENT;
692174294Sobrien      *rp = error;
693174294Sobrien      return 0;
694174294Sobrien    }
695174294Sobrien
696174294Sobrien    /*
697174294Sobrien     * Update last access to original node.  This
698174294Sobrien     * avoids timing it out and so sending ESTALE
699174294Sobrien     * back to the kernel.
700174294Sobrien     * XXX - Not sure we need this anymore (jsp, 90/10/6).
701174294Sobrien     */
702174294Sobrien    new_ttl(orig_ap);
703174294Sobrien
704174294Sobrien  }
705310490Scy#endif /* 0 */
706174294Sobrien
707174294Sobrien  /*
708174294Sobrien   * Disallow references to objects being unmounted, unless
709174294Sobrien   * they are automount points.
710174294Sobrien   */
711310490Scy  if (ap->am_al->al_mnt && (ap->am_al->al_mnt->mf_flags & MFF_UNMOUNTING) &&
712174294Sobrien      !(ap->am_flags & AMF_ROOT)) {
713174294Sobrien    if (amd_state == Finishing)
714174294Sobrien      *rp = ENOENT;
715174294Sobrien    else
716174294Sobrien      *rp = -1;
717174294Sobrien    return 0;
718174294Sobrien  }
719174294Sobrien  new_ttl(ap);
720174294Sobrien
721174294Sobriendrop:
722310490Scy  if (!ap || !ap->am_al->al_mnt) {
723174294Sobrien    /*
724174294Sobrien     * If we are shutting down then it is likely
725174294Sobrien     * that this node has disappeared because of
726174294Sobrien     * a fast timeout.  To avoid things thrashing
727174294Sobrien     * just pretend it doesn't exist at all.  If
728174294Sobrien     * ESTALE is returned, some NFS clients just
729174294Sobrien     * keep retrying (stupid or what - if it's
730174294Sobrien     * stale now, what's it going to be in 5 minutes?)
731174294Sobrien     */
732174294Sobrien    if (amd_state == Finishing)
733174294Sobrien      *rp = ENOENT;
734310490Scy    else {
735174294Sobrien      *rp = ESTALE;
736310490Scy      amd_stats.d_stale++;
737310490Scy    }
738174294Sobrien  }
739174294Sobrien
740174294Sobrien  return ap;
741174294Sobrien}
742174294Sobrien
743310490Scy/*
744310490Scy * Convert from file handle to automount node.
745310490Scy */
746310490Scystatic am_node *
747310490Scyfh_to_mp3(am_nfs_fh *fhp, int *rp, int vop)
748310490Scy{
749310490Scy  struct am_fh *fp = (struct am_fh *) fhp;
750310490Scy  am_node *ap = NULL;
751174294Sobrien
752310490Scy  if (fp->u.s.fhh_type != 0) {
753310490Scy    /* New filehandle type */
754310490Scy    int len = sizeof(*fhp) - sizeof(fp->fhh_gen);
755310490Scy    char *path = xmalloc(len+1);
756310490Scy    /*
757310490Scy     * Because fhp is treated as a filehandle we use memcpy
758310490Scy     * instead of xstrlcpy.
759310490Scy     */
760310490Scy    memcpy(path, (char *) fp->u.fhh_path, len);
761310490Scy    path[len] = '\0';
762310490Scy    dlog("%s: new filehandle: %s", __func__, path);
763310490Scy
764310490Scy    ap = path_to_exported_ap(path);
765310490Scy    XFREE(path);
766310490Scy  } else {
767310490Scy    dlog("%s: old filehandle: %d", __func__, fp->u.s.fhh_id);
768310490Scy    /*
769310490Scy     * Check process id matches
770310490Scy     * If it doesn't then it is probably
771310490Scy     * from an old kernel-cached filehandle
772310490Scy     * which is now out of date.
773310490Scy     */
774310490Scy    if (fp->u.s.fhh_pid != get_server_pid()) {
775310490Scy      dlog("%s: wrong pid %ld != my pid %ld", __func__,
776310490Scy	   (long) fp->u.s.fhh_pid, get_server_pid());
777310490Scy      goto done;
778310490Scy    }
779310490Scy
780310490Scy    /*
781310490Scy     * Get hold of the supposed mount node
782310490Scy     */
783310490Scy    ap = get_exported_ap(fp->u.s.fhh_id);
784310490Scy  }
785310490Scydone:
786310490Scy  return validate_ap(ap, rp, fp->fhh_gen);
787310490Scy}
788310490Scy
789174294Sobrienstatic am_node *
790174294Sobrienfh_to_mp(am_nfs_fh *fhp)
791174294Sobrien{
792174294Sobrien  int dummy;
793174294Sobrien
794174294Sobrien  return fh_to_mp3(fhp, &dummy, VLOOK_CREATE);
795174294Sobrien}
796174294Sobrien
797310490Scystatic am_node *
798310490Scyfh3_to_mp3(am_nfs_fh3 *fhp, int *rp, int vop)
799310490Scy{
800310490Scy  struct am_fh3 *fp = (struct am_fh3 *) fhp->am_fh3_data;
801310490Scy  am_node *ap = NULL;
802174294Sobrien
803310490Scy  if (fp->u.s.fhh_type != 0) {
804310490Scy    /* New filehandle type */
805310490Scy    int len = sizeof(*fp) - sizeof(fp->fhh_gen);
806310490Scy    char *path = xmalloc(len+1);
807310490Scy    /*
808310490Scy     * Because fhp is treated as a filehandle we use memcpy
809310490Scy     * instead of xstrlcpy.
810310490Scy     */
811310490Scy    memcpy(path, (char *) fp->u.fhh_path, len);
812310490Scy    path[len] = '\0';
813310490Scy    dlog("%s: new filehandle: %s", __func__, path);
814310490Scy
815310490Scy    ap = path_to_exported_ap(path);
816310490Scy    XFREE(path);
817310490Scy  } else {
818310490Scy    dlog("%s: old filehandle: %d", __func__, fp->u.s.fhh_id);
819310490Scy    /*
820310490Scy     * Check process id matches
821310490Scy     * If it doesn't then it is probably
822310490Scy     * from an old kernel-cached filehandle
823310490Scy     * which is now out of date.
824310490Scy     */
825310490Scy    if (fp->u.s.fhh_pid != get_server_pid()) {
826310490Scy      dlog("%s: wrong pid %ld != my pid %ld", __func__,
827310490Scy	   (long) fp->u.s.fhh_pid, get_server_pid());
828310490Scy      goto done;
829310490Scy    }
830310490Scy
831310490Scy    /*
832310490Scy     * Get hold of the supposed mount node
833310490Scy     */
834310490Scy    ap = get_exported_ap(fp->u.s.fhh_id);
835310490Scy  }
836310490Scydone:
837310490Scy  return validate_ap(ap, rp, fp->fhh_gen);
838310490Scy}
839310490Scy
840310490Scystatic am_node *
841310490Scyfh3_to_mp(am_nfs_fh3 *fhp)
842310490Scy{
843310490Scy  int dummy;
844310490Scy
845310490Scy  return fh3_to_mp3(fhp, &dummy, VLOOK_CREATE);
846310490Scy}
847310490Scy
848174294Sobrien/*
849174294Sobrien * Convert from automount node to file handle.
850174294Sobrien */
851174294Sobrienvoid
852174294Sobrienmp_to_fh(am_node *mp, am_nfs_fh *fhp)
853174294Sobrien{
854174294Sobrien  u_int pathlen;
855174294Sobrien  struct am_fh *fp = (struct am_fh *) fhp;
856174294Sobrien
857174294Sobrien  memset((char *) fhp, 0, sizeof(am_nfs_fh));
858174294Sobrien
859174294Sobrien  /* Store the generation number */
860174294Sobrien  fp->fhh_gen = mp->am_gen;
861174294Sobrien
862174294Sobrien  pathlen = strlen(mp->am_path);
863174294Sobrien  if (pathlen <= sizeof(*fhp) - sizeof(fp->fhh_gen)) {
864174294Sobrien    /* dlog("mp_to_fh: new filehandle: %s", mp->am_path); */
865174294Sobrien
866174294Sobrien    /*
867174294Sobrien     * Because fhp is treated as a filehandle we use memcpy instead of
868174294Sobrien     * xstrlcpy.
869174294Sobrien     */
870174294Sobrien    memcpy(fp->u.fhh_path, mp->am_path, pathlen); /* making a filehandle */
871174294Sobrien  } else {
872174294Sobrien    /*
873174294Sobrien     * Take the process id
874174294Sobrien     */
875174294Sobrien    fp->u.s.fhh_pid = get_server_pid();
876174294Sobrien
877174294Sobrien    /*
878174294Sobrien     * ... the map number
879174294Sobrien     */
880174294Sobrien    fp->u.s.fhh_id = mp->am_mapno;
881174294Sobrien
882174294Sobrien    /*
883174294Sobrien     * ... and the generation number (previously stored)
884174294Sobrien     * to make a "unique" triple that will never
885174294Sobrien     * be reallocated except across reboots (which doesn't matter)
886174294Sobrien     * or if we are unlucky enough to be given the same
887174294Sobrien     * pid as a previous amd (very unlikely).
888174294Sobrien     */
889174294Sobrien    /* dlog("mp_to_fh: old filehandle: %d", fp->u.s.fhh_id); */
890174294Sobrien  }
891174294Sobrien}
892310490Scyvoid
893310490Scymp_to_fh3(am_node *mp, am_nfs_fh3 *fhp)
894310490Scy{
895310490Scy  u_int pathlen;
896310490Scy  struct am_fh3 *fp = (struct am_fh3 *) fhp->am_fh3_data;
897310490Scy
898310490Scy  memset((char *) fhp, 0, sizeof(am_nfs_fh3));
899310490Scy  fhp->am_fh3_length = AM_FHSIZE3;
900310490Scy
901310490Scy  /* Store the generation number */
902310490Scy  fp->fhh_gen = mp->am_gen;
903310490Scy
904310490Scy  pathlen = strlen(mp->am_path);
905310490Scy  if (pathlen <= sizeof(*fp) - sizeof(fp->fhh_gen)) {
906310490Scy    /* dlog("mp_to_fh: new filehandle: %s", mp->am_path); */
907310490Scy
908310490Scy    /*
909310490Scy     * Because fhp is treated as a filehandle we use memcpy instead of
910310490Scy     * xstrlcpy.
911310490Scy     */
912310490Scy    memcpy(fp->u.fhh_path, mp->am_path, pathlen); /* making a filehandle */
913310490Scy  } else {
914310490Scy    /*
915310490Scy     * Take the process id
916310490Scy     */
917310490Scy    fp->u.s.fhh_pid = get_server_pid();
918310490Scy
919310490Scy    /*
920310490Scy     * ... the map number
921310490Scy     */
922310490Scy    fp->u.s.fhh_id = mp->am_mapno;
923310490Scy
924310490Scy    /*
925310490Scy     * ... and the generation number (previously stored)
926310490Scy     * to make a "unique" triple that will never
927310490Scy     * be reallocated except across reboots (which doesn't matter)
928310490Scy     * or if we are unlucky enough to be given the same
929310490Scy     * pid as a previous amd (very unlikely).
930310490Scy     */
931310490Scy    /* dlog("mp_to_fh: old filehandle: %d", fp->u.s.fhh_id); */
932310490Scy  }
933310490Scy}
934310490Scy
935310490Scy#ifdef HAVE_FS_NFS3
936310490Scystatic am_ftype3 ftype_to_ftype3(nfsftype ftype)
937310490Scy{
938310490Scy  if (ftype == NFFIFO)
939310490Scy    return AM_NF3FIFO;
940310490Scy  else
941310490Scy    return ftype;
942310490Scy}
943310490Scy
944310490Scystatic void nfstime_to_am_nfstime3(nfstime *time, am_nfstime3 *time3)
945310490Scy{
946310490Scy  time3->seconds = time->seconds;
947310490Scy  time3->nseconds = time->useconds * 1000;
948310490Scy}
949310490Scy
950310490Scystatic void rdev_to_am_specdata3(u_int rdev, am_specdata3 *rdev3)
951310490Scy{
952310490Scy  /* No device node here */
953310490Scy  rdev3->specdata1 = (u_int) -1;
954310490Scy  rdev3->specdata2 = (u_int) -1;
955310490Scy}
956310490Scy
957310490Scystatic void fattr_to_fattr3(nfsfattr *fattr, am_fattr3 *fattr3)
958310490Scy{
959310490Scy  fattr3->type = ftype_to_ftype3(fattr->na_type);
960310490Scy  fattr3->mode = (am_mode3) fattr->na_mode;
961310490Scy  fattr3->nlink = fattr->na_nlink;
962310490Scy  fattr3->uid = (am_uid3) fattr->na_uid;
963310490Scy  fattr3->gid = (am_uid3) fattr->na_gid;
964310490Scy  fattr3->size = (am_size3) fattr->na_size;
965310490Scy  fattr3->used = (am_size3) fattr->na_size;
966310490Scy  rdev_to_am_specdata3(fattr->na_rdev, &fattr3->rdev);
967310490Scy  fattr3->fsid = (uint64) fattr->na_fsid;
968310490Scy  fattr3->fileid = (uint64) fattr->na_fileid;
969310490Scy  nfstime_to_am_nfstime3(&fattr->na_atime, &fattr3->atime);
970310490Scy  nfstime_to_am_nfstime3(&fattr->na_mtime, &fattr3->mtime);
971310490Scy  nfstime_to_am_nfstime3(&fattr->na_ctime, &fattr3->ctime);
972310490Scy}
973310490Scy
974310490Scystatic void fattr_to_wcc_attr(nfsfattr *fattr, am_wcc_attr *wcc_attr)
975310490Scy{
976310490Scy  wcc_attr->size = (am_size3) fattr->na_size;
977310490Scy  nfstime_to_am_nfstime3(&fattr->na_mtime, &wcc_attr->mtime);
978310490Scy  nfstime_to_am_nfstime3(&fattr->na_ctime, &wcc_attr->ctime);
979310490Scy}
980310490Scy
981310490Scystatic am_nfsstat3 return_estale_or_rofs(am_nfs_fh3 *fh,
982310490Scy                                         am_pre_op_attr *pre_op,
983310490Scy                                         am_post_op_attr *post_op)
984310490Scy{
985310490Scy  am_node *mp;
986310490Scy
987310490Scy  mp = fh3_to_mp(fh);
988310490Scy  if (!mp) {
989310490Scy    pre_op->attributes_follow = 0;
990310490Scy    post_op->attributes_follow = 0;
991310490Scy    return  nfs_error(ESTALE);
992310490Scy  } else {
993310490Scy    am_fattr3 *fattr3 = &post_op->am_post_op_attr_u.attributes;
994310490Scy    am_wcc_attr *wcc_attr = &pre_op->am_pre_op_attr_u.attributes;
995310490Scy    nfsfattr *fattr = &mp->am_fattr;
996310490Scy    pre_op->attributes_follow = 1;
997310490Scy    fattr_to_wcc_attr(fattr, wcc_attr);
998310490Scy    post_op->attributes_follow = 1;
999310490Scy    fattr_to_fattr3(fattr, fattr3);
1000310490Scy    return nfs_error(EROFS);
1001310490Scy  }
1002310490Scy}
1003310490Scy
1004310490Scystatic am_nfsstat3 unlink3_or_rmdir3(am_diropargs3 *argp,
1005310490Scy                                     am_wcc_data *wcc_data, int unlinkp)
1006310490Scy{
1007310490Scy  static am_nfsstat3 res;
1008310490Scy  am_nfs_fh3 *dir = &argp->dir;
1009310490Scy  am_filename3 name = argp->name;
1010310490Scy  am_pre_op_attr *pre_op_dir = &wcc_data->before;
1011310490Scy  am_post_op_attr *post_op_dir = &wcc_data->after;
1012310490Scy  nfsfattr *fattr;
1013310490Scy  am_wcc_attr *wcc_attr;
1014310490Scy  am_node *mp, *ap;
1015310490Scy  int retry;
1016310490Scy
1017310490Scy  post_op_dir->attributes_follow = 0;
1018310490Scy
1019310490Scy  mp = fh3_to_mp3(dir, &retry, VLOOK_DELETE);
1020310490Scy  if (!mp) {
1021310490Scy    pre_op_dir->attributes_follow = 0;
1022310490Scy    if (retry < 0) {
1023310490Scy      amd_stats.d_drops++;
1024310490Scy      return 0;
1025310490Scy    }
1026310490Scy    res = nfs_error(retry);
1027310490Scy    goto out;
1028310490Scy  }
1029310490Scy
1030310490Scy  pre_op_dir->attributes_follow = 1;
1031310490Scy  fattr = &mp->am_fattr;
1032310490Scy  wcc_attr = &pre_op_dir->am_pre_op_attr_u.attributes;
1033310490Scy  fattr_to_wcc_attr(fattr, wcc_attr);
1034310490Scy
1035310490Scy  if (mp->am_fattr.na_type != NFDIR) {
1036310490Scy    res = nfs_error(ENOTDIR);
1037310490Scy    goto out;
1038310490Scy  }
1039310490Scy
1040310490Scy  if (amuDebug(D_TRACE))
1041310490Scy    plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, name);
1042310490Scy
1043310490Scy  ap = mp->am_al->al_mnt->mf_ops->lookup_child(mp, name, &retry, VLOOK_DELETE);
1044310490Scy  if (!ap) {
1045310490Scy    /*
1046310490Scy     * Ignore retries...
1047310490Scy     */
1048310490Scy    if (retry < 0)
1049310490Scy      retry = 0;
1050310490Scy    /*
1051310490Scy     * Usual NFS workaround...
1052310490Scy     */
1053310490Scy    else if (retry == ENOENT)
1054310490Scy      retry = 0;
1055310490Scy    res = nfs_error(retry);
1056310490Scy  } else {
1057310490Scy    forcibly_timeout_mp(mp);
1058310490Scy    res = AM_NFS3_OK;
1059310490Scy  }
1060310490Scy
1061310490Scyout:
1062310490Scy  return res;
1063310490Scy}
1064310490Scy
1065310490Scyvoidp
1066310490Scyam_nfs3_null_3_svc(voidp argp, struct svc_req *rqstp)
1067310490Scy{
1068310490Scy  static char * result;
1069310490Scy
1070310490Scy  return (voidp) &result;
1071310490Scy}
1072310490Scy
1073310490Scyam_GETATTR3res *
1074310490Scyam_nfs3_getattr_3_svc(am_GETATTR3args *argp, struct svc_req *rqstp)
1075310490Scy{
1076310490Scy  static am_GETATTR3res  result;
1077310490Scy  am_nfs_fh3 *fh = (am_nfs_fh3 *) &argp->object;
1078310490Scy  am_fattr3 *fattr3;
1079310490Scy  nfsfattr *fattr;
1080310490Scy  am_node *mp;
1081310490Scy  int retry = 0;
1082310490Scy  time_t now = clocktime(NULL);
1083310490Scy
1084310490Scy  if (amuDebug(D_TRACE))
1085310490Scy    plog(XLOG_DEBUG, "getattr_3:");
1086310490Scy
1087310490Scy  mp = fh3_to_mp3(fh, &retry, VLOOK_CREATE);
1088310490Scy  if (!mp) {
1089310490Scy    if (amuDebug(D_TRACE))
1090310490Scy      plog(XLOG_DEBUG, "\tretry=%d", retry);
1091310490Scy
1092310490Scy    if (retry < 0) {
1093310490Scy      amd_stats.d_drops++;
1094310490Scy      return 0;
1095310490Scy    }
1096310490Scy    result.status = nfs_error(retry);
1097310490Scy    return &result;
1098310490Scy  }
1099310490Scy
1100310490Scy  fattr = &mp->am_fattr;
1101310490Scy  fattr3 = (am_fattr3 *) &result.res_u.ok.obj_attributes;
1102310490Scy  fattr_to_fattr3(fattr, fattr3);
1103310490Scy
1104310490Scy  result.status = AM_NFS3_OK;
1105310490Scy
1106310490Scy  if (amuDebug(D_TRACE))
1107310490Scy    plog(XLOG_DEBUG, "\tstat(%s), size = %lu, mtime=%d.%d",
1108310490Scy	 mp->am_path,
1109310490Scy	 (u_long) fattr3->size,
1110310490Scy	 (u_int) fattr3->mtime.seconds,
1111310490Scy	 (u_int) fattr3->mtime.nseconds);
1112310490Scy
1113310490Scy  /* Delay unmount of what was looked up */
1114310490Scy  if (mp->am_timeo_w < 4 * gopt.am_timeo_w)
1115310490Scy    mp->am_timeo_w += gopt.am_timeo_w;
1116310490Scy  mp->am_ttl = now + mp->am_timeo_w;
1117310490Scy
1118310490Scy  mp->am_stats.s_getattr++;
1119310490Scy
1120310490Scy  return &result;
1121310490Scy}
1122310490Scy
1123310490Scyam_SETATTR3res *
1124310490Scyam_nfs3_setattr_3_svc(am_SETATTR3args *argp, struct svc_req *rqstp)
1125310490Scy{
1126310490Scy  static am_SETATTR3res  result;
1127310490Scy  am_nfs_fh3 *fh = (am_nfs_fh3 *) &argp->object;
1128310490Scy  am_pre_op_attr *pre_op_obj = &result.res_u.fail.obj_wcc.before;
1129310490Scy  am_post_op_attr *post_op_obj = &result.res_u.fail.obj_wcc.after;
1130310490Scy
1131310490Scy  if (amuDebug(D_TRACE))
1132310490Scy    plog(XLOG_DEBUG, "setattr_3:");
1133310490Scy
1134310490Scy  result.status = return_estale_or_rofs(fh, pre_op_obj, post_op_obj);
1135310490Scy
1136310490Scy  return &result;
1137310490Scy}
1138310490Scy
1139310490Scyam_LOOKUP3res *
1140310490Scyam_nfs3_lookup_3_svc(am_LOOKUP3args *argp, struct svc_req *rqstp)
1141310490Scy{
1142310490Scy  static am_LOOKUP3res  result;
1143310490Scy  am_nfs_fh3 *dir = &argp->what.dir;
1144310490Scy  am_post_op_attr *post_op_dir;
1145310490Scy  am_post_op_attr *post_op_obj;
1146310490Scy  am_node *mp;
1147310490Scy  int retry;
1148310490Scy  uid_t uid;
1149310490Scy  gid_t gid;
1150310490Scy
1151310490Scy  if (amuDebug(D_TRACE))
1152310490Scy    plog(XLOG_DEBUG, "lookup_3:");
1153310490Scy
1154310490Scy  /* finally, find the effective uid/gid from RPC request */
1155310490Scy  if (getcreds(rqstp, &uid, &gid, nfsxprt) < 0)
1156310490Scy    plog(XLOG_ERROR, "cannot get uid/gid from RPC credentials");
1157310490Scy  xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) uid);
1158310490Scy  xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) gid);
1159310490Scy
1160310490Scy  mp = fh3_to_mp3(dir, &retry, VLOOK_CREATE);
1161310490Scy  if (!mp) {
1162310490Scy    post_op_dir = &result.res_u.fail.dir_attributes;
1163310490Scy    post_op_dir->attributes_follow = 0;
1164310490Scy    if (retry < 0) {
1165310490Scy      amd_stats.d_drops++;
1166310490Scy      return 0;
1167310490Scy    }
1168310490Scy    result.status = nfs_error(retry);
1169310490Scy  } else {
1170310490Scy    post_op_dir = &result.res_u.ok.dir_attributes;
1171310490Scy    post_op_obj = &result.res_u.ok.obj_attributes;
1172310490Scy    am_filename3 name;
1173310490Scy    am_fattr3 *fattr3;
1174310490Scy    nfsfattr *fattr;
1175310490Scy    am_node *ap;
1176310490Scy    int error;
1177310490Scy
1178310490Scy    /* dir attributes */
1179310490Scy    post_op_dir->attributes_follow = 1;
1180310490Scy    fattr = &mp->am_fattr;
1181310490Scy    fattr3 = &post_op_dir->am_post_op_attr_u.attributes;
1182310490Scy    fattr_to_fattr3(fattr, fattr3);
1183310490Scy
1184310490Scy    post_op_obj->attributes_follow = 0;
1185310490Scy
1186310490Scy    name = argp->what.name;
1187310490Scy
1188310490Scy    if (amuDebug(D_TRACE))
1189310490Scy      plog(XLOG_DEBUG, "\tlookup_3(%s, %s)", mp->am_path, name);
1190310490Scy
1191310490Scy    ap = mp->am_al->al_mnt->mf_ops->lookup_child(mp, name, &error, VLOOK_CREATE);
1192310490Scy    if (ap && error < 0)
1193310490Scy      ap = mp->am_al->al_mnt->mf_ops->mount_child(ap, &error);
1194310490Scy    if (ap == 0) {
1195310490Scy      if (error < 0) {
1196310490Scy	amd_stats.d_drops++;
1197310490Scy	return 0;
1198310490Scy      }
1199310490Scy      result.status = nfs_error(error);
1200310490Scy    } else {
1201310490Scy      /*
1202310490Scy       * XXX: EXPERIMENTAL! Delay unmount of what was looked up.  This
1203310490Scy       * should reduce the chance for race condition between unmounting an
1204310490Scy       * entry synchronously, and re-mounting it asynchronously.
1205310490Scy       */
1206310490Scy      if (ap->am_ttl < mp->am_ttl)
1207310490Scy        ap->am_ttl = mp->am_ttl;
1208310490Scy
1209310490Scy      mp_to_fh3(ap, &result.res_u.ok.object);
1210310490Scy
1211310490Scy      /* mount attributes */
1212310490Scy      post_op_obj->attributes_follow = 1;
1213310490Scy      fattr = &ap->am_fattr;
1214310490Scy      fattr3 = &post_op_obj->am_post_op_attr_u.attributes;
1215310490Scy      fattr_to_fattr3(fattr, fattr3);
1216310490Scy
1217310490Scy      result.status = AM_NFS3_OK;
1218310490Scy    }
1219310490Scy    mp->am_stats.s_lookup++;
1220310490Scy  }
1221310490Scy  return &result;
1222310490Scy}
1223310490Scy
1224310490Scyam_ACCESS3res *
1225310490Scyam_nfs3_access_3_svc(am_ACCESS3args *argp, struct svc_req *rqstp)
1226310490Scy{
1227310490Scy  static am_ACCESS3res  result;
1228310490Scy
1229310490Scy  am_nfs_fh3 *obj = &argp->object;
1230310490Scy  u_int accessbits = argp->access;
1231310490Scy  u_int accessmask = AM_ACCESS3_LOOKUP|AM_ACCESS3_READ;
1232310490Scy  am_post_op_attr *post_op_obj;
1233310490Scy  am_node *mp;
1234310490Scy
1235310490Scy  if (amuDebug(D_TRACE))
1236310490Scy    plog(XLOG_DEBUG, "access_3:");
1237310490Scy
1238310490Scy  mp = fh3_to_mp(obj);
1239310490Scy  if (!mp) {
1240310490Scy    post_op_obj = &result.res_u.fail.obj_attributes;
1241310490Scy    post_op_obj->attributes_follow = 0;
1242310490Scy    result.status = nfs_error(ENOENT);
1243310490Scy    if (amuDebug(D_TRACE))
1244310490Scy      plog(XLOG_DEBUG, "access_3: ENOENT");
1245310490Scy  } else {
1246310490Scy    nfsfattr *fattr = &mp->am_fattr;
1247310490Scy    am_fattr3 *fattr3;
1248310490Scy    post_op_obj = &result.res_u.ok.obj_attributes;
1249310490Scy    fattr3 = &post_op_obj->am_post_op_attr_u.attributes;
1250310490Scy    post_op_obj->attributes_follow = 1;
1251310490Scy    fattr_to_fattr3(fattr, fattr3);
1252310490Scy
1253310490Scy    result.res_u.ok.access = accessbits & accessmask;
1254310490Scy    if (amuDebug(D_TRACE))
1255310490Scy      plog(XLOG_DEBUG, "access_3: b=%x m=%x", accessbits, accessmask);
1256310490Scy
1257310490Scy    result.status = AM_NFS3_OK;
1258310490Scy  }
1259310490Scy
1260310490Scy  return &result;
1261310490Scy}
1262310490Scy
1263310490Scyam_READLINK3res *
1264310490Scyam_nfs3_readlink_3_svc(am_READLINK3args *argp, struct svc_req *rqstp)
1265310490Scy{
1266310490Scy  static am_READLINK3res  result;
1267310490Scy
1268310490Scy  am_nfs_fh3 *symlink = (am_nfs_fh3 *) &argp->symlink;
1269310490Scy  am_post_op_attr *post_op_sym;
1270310490Scy  am_node *mp;
1271310490Scy  int retry = 0;
1272310490Scy
1273310490Scy  if (amuDebug(D_TRACE))
1274310490Scy    plog(XLOG_DEBUG, "readlink_3:");
1275310490Scy
1276310490Scy  mp = fh3_to_mp3(symlink, &retry, VLOOK_CREATE);
1277310490Scy  if (!mp) {
1278310490Scy  readlink_retry:
1279310490Scy    if (retry < 0) {
1280310490Scy      amd_stats.d_drops++;
1281310490Scy      return 0;
1282310490Scy    }
1283310490Scy    post_op_sym = &result.res_u.fail.symlink_attributes;
1284310490Scy    post_op_sym->attributes_follow = 0;
1285310490Scy    result.status = nfs_error(retry);
1286310490Scy  } else {
1287310490Scy    nfsfattr *fattr;
1288310490Scy    am_fattr3 *fattr3;
1289310490Scy    char *ln;
1290310490Scy
1291310490Scy    ln = do_readlink(mp, &retry);
1292310490Scy    if (!ln)
1293310490Scy      goto readlink_retry;
1294310490Scy
1295310490Scy    if (amuDebug(D_TRACE) && ln)
1296310490Scy      plog(XLOG_DEBUG, "\treadlink_3(%s) = %s", mp->am_path, ln);
1297310490Scy
1298310490Scy    result.res_u.ok.data = ln;
1299310490Scy
1300310490Scy    post_op_sym = &result.res_u.ok.symlink_attributes;
1301310490Scy    post_op_sym->attributes_follow = 1;
1302310490Scy    fattr = &mp->am_fattr;
1303310490Scy    fattr3 = &post_op_sym->am_post_op_attr_u.attributes;
1304310490Scy    fattr_to_fattr3(fattr, fattr3);
1305310490Scy
1306310490Scy    mp->am_stats.s_readlink++;
1307310490Scy    result.status = AM_NFS3_OK;
1308310490Scy  }
1309310490Scy
1310310490Scy  return &result;
1311310490Scy}
1312310490Scy
1313310490Scyam_READ3res *
1314310490Scyam_nfs3_read_3_svc(am_READ3args *argp, struct svc_req *rqstp)
1315310490Scy{
1316310490Scy  static am_READ3res  result;
1317310490Scy
1318310490Scy  am_nfs_fh3 *file = (am_nfs_fh3 *) &argp->file;
1319310490Scy  am_post_op_attr *post_op_file;
1320310490Scy  am_node *mp;
1321310490Scy
1322310490Scy  if (amuDebug(D_TRACE))
1323310490Scy    plog(XLOG_DEBUG, "read_3:");
1324310490Scy
1325310490Scy  post_op_file = &result.res_u.fail.file_attributes;
1326310490Scy  result.status = nfs_error(EACCES);
1327310490Scy
1328310490Scy  mp = fh3_to_mp(file);
1329310490Scy  if (!mp)
1330310490Scy    post_op_file->attributes_follow = 0;
1331310490Scy  else {
1332310490Scy    nfsfattr *fattr = &mp->am_fattr;
1333310490Scy    am_fattr3 *fattr3 = &post_op_file->am_post_op_attr_u.attributes;
1334310490Scy    post_op_file->attributes_follow = 1;
1335310490Scy    fattr_to_fattr3(fattr, fattr3);
1336310490Scy  }
1337310490Scy
1338310490Scy  return &result;
1339310490Scy}
1340310490Scy
1341310490Scyam_WRITE3res *
1342310490Scyam_nfs3_write_3_svc(am_WRITE3args *argp, struct svc_req *rqstp)
1343310490Scy{
1344310490Scy  static am_WRITE3res  result;
1345310490Scy
1346310490Scy  am_nfs_fh3 *file = (am_nfs_fh3 *) &argp->file;
1347310490Scy  am_pre_op_attr *pre_op_file = &result.res_u.fail.file_wcc.before;
1348310490Scy  am_post_op_attr *post_op_file = &result.res_u.fail.file_wcc.after;
1349310490Scy
1350310490Scy  if (amuDebug(D_TRACE))
1351310490Scy    plog(XLOG_DEBUG, "write_3:");
1352310490Scy
1353310490Scy  result.status = return_estale_or_rofs(file, pre_op_file, post_op_file);
1354310490Scy
1355310490Scy  return &result;
1356310490Scy}
1357310490Scy
1358310490Scyam_CREATE3res *
1359310490Scyam_nfs3_create_3_svc(am_CREATE3args *argp, struct svc_req *rqstp)
1360310490Scy{
1361310490Scy  static am_CREATE3res  result;
1362310490Scy
1363310490Scy  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->where.dir;
1364310490Scy  am_pre_op_attr *pre_op_dir = &result.res_u.fail.dir_wcc.before;
1365310490Scy  am_post_op_attr *post_op_dir = &result.res_u.fail.dir_wcc.after;
1366310490Scy
1367310490Scy  if (amuDebug(D_TRACE))
1368310490Scy    plog(XLOG_DEBUG, "create_3:");
1369310490Scy
1370310490Scy  result.status = return_estale_or_rofs(dir, pre_op_dir, post_op_dir);
1371310490Scy
1372310490Scy  return &result;
1373310490Scy}
1374310490Scy
1375310490Scyam_MKDIR3res *
1376310490Scyam_nfs3_mkdir_3_svc(am_MKDIR3args *argp, struct svc_req *rqstp)
1377310490Scy{
1378310490Scy  static am_MKDIR3res  result;
1379310490Scy
1380310490Scy  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->where.dir;
1381310490Scy  am_pre_op_attr *pre_op_dir = &result.res_u.fail.dir_wcc.before;
1382310490Scy  am_post_op_attr *post_op_dir = &result.res_u.fail.dir_wcc.after;
1383310490Scy
1384310490Scy  if (amuDebug(D_TRACE))
1385310490Scy    plog(XLOG_DEBUG, "mkdir_3:");
1386310490Scy
1387310490Scy  result.status = return_estale_or_rofs(dir, pre_op_dir, post_op_dir);
1388310490Scy
1389310490Scy  return &result;
1390310490Scy}
1391310490Scy
1392310490Scyam_SYMLINK3res *
1393310490Scyam_nfs3_symlink_3_svc(am_SYMLINK3args *argp, struct svc_req *rqstp)
1394310490Scy{
1395310490Scy  static am_SYMLINK3res  result;
1396310490Scy
1397310490Scy  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->where.dir;
1398310490Scy  am_pre_op_attr *pre_op_dir = &result.res_u.fail.dir_wcc.before;
1399310490Scy  am_post_op_attr *post_op_dir = &result.res_u.fail.dir_wcc.after;
1400310490Scy
1401310490Scy  if (amuDebug(D_TRACE))
1402310490Scy    plog(XLOG_DEBUG, "symlink_3:");
1403310490Scy
1404310490Scy  result.status = return_estale_or_rofs(dir, pre_op_dir, post_op_dir);
1405310490Scy
1406310490Scy  return &result;
1407310490Scy}
1408310490Scy
1409310490Scyam_MKNOD3res *
1410310490Scyam_nfs3_mknod_3_svc(am_MKNOD3args *argp, struct svc_req *rqstp)
1411310490Scy{
1412310490Scy  static am_MKNOD3res  result;
1413310490Scy
1414310490Scy  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->where.dir;
1415310490Scy  am_pre_op_attr *pre_op_dir = &result.res_u.fail.dir_wcc.before;
1416310490Scy  am_post_op_attr *post_op_dir =  &result.res_u.fail.dir_wcc.after;
1417310490Scy
1418310490Scy  if (amuDebug(D_TRACE))
1419310490Scy    plog(XLOG_DEBUG, "mknod_3:");
1420310490Scy
1421310490Scy  result.status = return_estale_or_rofs(dir, pre_op_dir, post_op_dir);
1422310490Scy  return &result;
1423310490Scy}
1424310490Scy
1425310490Scyam_REMOVE3res *
1426310490Scyam_nfs3_remove_3_svc(am_REMOVE3args *argp, struct svc_req *rqstp)
1427310490Scy{
1428310490Scy  static am_REMOVE3res  result;
1429310490Scy
1430310490Scy  am_diropargs3 *obj = &argp->object;
1431310490Scy  am_wcc_data dir_wcc;
1432310490Scy
1433310490Scy  if (amuDebug(D_TRACE))
1434310490Scy    plog(XLOG_DEBUG, "remove_3:");
1435310490Scy
1436310490Scy  result.status = unlink3_or_rmdir3(obj, &dir_wcc, TRUE);
1437310490Scy
1438310490Scy  result.res_u.ok.dir_wcc = dir_wcc;
1439310490Scy
1440310490Scy  return &result;
1441310490Scy}
1442310490Scy
1443310490Scyam_RMDIR3res *
1444310490Scyam_nfs3_rmdir_3_svc(am_RMDIR3args *argp, struct svc_req *rqstp)
1445310490Scy{
1446310490Scy  static am_RMDIR3res  result;
1447310490Scy
1448310490Scy  am_diropargs3 *obj = &argp->object;
1449310490Scy  am_wcc_data dir_wcc;
1450310490Scy
1451310490Scy  if (amuDebug(D_TRACE))
1452310490Scy    plog(XLOG_DEBUG, "rmdir_3:");
1453310490Scy
1454310490Scy  result.status = unlink3_or_rmdir3(obj, &dir_wcc, TRUE);
1455310490Scy
1456310490Scy  result.res_u.ok.dir_wcc = dir_wcc;
1457310490Scy
1458310490Scy  return &result;
1459310490Scy}
1460310490Scy
1461310490Scyam_RENAME3res *
1462310490Scyam_nfs3_rename_3_svc(am_RENAME3args *argp, struct svc_req *rqstp)
1463310490Scy{
1464310490Scy  static am_RENAME3res  result;
1465310490Scy
1466310490Scy  am_nfs_fh3 *fromdir = (am_nfs_fh3 *) &argp->from.dir;
1467310490Scy  am_nfs_fh3 *todir = (am_nfs_fh3 *) &argp->to.dir;
1468310490Scy  am_filename3 name = argp->to.name;
1469310490Scy  am_node *to_mp, *from_mp;
1470310490Scy
1471310490Scy  if (amuDebug(D_TRACE))
1472310490Scy    plog(XLOG_DEBUG, "rename_3:");
1473310490Scy
1474310490Scy  if (!(from_mp = fh3_to_mp(fromdir)) || !(to_mp = fh3_to_mp(todir)))
1475310490Scy    result.status = nfs_error(ESTALE);
1476310490Scy  /*
1477310490Scy   * If the kernel is doing clever things with referenced files
1478310490Scy   * then let it pretend...
1479310490Scy   */
1480310490Scy  else {
1481310490Scy    am_wcc_attr *wcc_attr;
1482310490Scy    am_fattr3 *fattr3;
1483310490Scy    am_wcc_data *to_wcc_data, *from_wcc_data;
1484310490Scy    am_pre_op_attr *pre_op_to, *pre_op_from;
1485310490Scy    am_post_op_attr *post_op_to, *post_op_from;
1486310490Scy    nfsfattr *fattr;
1487310490Scy
1488310490Scy    to_wcc_data = &result.res_u.ok.todir_wcc;
1489310490Scy
1490310490Scy    pre_op_to = &to_wcc_data->before;
1491310490Scy    post_op_to = &to_wcc_data->after;
1492310490Scy
1493310490Scy    pre_op_to->attributes_follow = 1;
1494310490Scy    fattr = &to_mp->am_fattr;
1495310490Scy    wcc_attr = &pre_op_to->am_pre_op_attr_u.attributes;
1496310490Scy    fattr_to_wcc_attr(fattr, wcc_attr);
1497310490Scy    post_op_to->attributes_follow = 1;
1498310490Scy    fattr3 = &post_op_to->am_post_op_attr_u.attributes;
1499310490Scy    fattr_to_fattr3(fattr, fattr3);
1500310490Scy
1501310490Scy    from_wcc_data = &result.res_u.ok.fromdir_wcc;
1502310490Scy
1503310490Scy    pre_op_from = &from_wcc_data->before;
1504310490Scy    post_op_from = &from_wcc_data->after;
1505310490Scy
1506310490Scy    pre_op_from->attributes_follow = 1;
1507310490Scy    fattr = &from_mp->am_fattr;
1508310490Scy    wcc_attr = &pre_op_from->am_pre_op_attr_u.attributes;
1509310490Scy    fattr_to_wcc_attr(fattr, wcc_attr);
1510310490Scy    post_op_from->attributes_follow = 1;
1511310490Scy    fattr3 = &post_op_from->am_post_op_attr_u.attributes;
1512310490Scy    fattr_to_fattr3(fattr, fattr3);
1513310490Scy
1514310490Scy    if (NSTREQ(name, ".nfs", 4))
1515310490Scy      result.status = AM_NFS3_OK;
1516310490Scy    /*
1517310490Scy     * otherwise a failure
1518310490Scy     */
1519310490Scy    else
1520310490Scy      result.status = nfs_error(EROFS);
1521310490Scy  }
1522310490Scy
1523310490Scy  return &result;
1524310490Scy}
1525310490Scy
1526310490Scyam_LINK3res *
1527310490Scyam_nfs3_link_3_svc(am_LINK3args *argp, struct svc_req *rqstp)
1528310490Scy{
1529310490Scy  static am_LINK3res  result;
1530310490Scy
1531310490Scy  am_nfs_fh3 *file = (am_nfs_fh3 *) &argp->file;
1532310490Scy  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->link.dir;
1533310490Scy  am_post_op_attr *post_op_file;
1534310490Scy  am_pre_op_attr *pre_op_dir;
1535310490Scy  am_post_op_attr *post_op_dir;
1536310490Scy  am_node *mp_file, *mp_dir;
1537310490Scy
1538310490Scy  if (amuDebug(D_TRACE))
1539310490Scy    plog(XLOG_DEBUG, "link_3:");
1540310490Scy
1541310490Scy  post_op_file = &result.res_u.fail.file_attributes;
1542310490Scy  post_op_file->attributes_follow = 0;
1543310490Scy
1544310490Scy  mp_file = fh3_to_mp(file);
1545310490Scy  if (mp_file) {
1546310490Scy    nfsfattr *fattr = &mp_file->am_fattr;
1547310490Scy    am_fattr3 *fattr3 = &post_op_file->am_post_op_attr_u.attributes;
1548310490Scy    fattr_to_fattr3(fattr, fattr3);
1549310490Scy  }
1550310490Scy
1551310490Scy  pre_op_dir = &result.res_u.fail.linkdir_wcc.before;
1552310490Scy  pre_op_dir->attributes_follow = 0;
1553310490Scy  post_op_dir = &result.res_u.fail.linkdir_wcc.after;
1554310490Scy  post_op_dir->attributes_follow = 0;
1555310490Scy
1556310490Scy  mp_dir = fh3_to_mp(dir);
1557310490Scy  if (mp_dir) {
1558310490Scy    nfsfattr *fattr = &mp_dir->am_fattr;
1559310490Scy    am_fattr3 *fattr3 = &post_op_dir->am_post_op_attr_u.attributes;
1560310490Scy    am_wcc_attr *wcc_attr = &pre_op_dir->am_pre_op_attr_u.attributes;
1561310490Scy
1562310490Scy    pre_op_dir->attributes_follow = 1;
1563310490Scy    fattr_to_wcc_attr(fattr, wcc_attr);
1564310490Scy    post_op_dir->attributes_follow = 1;
1565310490Scy    fattr_to_fattr3(fattr, fattr3);
1566310490Scy  }
1567310490Scy
1568310490Scy  if (!mp_file || !mp_dir)
1569310490Scy    result.status = nfs_error(ESTALE);
1570310490Scy  else
1571310490Scy    result.status = nfs_error(EROFS);
1572310490Scy
1573310490Scy  return &result;
1574310490Scy}
1575310490Scy
1576310490Scyam_READDIR3res *
1577310490Scyam_nfs3_readdir_3_svc(am_READDIR3args *argp, struct svc_req *rqstp)
1578310490Scy{
1579310490Scy  static am_READDIR3res  result;
1580310490Scy  static am_entry3 entries[MAX_READDIR_ENTRIES];
1581310490Scy  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->dir;
1582310490Scy  am_cookie3 cookie = argp->cookie;
1583310490Scy  am_cookieverf3 cookieverf;
1584310490Scy  am_count3 count = argp->count;
1585310490Scy  am_post_op_attr *post_op_dir;
1586310490Scy  am_node *mp;
1587310490Scy  int retry;
1588310490Scy
1589310490Scy  if (amuDebug(D_TRACE))
1590310490Scy    plog(XLOG_DEBUG, "readdir_3:");
1591310490Scy
1592310490Scy  memcpy(&cookieverf, &argp->cookieverf, sizeof(am_cookieverf3));
1593310490Scy
1594310490Scy  mp = fh3_to_mp3(dir, &retry, VLOOK_CREATE);
1595310490Scy  if (mp == NULL) {
1596310490Scy    if (retry < 0) {
1597310490Scy      amd_stats.d_drops++;
1598310490Scy      return 0;
1599310490Scy    }
1600310490Scy    post_op_dir = &result.res_u.fail.dir_attributes;
1601310490Scy    post_op_dir->attributes_follow = 0;
1602310490Scy    result.status = nfs_error(retry);
1603310490Scy  } else {
1604310490Scy    am_dirlist3 *list = &result.res_u.ok.reply;
1605310490Scy    am_nfsstat3 status;
1606310490Scy
1607310490Scy    if (amuDebug(D_TRACE))
1608310490Scy      plog(XLOG_DEBUG, "\treaddir_3(%s)", mp->am_path);
1609310490Scy
1610310490Scy    status = mp->am_al->al_mnt->mf_ops->readdir(mp,
1611310490Scy					(voidp)&cookie, list, entries, count);
1612310490Scy    if (status == 0) {
1613310490Scy      post_op_dir = &result.res_u.ok.dir_attributes;
1614310490Scy      nfsfattr *fattr;
1615310490Scy      am_fattr3 *fattr3;
1616310490Scy
1617310490Scy      fattr = &mp->am_fattr;
1618310490Scy      fattr3 = &post_op_dir->am_post_op_attr_u.attributes;
1619310490Scy      post_op_dir->attributes_follow = 1;
1620310490Scy      fattr_to_fattr3(fattr, fattr3);
1621310490Scy      result.status = AM_NFS3_OK;
1622310490Scy    } else {
1623310490Scy      post_op_dir = &result.res_u.fail.dir_attributes;
1624310490Scy      post_op_dir->attributes_follow = 0;
1625310490Scy      result.status = nfs_error(status);
1626310490Scy    }
1627310490Scy
1628310490Scy    mp->am_stats.s_readdir++;
1629310490Scy  }
1630310490Scy
1631310490Scy  return &result;
1632310490Scy}
1633310490Scy
1634310490Scyam_READDIRPLUS3res *
1635310490Scyam_nfs3_readdirplus_3_svc(am_READDIRPLUS3args *argp, struct svc_req *rqstp)
1636310490Scy{
1637310490Scy  static am_READDIRPLUS3res  result;
1638310490Scy  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->dir;
1639310490Scy  am_post_op_attr *post_op_dir;
1640310490Scy  nfsfattr *fattr;
1641310490Scy  am_fattr3 *fattr3;
1642310490Scy  am_node *mp;
1643310490Scy  int retry;
1644310490Scy
1645310490Scy  mp = fh3_to_mp3(dir, &retry, VLOOK_CREATE);
1646310490Scy  if (mp == NULL) {
1647310490Scy    if (retry < 0) {
1648310490Scy      amd_stats.d_drops++;
1649310490Scy      return 0;
1650310490Scy    }
1651310490Scy    post_op_dir = &result.res_u.fail.dir_attributes;
1652310490Scy    post_op_dir->attributes_follow = 0;
1653310490Scy    result.status = nfs_error(retry);
1654310490Scy  } else {
1655310490Scy      post_op_dir = &result.res_u.ok.dir_attributes;
1656310490Scy      fattr = &mp->am_fattr;
1657310490Scy      fattr3 = &post_op_dir->am_post_op_attr_u.attributes;
1658310490Scy      post_op_dir->attributes_follow = 1;
1659310490Scy      fattr_to_fattr3(fattr, fattr3);
1660310490Scy      result.status = AM_NFS3ERR_NOTSUPP;
1661310490Scy  }
1662310490Scy
1663310490Scy  return &result;
1664310490Scy}
1665310490Scy
1666310490Scyam_FSSTAT3res *
1667310490Scyam_nfs3_fsstat_3_svc(am_FSSTAT3args *argp, struct svc_req *rqstp)
1668310490Scy{
1669310490Scy  static am_FSSTAT3res  result;
1670310490Scy
1671310490Scy  am_nfs_fh3 *fsroot = (am_nfs_fh3 *) &argp->fsroot;
1672310490Scy  am_post_op_attr *post_op_fsroot;
1673310490Scy  am_node *mp;
1674310490Scy  int retry;
1675310490Scy
1676310490Scy  if (amuDebug(D_TRACE))
1677310490Scy    plog(XLOG_DEBUG, "fsstat_3:");
1678310490Scy
1679310490Scy  mp = fh3_to_mp3(fsroot, &retry, VLOOK_CREATE);
1680310490Scy  if (!mp) {
1681310490Scy    if (retry < 0) {
1682310490Scy      amd_stats.d_drops++;
1683310490Scy      return 0;
1684310490Scy    }
1685310490Scy    post_op_fsroot = &result.res_u.fail.obj_attributes;
1686310490Scy    post_op_fsroot->attributes_follow = 0;
1687310490Scy    result.status = nfs_error(retry);
1688310490Scy  } else {
1689310490Scy    am_FSSTAT3resok *ok = &result.res_u.ok;
1690310490Scy    u_int blocks, bfree, bavail;
1691310490Scy    nfsfattr *fattr;
1692310490Scy    am_fattr3 *fattr3;
1693310490Scy    mntent_t mnt;
1694310490Scy
1695310490Scy    if (amuDebug(D_TRACE))
1696310490Scy      plog(XLOG_DEBUG, "\tfsstat_3(%s)", mp->am_path);
1697310490Scy
1698310490Scy    fattr = &mp->am_fattr;
1699310490Scy    post_op_fsroot = &ok->obj_attributes;
1700310490Scy    post_op_fsroot->attributes_follow = 1;
1701310490Scy    fattr3 = &post_op_fsroot->am_post_op_attr_u.attributes;
1702310490Scy    fattr_to_fattr3(fattr, fattr3);
1703310490Scy
1704310490Scy    /*
1705310490Scy     * just return faked up file system information
1706310490Scy     */
1707310490Scy    ok->tbytes = 1024;
1708310490Scy    ok->invarsec = 0;
1709310490Scy
1710310490Scy    /* check if map is browsable and show_statfs_entries=yes  */
1711310490Scy    if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) &&
1712310490Scy	mp->am_al->al_mnt && mp->am_al->al_mnt->mf_mopts) {
1713310490Scy      mnt.mnt_opts = mp->am_al->al_mnt->mf_mopts;
1714310490Scy      if (amu_hasmntopt(&mnt, "browsable")) {
1715310490Scy	count_map_entries(mp, &blocks, &bfree, &bavail);
1716310490Scy      }
1717310490Scy      ok->fbytes = bfree;
1718310490Scy      ok->abytes = bavail;
1719310490Scy      ok->ffiles = bfree;
1720310490Scy      ok->afiles = bavail;
1721310490Scy      ok->tfiles = blocks;
1722310490Scy    } else {
1723310490Scy      ok->fbytes = 0;
1724310490Scy      ok->abytes = 0;
1725310490Scy      ok->ffiles = 0;
1726310490Scy      ok->afiles = 0;
1727310490Scy      ok->tfiles = 0; /* set to 1 if you don't want empty automounts */
1728310490Scy    }
1729310490Scy
1730310490Scy    result.status = AM_NFS3_OK;
1731310490Scy    mp->am_stats.s_statfs++;
1732310490Scy  }
1733310490Scy
1734310490Scy  return &result;
1735310490Scy}
1736310490Scy
1737310490Scy#define FSF3_HOMOGENEOUS 0x0008
1738310490Scy
1739310490Scyam_FSINFO3res *
1740310490Scyam_nfs3_fsinfo_3_svc(am_FSINFO3args *argp, struct svc_req *rqstp)
1741310490Scy{
1742310490Scy  static am_FSINFO3res  result;
1743310490Scy
1744310490Scy  am_nfs_fh3 *fsroot = (am_nfs_fh3 *) &argp->fsroot;
1745310490Scy  am_post_op_attr *post_op_fsroot;
1746310490Scy  am_node *mp;
1747310490Scy  int retry;
1748310490Scy
1749310490Scy  if (amuDebug(D_TRACE))
1750310490Scy    plog(XLOG_DEBUG, "fsinfo_3:");
1751310490Scy
1752310490Scy  mp = fh3_to_mp3(fsroot, &retry, VLOOK_CREATE);
1753310490Scy  if (!mp) {
1754310490Scy    if (retry < 0) {
1755310490Scy      amd_stats.d_drops++;
1756310490Scy      return 0;
1757310490Scy    }
1758310490Scy    post_op_fsroot = &result.res_u.fail.obj_attributes;
1759310490Scy    post_op_fsroot->attributes_follow = 0;
1760310490Scy    result.status = nfs_error(retry);
1761310490Scy  } else {
1762310490Scy    am_FSINFO3resok *ok = &result.res_u.ok;
1763310490Scy    nfsfattr *fattr;
1764310490Scy    am_fattr3 *fattr3;
1765310490Scy
1766310490Scy    if (amuDebug(D_TRACE))
1767310490Scy      plog(XLOG_DEBUG, "\tfsinfo_3(%s)", mp->am_path);
1768310490Scy
1769310490Scy    fattr = &mp->am_fattr;
1770310490Scy    post_op_fsroot = &ok->obj_attributes;
1771310490Scy    post_op_fsroot->attributes_follow = 1;
1772310490Scy    fattr3 = &post_op_fsroot->am_post_op_attr_u.attributes;
1773310490Scy    fattr_to_fattr3(fattr, fattr3);
1774310490Scy
1775310490Scy    /*
1776310490Scy     * just return faked up file system information
1777310490Scy     */
1778310490Scy    ok->rtmax = 0;
1779310490Scy    ok->rtpref = 0;
1780310490Scy    ok->rtmult = 0;
1781310490Scy    ok->wtmax = 0;
1782310490Scy    ok->wtpref = 0;
1783310490Scy    ok->wtmult = 0;
1784310490Scy    ok->dtpref = 1024;
1785310490Scy    ok->maxfilesize = 0;
1786310490Scy    ok->time_delta.seconds = 1;
1787310490Scy    ok->time_delta.nseconds = 0;
1788310490Scy    ok->properties = FSF3_HOMOGENEOUS;
1789310490Scy
1790310490Scy    result.status = AM_NFS3_OK;
1791310490Scy    mp->am_stats.s_fsinfo++;
1792310490Scy  }
1793310490Scy
1794310490Scy  return &result;
1795310490Scy}
1796310490Scy
1797310490Scyam_PATHCONF3res *
1798310490Scyam_nfs3_pathconf_3_svc(am_PATHCONF3args *argp, struct svc_req *rqstp)
1799310490Scy{
1800310490Scy  static am_PATHCONF3res  result;
1801310490Scy
1802310490Scy  am_nfs_fh3 *obj = (am_nfs_fh3 *) &argp->object;
1803310490Scy  am_post_op_attr *post_op_obj;
1804310490Scy  am_node *mp;
1805310490Scy  int retry;
1806310490Scy
1807310490Scy  if (amuDebug(D_TRACE))
1808310490Scy    plog(XLOG_DEBUG, "pathconf_3:");
1809310490Scy
1810310490Scy  mp = fh3_to_mp3(obj, &retry, VLOOK_CREATE);
1811310490Scy  if (!mp) {
1812310490Scy    if (retry < 0) {
1813310490Scy      amd_stats.d_drops++;
1814310490Scy      return 0;
1815310490Scy    }
1816310490Scy    post_op_obj = &result.res_u.fail.obj_attributes;
1817310490Scy    post_op_obj->attributes_follow = 0;
1818310490Scy    result.status = nfs_error(retry);
1819310490Scy  } else {
1820310490Scy    am_PATHCONF3resok *ok = &result.res_u.ok;
1821310490Scy    nfsfattr *fattr;
1822310490Scy    am_fattr3 *fattr3;
1823310490Scy
1824310490Scy    if (amuDebug(D_TRACE))
1825310490Scy      plog(XLOG_DEBUG, "\tpathconf_3(%s)", mp->am_path);
1826310490Scy
1827310490Scy    fattr = &mp->am_fattr;
1828310490Scy    post_op_obj = &ok->obj_attributes;
1829310490Scy    post_op_obj->attributes_follow = 1;
1830310490Scy    fattr3 = &post_op_obj->am_post_op_attr_u.attributes;
1831310490Scy    fattr_to_fattr3(fattr, fattr3);
1832310490Scy
1833310490Scy    ok->linkmax = 0;
1834310490Scy    ok->name_max = NAME_MAX;
1835310490Scy    ok->no_trunc = 1;
1836310490Scy    ok->chown_restricted = 1;
1837310490Scy    ok->case_insensitive = 0;
1838310490Scy    ok->case_preserving = 1;
1839310490Scy
1840310490Scy    result.status = AM_NFS3_OK;
1841310490Scy    mp->am_stats.s_pathconf++;
1842310490Scy  }
1843310490Scy
1844310490Scy  return &result;
1845310490Scy}
1846310490Scy
1847310490Scyam_COMMIT3res *
1848310490Scyam_nfs3_commit_3_svc(am_COMMIT3args *argp, struct svc_req *rqstp)
1849310490Scy{
1850310490Scy  static am_COMMIT3res  result;
1851310490Scy
1852310490Scy  am_nfs_fh3 *file = (am_nfs_fh3 *) &argp->file;
1853310490Scy  am_pre_op_attr *pre_op_file = &result.res_u.fail.file_wcc.before;
1854310490Scy  am_post_op_attr *post_op_file = &result.res_u.fail.file_wcc.after;
1855310490Scy
1856310490Scy  if (amuDebug(D_TRACE))
1857310490Scy    plog(XLOG_DEBUG, "commit_3:");
1858310490Scy
1859310490Scy  result.status = return_estale_or_rofs(file, pre_op_file, post_op_file);
1860310490Scy
1861310490Scy  return &result;
1862310490Scy}
1863310490Scy#endif /* HAVE_FS_NFS3 */
1864