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