Print this page
NEX-16712 NFS dtrace providers do not support per-share filtering
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Yuri Pankon <yuri.pankov@nexenta.com>
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-9275 Got "bad mutex" panic when run IO to nfs share from clients
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-3524 CLONE - Port NEX-3505 "wrong authentication" messages with root=@0.0.0.0/0 set, result in loss of client access
Reviewed by: Marcel Telka <marcel.telka@nexenta.com>
NEX-3533 CLONE - Port NEX-3019 NFSv3 writes underneath mounted filesystem to directory
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-3095 Issues related to NFS nohide
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-1128 NFS server: Generic uid and gid remapping for AUTH_SYS
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
OS-20 share_nfs(1m) charset handling is unreliable
OS-22 Page fault at nfscmd_dropped_entrysize+0x1e()
OS-23 NFSv2/3/4: READDIR responses are inconsistent when charset conversion fails
OS-24 rfs3_readdir(): Issues related to nfscmd_convdirent()
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
closes #12112 rb3823 - nfs-nohide: lookup("..") for submount should be correct
re #3541 rb11254 - nfs nohide - "nfssrv: need ability to go to submounts for v3 and v2 protocols"

*** 18,35 **** * * CDDL HEADER END */ /* ! * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include <sys/param.h> #include <sys/types.h> #include <sys/systm.h> #include <sys/cred.h> #include <sys/buf.h> --- 18,36 ---- * * CDDL HEADER END */ /* ! * Copyright 2018 Nexenta Systems, Inc. * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ + #include <sys/param.h> #include <sys/types.h> #include <sys/systm.h> #include <sys/cred.h> #include <sys/buf.h>
*** 66,82 **** #include <inet/ip.h> #include <inet/ip6.h> /* * These are the interface routines for the server side of the * Network File System. See the NFS version 3 protocol specification * for a description of this interface. */ - static writeverf3 write3verf; - static int sattr3_to_vattr(sattr3 *, struct vattr *); static int vattr_to_fattr3(struct vattr *, fattr3 *); static int vattr_to_wcc_attr(struct vattr *, wcc_attr *); static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *); static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *); --- 67,88 ---- #include <inet/ip.h> #include <inet/ip6.h> /* + * Zone global variables of NFSv3 server + */ + typedef struct nfs3_srv { + writeverf3 write3verf; + } nfs3_srv_t; + + /* * These are the interface routines for the server side of the * Network File System. See the NFS version 3 protocol specification * for a description of this interface. */ static int sattr3_to_vattr(sattr3 *, struct vattr *); static int vattr_to_fattr3(struct vattr *, fattr3 *); static int vattr_to_wcc_attr(struct vattr *, wcc_attr *); static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *); static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
*** 83,92 **** --- 89,99 ---- static int rdma_setup_read_data3(READ3args *, READ3resok *); extern int nfs_loaned_buffers; u_longlong_t nfs3_srv_caller_id; + static zone_key_t rfs3_zone_key; /* ARGSUSED */ void rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
*** 95,106 **** vnode_t *vp; struct vattr va; vp = nfs3_fhtovp(&args->object, exi); ! DTRACE_NFSV3_4(op__getattr__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, GETATTR3args *, args); if (vp == NULL) { error = ESTALE; goto out; } --- 102,114 ---- vnode_t *vp; struct vattr va; vp = nfs3_fhtovp(&args->object, exi); ! DTRACE_NFSV3_5(op__getattr__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! GETATTR3args *, args); if (vp == NULL) { error = ESTALE; goto out; }
*** 117,128 **** error = vattr_to_fattr3(&va, &resp->resok.obj_attributes); if (error) goto out; resp->status = NFS3_OK; ! DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp); VN_RELE(vp); return; } --- 125,137 ---- error = vattr_to_fattr3(&va, &resp->resok.obj_attributes); if (error) goto out; resp->status = NFS3_OK; ! DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! GETATTR3res *, resp); VN_RELE(vp); return; }
*** 132,152 **** curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); ! DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp); if (vp != NULL) VN_RELE(vp); } void * rfs3_getattr_getfh(GETATTR3args *args) { - return (&args->object); } void rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi, --- 141,161 ---- curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); ! DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! GETATTR3res *, resp); if (vp != NULL) VN_RELE(vp); } void * rfs3_getattr_getfh(GETATTR3args *args) { return (&args->object); } void rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
*** 166,177 **** bvap = NULL; avap = NULL; vp = nfs3_fhtovp(&args->object, exi); ! DTRACE_NFSV3_4(op__setattr__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, SETATTR3args *, args); if (vp == NULL) { error = ESTALE; goto out; } --- 175,187 ---- bvap = NULL; avap = NULL; vp = nfs3_fhtovp(&args->object, exi); ! DTRACE_NFSV3_5(op__setattr__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! SETATTR3args *, args); if (vp == NULL) { error = ESTALE; goto out; }
*** 328,339 **** nbl_end_crit(vp); resp->status = NFS3_OK; vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc); ! DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp); VN_RELE(vp); return; --- 338,350 ---- nbl_end_crit(vp); resp->status = NFS3_OK; vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc); ! DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! SETATTR3res *, resp); VN_RELE(vp); return;
*** 342,353 **** curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp); if (vp != NULL) { if (in_crit) nbl_end_crit(vp); VN_RELE(vp); --- 353,365 ---- curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! SETATTR3res *, resp); if (vp != NULL) { if (in_crit) nbl_end_crit(vp); VN_RELE(vp);
*** 356,366 **** } void * rfs3_setattr_getfh(SETATTR3args *args) { - return (&args->object); } /* ARGSUSED */ void --- 368,377 ----
*** 380,404 **** struct sockaddr *ca; char *name = NULL; dvap = NULL; /* * Allow lookups from the root - the default * location of the public filehandle. */ if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) { ! dvp = rootdir; VN_HOLD(dvp); ! DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args); } else { dvp = nfs3_fhtovp(&args->what.dir, exi); ! DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args); if (dvp == NULL) { error = ESTALE; goto out; } --- 391,420 ---- struct sockaddr *ca; char *name = NULL; dvap = NULL; + if (exi != NULL) + exi_hold(exi); + /* * Allow lookups from the root - the default * location of the public filehandle. */ if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) { ! dvp = ZONE_ROOTVP(); VN_HOLD(dvp); ! DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! LOOKUP3args *, args); } else { dvp = nfs3_fhtovp(&args->what.dir, exi); ! DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! LOOKUP3args *, args); if (dvp == NULL) { error = ESTALE; goto out; }
*** 418,430 **** --- 434,457 ---- } fhp = &args->what.dir; if (strcmp(args->what.name, "..") == 0 && EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) { + if ((exi->exi_export.ex_flags & EX_NOHIDE) && + (dvp->v_flag & VROOT)) { + /* + * special case for ".." and 'nohide'exported root + */ + if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } else { resp->status = NFS3ERR_NOENT; goto out1; } + } ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; name = nfscmd_convname(ca, exi, args->what.name, NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
*** 437,450 **** * If the public filehandle is used then allow * a multi-component lookup */ if (PUBLIC_FH3(&args->what.dir)) { publicfh_flag = TRUE; error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi, &sec); ! if (error && exi != NULL) ! exi_rele(exi); /* See comment below Re: publicfh_flag */ /* * Since WebNFS may bypass MOUNT, we need to ensure this * request didn't come from an unlabeled admin_low client. */ if (is_system_labeled() && error == 0) { --- 464,479 ---- * If the public filehandle is used then allow * a multi-component lookup */ if (PUBLIC_FH3(&args->what.dir)) { publicfh_flag = TRUE; + + exi_rele(&exi); + error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi, &sec); ! /* * Since WebNFS may bypass MOUNT, we need to ensure this * request didn't come from an unlabeled admin_low client. */ if (is_system_labeled() && error == 0) {
*** 462,473 **** } tp = find_tpc(ipaddr, addr_type, B_FALSE); if (tp == NULL || tp->tpc_tp.tp_doi != l_admin_low->tsl_doi || tp->tpc_tp.host_type != SUN_CIPSO) { - if (exi != NULL) - exi_rele(exi); VN_RELE(vp); error = EACCES; } if (tp != NULL) TPC_RELE(tp); --- 491,500 ----
*** 478,487 **** --- 505,520 ---- } if (name != args->what.name) kmem_free(name, MAXPATHLEN + 1); + if (error == 0 && vn_ismntpt(vp)) { + error = rfs_cross_mnt(&vp, &exi); + if (error) + VN_RELE(vp); + } + if (is_system_labeled() && error == 0) { bslabel_t *clabel = req->rq_label; ASSERT(clabel != NULL); DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
*** 488,499 **** "got client label from request(1)", struct svc_req *, req); if (!blequal(&l_admin_low->tsl_label, clabel)) { if (!do_rfs_label_check(clabel, dvp, DOMINANCE_CHECK, exi)) { - if (publicfh_flag && exi != NULL) - exi_rele(exi); VN_RELE(vp); error = EACCES; } } } --- 521,530 ----
*** 510,536 **** error = makefh3(&resp->resok.object, vp, exi); if (!error && publicfh_flag && !chk_clnt_sec(exi, req)) auth_weak = TRUE; } - /* - * If publicfh_flag is true then we have called rfs_publicfh_mclookup - * and have obtained a new exportinfo in exi which needs to be - * released. Note that the original exportinfo pointed to by exi - * will be released by the caller, common_dispatch. - */ - if (publicfh_flag) - exi_rele(exi); - if (error) { VN_RELE(vp); goto out; } va.va_mask = AT_ALL; vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; VN_RELE(vp); resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes); --- 541,559 ---- error = makefh3(&resp->resok.object, vp, exi); if (!error && publicfh_flag && !chk_clnt_sec(exi, req)) auth_weak = TRUE; } if (error) { VN_RELE(vp); goto out; } va.va_mask = AT_ALL; vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; + exi_rele(&exi); VN_RELE(vp); resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
*** 541,552 **** * Then set RPC status to AUTH_TOOWEAK in common_dispatch. */ if (auth_weak) resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR; ! DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp); VN_RELE(dvp); return; out: --- 564,576 ---- * Then set RPC status to AUTH_TOOWEAK in common_dispatch. */ if (auth_weak) resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR; ! DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! LOOKUP3res *, resp); VN_RELE(dvp); return; out:
*** 554,580 **** curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp); if (dvp != NULL) VN_RELE(dvp); vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes); } void * rfs3_lookup_getfh(LOOKUP3args *args) { - return (&args->what.dir); } - /* ARGSUSED */ void rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) { int error; --- 578,606 ---- curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! if (exi != NULL) ! exi_rele(&exi); + DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req, + cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, + LOOKUP3res *, resp); + if (dvp != NULL) VN_RELE(dvp); vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes); } void * rfs3_lookup_getfh(LOOKUP3args *args) { return (&args->what.dir); } void rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) { int error;
*** 588,599 **** vap = NULL; vp = nfs3_fhtovp(&args->object, exi); ! DTRACE_NFSV3_4(op__access__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, ACCESS3args *, args); if (vp == NULL) { error = ESTALE; goto out; } --- 614,626 ---- vap = NULL; vp = nfs3_fhtovp(&args->object, exi); ! DTRACE_NFSV3_5(op__access__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! ACCESS3args *, args); if (vp == NULL) { error = ESTALE; goto out; }
*** 699,710 **** vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); ! DTRACE_NFSV3_4(op__access__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp); VN_RELE(vp); return; --- 726,738 ---- vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va; resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); ! DTRACE_NFSV3_5(op__access__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! ACCESS3res *, resp); VN_RELE(vp); return;
*** 712,732 **** if (curthread->t_flag & T_WOULDBLOCK) { curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); ! DTRACE_NFSV3_4(op__access__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp); if (vp != NULL) VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); } void * rfs3_access_getfh(ACCESS3args *args) { - return (&args->object); } /* ARGSUSED */ void --- 740,760 ---- if (curthread->t_flag & T_WOULDBLOCK) { curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); ! DTRACE_NFSV3_5(op__access__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! ACCESS3res *, resp); if (vp != NULL) VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); } void * rfs3_access_getfh(ACCESS3args *args) { return (&args->object); } /* ARGSUSED */ void
*** 746,757 **** vap = NULL; vp = nfs3_fhtovp(&args->symlink, exi); ! DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READLINK3args *, args); if (vp == NULL) { error = ESTALE; goto out; } --- 774,786 ---- vap = NULL; vp = nfs3_fhtovp(&args->symlink, exi); ! DTRACE_NFSV3_5(op__readlink__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! READLINK3args *, args); if (vp == NULL) { error = ESTALE; goto out; }
*** 867,878 **** resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes); resp->resok.data = name; ! DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READLINK3res *, resp); VN_RELE(vp); if (name != data) kmem_free(data, MAXPATHLEN + 1); --- 896,908 ---- resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes); resp->resok.data = name; ! DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! READLINK3res *, resp); VN_RELE(vp); if (name != data) kmem_free(data, MAXPATHLEN + 1);
*** 883,910 **** curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READLINK3res *, resp); if (vp != NULL) VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes); } void * rfs3_readlink_getfh(READLINK3args *args) { - return (&args->symlink); } void rfs3_readlink_free(READLINK3res *resp) { - if (resp->status == NFS3_OK) kmem_free(resp->resok.data, MAXPATHLEN + 1); } /* --- 913,939 ---- curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! READLINK3res *, resp); if (vp != NULL) VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes); } void * rfs3_readlink_getfh(READLINK3args *args) { return (&args->symlink); } void rfs3_readlink_free(READLINK3res *resp) { if (resp->status == NFS3_OK) kmem_free(resp->resok.data, MAXPATHLEN + 1); } /*
*** 934,946 **** vap = NULL; vp = nfs3_fhtovp(&args->file, exi); ! DTRACE_NFSV3_4(op__read__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READ3args *, args); if (vp == NULL) { error = ESTALE; goto out; } --- 963,977 ---- vap = NULL; vp = nfs3_fhtovp(&args->file, exi); ! DTRACE_NFSV3_5(op__read__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! READ3args *, args); + if (vp == NULL) { error = ESTALE; goto out; }
*** 1190,1201 **** resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base; (resp->resok).wlist = NULL; } done: ! DTRACE_NFSV3_4(op__read__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READ3res *, resp); VN_RELE(vp); if (iovp != NULL) kmem_free(iovp, iovcnt * sizeof (struct iovec)); --- 1221,1233 ---- resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base; (resp->resok).wlist = NULL; } done: ! DTRACE_NFSV3_5(op__read__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! READ3res *, resp); VN_RELE(vp); if (iovp != NULL) kmem_free(iovp, iovcnt * sizeof (struct iovec));
*** 1207,1218 **** curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_4(op__read__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READ3res *, resp); if (vp != NULL) { if (need_rwunlock) VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); if (in_crit) --- 1239,1251 ---- curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_5(op__read__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! READ3res *, resp); if (vp != NULL) { if (need_rwunlock) VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct); if (in_crit)
*** 1238,1248 **** } void * rfs3_read_getfh(READ3args *args) { - return (&args->file); } #define MAX_IOVECS 12 --- 1271,1280 ----
*** 1253,1262 **** --- 1285,1295 ---- void rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) { + nfs3_srv_t *ns; int error; vnode_t *vp; struct vattr *bvap = NULL; struct vattr bva; struct vattr *avap = NULL;
*** 1273,1290 **** int rwlock_ret = -1; caller_context_t ct; vp = nfs3_fhtovp(&args->file, exi); ! DTRACE_NFSV3_4(op__write__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, WRITE3args *, args); if (vp == NULL) { error = ESTALE; goto err; } if (is_system_labeled()) { bslabel_t *clabel = req->rq_label; ASSERT(clabel != NULL); DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *, --- 1306,1325 ---- int rwlock_ret = -1; caller_context_t ct; vp = nfs3_fhtovp(&args->file, exi); ! DTRACE_NFSV3_5(op__write__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! WRITE3args *, args); if (vp == NULL) { error = ESTALE; goto err; } + ns = zone_getspecific(rfs3_zone_key, curzone); if (is_system_labeled()) { bslabel_t *clabel = req->rq_label; ASSERT(clabel != NULL); DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
*** 1368,1378 **** if (args->count == 0) { resp->status = NFS3_OK; vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); resp->resok.count = 0; resp->resok.committed = args->stable; ! resp->resok.verf = write3verf; goto out; } if (args->mblk != NULL) { iovcnt = 0; --- 1403,1413 ---- if (args->count == 0) { resp->status = NFS3_OK; vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); resp->resok.count = 0; resp->resok.committed = args->stable; ! resp->resok.verf = ns->write3verf; goto out; } if (args->mblk != NULL) { iovcnt = 0;
*** 1470,1480 **** resp->status = NFS3_OK; vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); resp->resok.count = args->count - uio.uio_resid; resp->resok.committed = args->stable; ! resp->resok.verf = write3verf; goto out; err: if (curthread->t_flag & T_WOULDBLOCK) { curthread->t_flag &= ~T_WOULDBLOCK; --- 1505,1515 ---- resp->status = NFS3_OK; vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); resp->resok.count = args->count - uio.uio_resid; resp->resok.committed = args->stable; ! resp->resok.verf = ns->write3verf; goto out; err: if (curthread->t_flag & T_WOULDBLOCK) { curthread->t_flag &= ~T_WOULDBLOCK;
*** 1482,1493 **** } else resp->status = puterrno3(error); err1: vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); out: ! DTRACE_NFSV3_4(op__write__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, WRITE3res *, resp); if (vp != NULL) { if (rwlock_ret != -1) VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct); if (in_crit) --- 1517,1529 ---- } else resp->status = puterrno3(error); err1: vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); out: ! DTRACE_NFSV3_5(op__write__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! WRITE3res *, resp); if (vp != NULL) { if (rwlock_ret != -1) VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct); if (in_crit)
*** 1497,1507 **** } void * rfs3_write_getfh(WRITE3args *args) { - return (&args->file); } void rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi, --- 1533,1542 ----
*** 1528,1539 **** dbvap = NULL; davap = NULL; dvp = nfs3_fhtovp(&args->where.dir, exi); ! DTRACE_NFSV3_4(op__create__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, CREATE3args *, args); if (dvp == NULL) { error = ESTALE; goto out; } --- 1563,1575 ---- dbvap = NULL; davap = NULL; dvp = nfs3_fhtovp(&args->where.dir, exi); ! DTRACE_NFSV3_5(op__create__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! CREATE3args *, args); if (dvp == NULL) { error = ESTALE; goto out; }
*** 1555,1564 **** --- 1591,1605 ---- if (rdonly(ro, dvp)) { resp->status = NFS3ERR_ROFS; goto out1; } + if (protect_zfs_mntpt(dvp) != 0) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + if (is_system_labeled()) { bslabel_t *clabel = req->rq_label; ASSERT(clabel != NULL); DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
*** 1828,1839 **** resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); ! DTRACE_NFSV3_4(op__create__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp); VN_RELE(dvp); return; out: --- 1869,1881 ---- resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); ! DTRACE_NFSV3_5(op__create__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! CREATE3res *, resp); VN_RELE(dvp); return; out:
*** 1841,1852 **** curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_4(op__create__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp); if (name != NULL && name != args->where.name) kmem_free(name, MAXPATHLEN + 1); if (tvp != NULL) { --- 1883,1895 ---- curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_5(op__create__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! CREATE3res *, resp); if (name != NULL && name != args->where.name) kmem_free(name, MAXPATHLEN + 1); if (tvp != NULL) {
*** 1860,1870 **** } void * rfs3_create_getfh(CREATE3args *args) { - return (&args->where.dir); } void rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi, --- 1903,1912 ----
*** 1885,1896 **** dbvap = NULL; davap = NULL; dvp = nfs3_fhtovp(&args->where.dir, exi); ! DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args); if (dvp == NULL) { error = ESTALE; goto out; } --- 1927,1939 ---- dbvap = NULL; davap = NULL; dvp = nfs3_fhtovp(&args->where.dir, exi); ! DTRACE_NFSV3_5(op__mkdir__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! MKDIR3args *, args); if (dvp == NULL) { error = ESTALE; goto out; }
*** 1912,1921 **** --- 1955,1969 ---- if (rdonly(ro, dvp)) { resp->status = NFS3ERR_ROFS; goto out1; } + if (protect_zfs_mntpt(dvp) != 0) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + if (is_system_labeled()) { bslabel_t *clabel = req->rq_label; ASSERT(clabel != NULL); DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
*** 1985,1996 **** resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); ! DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp); VN_RELE(dvp); return; out: --- 2033,2045 ---- resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); ! DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! MKDIR3res *, resp); VN_RELE(dvp); return; out:
*** 1998,2018 **** curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp); if (dvp != NULL) VN_RELE(dvp); vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); } void * rfs3_mkdir_getfh(MKDIR3args *args) { - return (&args->where.dir); } void rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi, --- 2047,2067 ---- curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! MKDIR3res *, resp); if (dvp != NULL) VN_RELE(dvp); vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); } void * rfs3_mkdir_getfh(MKDIR3args *args) { return (&args->where.dir); } void rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
*** 2034,2045 **** dbvap = NULL; davap = NULL; dvp = nfs3_fhtovp(&args->where.dir, exi); ! DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args); if (dvp == NULL) { error = ESTALE; goto err; } --- 2083,2095 ---- dbvap = NULL; davap = NULL; dvp = nfs3_fhtovp(&args->where.dir, exi); ! DTRACE_NFSV3_5(op__symlink__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! SYMLINK3args *, args); if (dvp == NULL) { error = ESTALE; goto err; }
*** 2061,2070 **** --- 2111,2125 ---- if (rdonly(ro, dvp)) { resp->status = NFS3ERR_ROFS; goto err1; } + if (protect_zfs_mntpt(dvp) != 0) { + resp->status = NFS3ERR_ACCES; + goto err1; + } + if (is_system_labeled()) { bslabel_t *clabel = req->rq_label; ASSERT(clabel != NULL); DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
*** 2172,2192 **** if (name != NULL && name != args->where.name) kmem_free(name, MAXPATHLEN + 1); if (symdata != NULL && symdata != args->symlink.symlink_data) kmem_free(symdata, MAXPATHLEN + 1); ! DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp); if (dvp != NULL) VN_RELE(dvp); } void * rfs3_symlink_getfh(SYMLINK3args *args) { - return (&args->where.dir); } void rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi, --- 2227,2247 ---- if (name != NULL && name != args->where.name) kmem_free(name, MAXPATHLEN + 1); if (symdata != NULL && symdata != args->symlink.symlink_data) kmem_free(symdata, MAXPATHLEN + 1); ! DTRACE_NFSV3_5(op__symlink__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! SYMLINK3res *, resp); if (dvp != NULL) VN_RELE(dvp); } void * rfs3_symlink_getfh(SYMLINK3args *args) { return (&args->where.dir); } void rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
*** 2210,2221 **** dbvap = NULL; davap = NULL; dvp = nfs3_fhtovp(&args->where.dir, exi); ! DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args); if (dvp == NULL) { error = ESTALE; goto out; } --- 2265,2277 ---- dbvap = NULL; davap = NULL; dvp = nfs3_fhtovp(&args->where.dir, exi); ! DTRACE_NFSV3_5(op__mknod__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! MKNOD3args *, args); if (dvp == NULL) { error = ESTALE; goto out; }
*** 2237,2246 **** --- 2293,2307 ---- if (rdonly(ro, dvp)) { resp->status = NFS3ERR_ROFS; goto out1; } + if (protect_zfs_mntpt(dvp) != 0) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + if (is_system_labeled()) { bslabel_t *clabel = req->rq_label; ASSERT(clabel != NULL); DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
*** 2357,2368 **** VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); ! DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp); VN_RELE(dvp); return; out: if (curthread->t_flag & T_WOULDBLOCK) { --- 2418,2430 ---- VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc); ! DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! MKNOD3res *, resp); VN_RELE(dvp); return; out: if (curthread->t_flag & T_WOULDBLOCK) {
*** 2369,2389 **** curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp); if (dvp != NULL) VN_RELE(dvp); vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); } void * rfs3_mknod_getfh(MKNOD3args *args) { - return (&args->where.dir); } void rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi, --- 2431,2451 ---- curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi, ! MKNOD3res *, resp); if (dvp != NULL) VN_RELE(dvp); vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc); } void * rfs3_mknod_getfh(MKNOD3args *args) { return (&args->where.dir); } void rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
*** 2402,2413 **** bvap = NULL; avap = NULL; vp = nfs3_fhtovp(&args->object.dir, exi); ! DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, REMOVE3args *, args); if (vp == NULL) { error = ESTALE; goto err; } --- 2464,2476 ---- bvap = NULL; avap = NULL; vp = nfs3_fhtovp(&args->object.dir, exi); ! DTRACE_NFSV3_5(op__remove__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! REMOVE3args *, args); if (vp == NULL) { error = ESTALE; goto err; }
*** 2511,2522 **** } else resp->status = puterrno3(error); err1: vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); out: ! DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp); if (name != NULL && name != args->object.name) kmem_free(name, MAXPATHLEN + 1); if (vp != NULL) --- 2574,2586 ---- } else resp->status = puterrno3(error); err1: vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); out: ! DTRACE_NFSV3_5(op__remove__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! REMOVE3res *, resp); if (name != NULL && name != args->object.name) kmem_free(name, MAXPATHLEN + 1); if (vp != NULL)
*** 2524,2534 **** } void * rfs3_remove_getfh(REMOVE3args *args) { - return (&args->object.dir); } void rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi, --- 2588,2597 ----
*** 2546,2557 **** bvap = NULL; avap = NULL; vp = nfs3_fhtovp(&args->object.dir, exi); ! DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, RMDIR3args *, args); if (vp == NULL) { error = ESTALE; goto err; } --- 2609,2621 ---- bvap = NULL; avap = NULL; vp = nfs3_fhtovp(&args->object.dir, exi); ! DTRACE_NFSV3_5(op__rmdir__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! RMDIR3args *, args); if (vp == NULL) { error = ESTALE; goto err; }
*** 2603,2613 **** if (name == NULL) { resp->status = NFS3ERR_INVAL; goto err1; } ! error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0); if (name != args->object.name) kmem_free(name, MAXPATHLEN + 1); ava.va_mask = AT_ALL; --- 2667,2677 ---- if (name == NULL) { resp->status = NFS3ERR_INVAL; goto err1; } ! error = VOP_RMDIR(vp, name, ZONE_ROOTVP(), cr, NULL, 0); if (name != args->object.name) kmem_free(name, MAXPATHLEN + 1); ava.va_mask = AT_ALL;
*** 2641,2661 **** } else resp->status = puterrno3(error); err1: vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); out: ! DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp); if (vp != NULL) VN_RELE(vp); } void * rfs3_rmdir_getfh(RMDIR3args *args) { - return (&args->object.dir); } void rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi, --- 2705,2725 ---- } else resp->status = puterrno3(error); err1: vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc); out: ! DTRACE_NFSV3_5(op__rmdir__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! RMDIR3res *, resp); if (vp != NULL) VN_RELE(vp); } void * rfs3_rmdir_getfh(RMDIR3args *args) { return (&args->object.dir); } void rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
*** 2687,2698 **** tavap = NULL; tvp = NULL; fvp = nfs3_fhtovp(&args->from.dir, exi); ! DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, fvp, RENAME3args *, args); if (fvp == NULL) { error = ESTALE; goto err; } --- 2751,2763 ---- tavap = NULL; tvp = NULL; fvp = nfs3_fhtovp(&args->from.dir, exi); ! DTRACE_NFSV3_5(op__rename__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi, ! RENAME3args *, args); if (fvp == NULL) { error = ESTALE; goto err; }
*** 2720,2730 **** to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3)); if (to_exi == NULL) { resp->status = NFS3ERR_ACCES; goto err1; } ! exi_rele(to_exi); if (to_exi != exi) { resp->status = NFS3ERR_XDEV; goto err1; } --- 2785,2795 ---- to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3)); if (to_exi == NULL) { resp->status = NFS3ERR_ACCES; goto err1; } ! exi_rele(&to_exi); if (to_exi != exi) { resp->status = NFS3ERR_XDEV; goto err1; }
*** 2758,2767 **** --- 2823,2837 ---- if (rdonly(ro, tvp)) { resp->status = NFS3ERR_ROFS; goto err1; } + if (protect_zfs_mntpt(tvp) != 0) { + resp->status = NFS3ERR_ACCES; + goto err1; + } + if (is_system_labeled()) { if (!blequal(&l_admin_low->tsl_label, clabel)) { if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK, exi)) { resp->status = NFS3ERR_ACCES;
*** 2805,2818 **** resp->status = NFS3ERR_JUKEBOX; goto err1; } /* ! * Check for renaming over a delegated file. Check rfs4_deleg_policy * first to avoid VOP_LOOKUP if possible. */ ! if (rfs4_deleg_policy != SRV_NEVER_DELEGATE && VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr, NULL, NULL, NULL) == 0) { if (rfs4_check_delegated(FWRITE, targvp, TRUE)) { VN_RELE(targvp); --- 2875,2888 ---- resp->status = NFS3ERR_JUKEBOX; goto err1; } /* ! * Check for renaming over a delegated file. Check nfs4_deleg_policy * first to avoid VOP_LOOKUP if possible. */ ! if (nfs4_get_deleg_policy() != SRV_NEVER_DELEGATE && VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr, NULL, NULL, NULL) == 0) { if (rfs4_check_delegated(FWRITE, targvp, TRUE)) { VN_RELE(targvp);
*** 2872,2893 **** if (name != NULL && name != args->from.name) kmem_free(name, MAXPATHLEN + 1); if (toname != NULL && toname != args->to.name) kmem_free(toname, MAXPATHLEN + 1); ! DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp); if (fvp != NULL) VN_RELE(fvp); if (tvp != NULL) VN_RELE(tvp); } void * rfs3_rename_getfh(RENAME3args *args) { - return (&args->from.dir); } void rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi, --- 2942,2963 ---- if (name != NULL && name != args->from.name) kmem_free(name, MAXPATHLEN + 1); if (toname != NULL && toname != args->to.name) kmem_free(toname, MAXPATHLEN + 1); ! DTRACE_NFSV3_5(op__rename__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi, ! RENAME3res *, resp); if (fvp != NULL) VN_RELE(fvp); if (tvp != NULL) VN_RELE(tvp); } void * rfs3_rename_getfh(RENAME3args *args) { return (&args->from.dir); } void rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
*** 2913,2924 **** avap = NULL; dvp = NULL; vp = nfs3_fhtovp(&args->file, exi); ! DTRACE_NFSV3_4(op__link__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, LINK3args *, args); if (vp == NULL) { error = ESTALE; goto out; } --- 2983,2995 ---- avap = NULL; dvp = NULL; vp = nfs3_fhtovp(&args->file, exi); ! DTRACE_NFSV3_5(op__link__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! LINK3args *, args); if (vp == NULL) { error = ESTALE; goto out; }
*** 2930,2940 **** to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3)); if (to_exi == NULL) { resp->status = NFS3ERR_ACCES; goto out1; } ! exi_rele(to_exi); if (to_exi != exi) { resp->status = NFS3ERR_XDEV; goto out1; } --- 3001,3011 ---- to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3)); if (to_exi == NULL) { resp->status = NFS3ERR_ACCES; goto out1; } ! exi_rele(&to_exi); if (to_exi != exi) { resp->status = NFS3ERR_XDEV; goto out1; }
*** 2982,2991 **** --- 3053,3067 ---- if (rdonly(ro, dvp)) { resp->status = NFS3ERR_ROFS; goto out1; } + if (protect_zfs_mntpt(dvp) != 0) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + if (is_system_labeled()) { DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *, "got client label from request(1)", struct svc_req *, req); if (!blequal(&l_admin_low->tsl_label, clabel)) {
*** 3026,3037 **** resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.file_attributes); vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc); ! DTRACE_NFSV3_4(op__link__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, LINK3res *, resp); VN_RELE(vp); return; --- 3102,3114 ---- resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.file_attributes); vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc); ! DTRACE_NFSV3_5(op__link__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! LINK3res *, resp); VN_RELE(vp); return;
*** 3043,3054 **** resp->status = puterrno3(error); out1: if (name != NULL && name != args->link.name) kmem_free(name, MAXPATHLEN + 1); ! DTRACE_NFSV3_4(op__link__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, LINK3res *, resp); if (vp != NULL) VN_RELE(vp); if (dvp != NULL) VN_RELE(dvp); --- 3120,3132 ---- resp->status = puterrno3(error); out1: if (name != NULL && name != args->link.name) kmem_free(name, MAXPATHLEN + 1); ! DTRACE_NFSV3_5(op__link__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! LINK3res *, resp); if (vp != NULL) VN_RELE(vp); if (dvp != NULL) VN_RELE(dvp);
*** 3057,3099 **** } void * rfs3_link_getfh(LINK3args *args) { - return (&args->file); } ! /* ! * This macro defines the size of a response which contains attribute ! * information and one directory entry (whose length is specified by ! * the macro parameter). If the incoming request is larger than this, ! * then we are guaranteed to be able to return at one directory entry ! * if one exists. Therefore, we do not need to check for ! * NFS3ERR_TOOSMALL if the requested size is larger then this. If it ! * is not, then we need to check to make sure that this error does not ! * need to be returned. ! * ! * NFS3_READDIR_MIN_COUNT is comprised of following : ! * ! * status - 1 * BYTES_PER_XDR_UNIT ! * attr. flag - 1 * BYTES_PER_XDR_UNIT ! * cookie verifier - 2 * BYTES_PER_XDR_UNIT ! * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT ! * boolean - 1 * BYTES_PER_XDR_UNIT ! * file id - 2 * BYTES_PER_XDR_UNIT ! * directory name length - 1 * BYTES_PER_XDR_UNIT ! * cookie - 2 * BYTES_PER_XDR_UNIT ! * end of list - 1 * BYTES_PER_XDR_UNIT ! * end of file - 1 * BYTES_PER_XDR_UNIT ! * Name length of directory to the nearest byte ! */ - #define NFS3_READDIR_MIN_COUNT(length) \ - ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \ - BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT)) - /* ARGSUSED */ void rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) { --- 3135,3152 ---- } void * rfs3_link_getfh(LINK3args *args) { return (&args->file); } ! #ifdef nextdp ! #undef nextdp ! #endif ! #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) /* ARGSUSED */ void rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) {
*** 3101,3129 **** vnode_t *vp; struct vattr *vap; struct vattr va; struct iovec iov; struct uio uio; - char *data; int iseof; - int bufsize; - int namlen; - uint_t count; - struct sockaddr *ca; ! vap = NULL; vp = nfs3_fhtovp(&args->dir, exi); ! DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READDIR3args *, args); if (vp == NULL) { ! error = ESTALE; ! goto out; } if (is_system_labeled()) { bslabel_t *clabel = req->rq_label; ASSERT(clabel != NULL); DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *, --- 3154,3194 ---- vnode_t *vp; struct vattr *vap; struct vattr va; struct iovec iov; struct uio uio; int iseof; ! count3 count = args->count; ! count3 size; /* size of the READDIR3resok structure */ + size_t datasz; + char *data = NULL; + dirent64_t *dp; + + struct sockaddr *ca; + entry3 **eptr; + entry3 *entry; + vp = nfs3_fhtovp(&args->dir, exi); ! DTRACE_NFSV3_5(op__readdir__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! READDIR3args *, args); if (vp == NULL) { ! resp->status = NFS3ERR_STALE; ! vap = NULL; ! goto out1; } + if (vp->v_type != VDIR) { + resp->status = NFS3ERR_NOTDIR; + vap = NULL; + goto out1; + } + if (is_system_labeled()) { bslabel_t *clabel = req->rq_label; ASSERT(clabel != NULL); DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
*** 3131,3140 **** --- 3196,3206 ---- if (!blequal(&l_admin_low->tsl_label, clabel)) { if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, exi)) { resp->status = NFS3ERR_ACCES; + vap = NULL; goto out1; } } }
*** 3141,3263 **** (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); va.va_mask = AT_ALL; vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; - if (vp->v_type != VDIR) { - resp->status = NFS3ERR_NOTDIR; - goto out1; - } - error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); if (error) goto out; /* ! * Now don't allow arbitrary count to alloc; ! * allow the maximum not to exceed rfs3_tsize() */ ! if (args->count > rfs3_tsize(req)) ! args->count = rfs3_tsize(req); /* * Make sure that there is room to read at least one entry * if any are available. */ ! if (args->count < DIRENT64_RECLEN(MAXNAMELEN)) ! count = DIRENT64_RECLEN(MAXNAMELEN); ! else ! count = args->count; ! data = kmem_alloc(count, KM_SLEEP); - iov.iov_base = data; - iov.iov_len = count; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_extflg = UIO_COPY_CACHED; uio.uio_loffset = (offset_t)args->cookie; ! uio.uio_resid = count; ! error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0); ! va.va_mask = AT_ALL; ! vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; if (error) { ! kmem_free(data, count); ! goto out; } ! /* ! * If the count was not large enough to be able to guarantee ! * to be able to return at least one entry, then need to ! * check to see if NFS3ERR_TOOSMALL should be returned. ! */ ! if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) { ! /* ! * bufsize is used to keep track of the size of the response. ! * It is primed with: ! * 1 for the status + ! * 1 for the dir_attributes.attributes boolean + ! * 2 for the cookie verifier ! * all times BYTES_PER_XDR_UNIT to convert from XDR units ! * to bytes. If there are directory attributes to be ! * returned, then: ! * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3 ! * time BYTES_PER_XDR_UNIT is added to account for them. ! */ ! bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT; ! if (vap != NULL) ! bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; ! /* ! * An entry is composed of: ! * 1 for the true/false list indicator + ! * 2 for the fileid + ! * 1 for the length of the name + ! * 2 for the cookie + ! * all times BYTES_PER_XDR_UNIT to convert from ! * XDR units to bytes, plus the length of the name ! * rounded up to the nearest BYTES_PER_XDR_UNIT. ! */ ! if (count != uio.uio_resid) { ! namlen = strlen(((struct dirent64 *)data)->d_name); ! bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT + ! roundup(namlen, BYTES_PER_XDR_UNIT); } /* ! * We need to check to see if the number of bytes left ! * to go into the buffer will actually fit into the ! * buffer. This is calculated as the size of this ! * entry plus: ! * 1 for the true/false list indicator + ! * 1 for the eof indicator ! * times BYTES_PER_XDR_UNIT to convert from from ! * XDR units to bytes. */ ! bufsize += (1 + 1) * BYTES_PER_XDR_UNIT; ! if (bufsize > args->count) { ! kmem_free(data, count); ! resp->status = NFS3ERR_TOOSMALL; ! goto out1; } } ! /* ! * Have a valid readir buffer for the native character ! * set. Need to check if a conversion is necessary and ! * potentially rewrite the whole buffer. Note that if the ! * conversion expands names enough, the structure may not ! * fit. In this case, we need to drop entries until if fits ! * and patch the counts in order that the next readdir will ! * get the correct entries. ! */ ! ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; ! data = nfscmd_convdirent(ca, exi, data, count, &resp->status); VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); #if 0 /* notyet */ /* * Don't do this. It causes local disk writes when just --- 3207,3358 ---- (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); va.va_mask = AT_ALL; vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); if (error) goto out; /* ! * Don't allow arbitrary counts for allocation */ ! if (count > rfs3_tsize(req)) ! count = rfs3_tsize(req); /* + * struct READDIR3resok: + * dir_attributes: 1 + NFS3_SIZEOF_FATTR3 + * cookieverf: 2 + * entries (bool): 1 + * eof: 1 + */ + size = (1 + NFS3_SIZEOF_FATTR3 + 2 + 1 + 1) * BYTES_PER_XDR_UNIT; + + if (size > count) { + resp->status = NFS3ERR_TOOSMALL; + goto out1; + } + + /* + * This is simplification. The dirent64_t size is not the same as the + * size of XDR representation of entry3, but the sizes are similar so + * we'll assume they are same. This assumption should not cause any + * harm. In worst case we will need to issue VOP_READDIR() once more. + */ + datasz = count; + + /* * Make sure that there is room to read at least one entry * if any are available. */ ! if (datasz < DIRENT64_RECLEN(MAXNAMELEN)) ! datasz = DIRENT64_RECLEN(MAXNAMELEN); ! data = kmem_alloc(datasz, KM_NOSLEEP); ! if (data == NULL) { ! /* The allocation failed; downsize and wait for it this time */ ! if (datasz > MAXBSIZE) ! datasz = MAXBSIZE; ! data = kmem_alloc(datasz, KM_SLEEP); ! } uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_extflg = UIO_COPY_CACHED; uio.uio_loffset = (offset_t)args->cookie; ! uio.uio_resid = datasz; ! ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; ! eptr = &resp->resok.reply.entries; ! entry = NULL; ! getmoredents: ! iov.iov_base = data; ! iov.iov_len = datasz; + error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0); if (error) { ! iseof = 0; ! goto done; } ! if (iov.iov_len == datasz) ! goto done; ! ! for (dp = (dirent64_t *)data; (char *)dp - data < datasz - iov.iov_len; ! dp = nextdp(dp)) { ! char *name; ! count3 esize; ! ! if (dp->d_ino == 0) { ! if (entry != NULL) ! entry->cookie = (cookie3)dp->d_off; ! continue; } + + name = nfscmd_convname(ca, exi, dp->d_name, + NFSCMD_CONV_OUTBOUND, MAXPATHLEN + 1); + if (name == NULL) { + if (entry != NULL) + entry->cookie = (cookie3)dp->d_off; + continue; + } + /* ! * struct entry3: ! * fileid: 2 ! * name (length): 1 ! * name (data): length (rounded up) ! * cookie: 2 ! * nextentry (bool): 1 */ ! esize = (2 + 1 + 2 + 1) * BYTES_PER_XDR_UNIT + ! RNDUP(strlen(name)); ! ! /* If the new entry does not fit, discard it */ ! if (esize > count - size) { ! if (name != dp->d_name) ! kmem_free(name, MAXPATHLEN + 1); ! iseof = 0; ! goto done; } + + entry = kmem_alloc(sizeof (entry3), KM_SLEEP); + + entry->fileid = (fileid3)dp->d_ino; + entry->name = strdup(name); + if (name != dp->d_name) + kmem_free(name, MAXPATHLEN + 1); + entry->cookie = (cookie3)dp->d_off; + + size += esize; + + /* Add the entry to the linked list */ + *eptr = entry; + eptr = &entry->nextentry; } ! if (!iseof && size < count) { ! uio.uio_resid = MIN(datasz, MAXBSIZE); ! goto getmoredents; ! } + done: + *eptr = NULL; + va.va_mask = AT_ALL; + vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; + + if (!iseof && resp->resok.reply.entries == NULL) { + if (error) + goto out; + resp->status = NFS3ERR_TOOSMALL; + goto out1; + } + VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); #if 0 /* notyet */ /* * Don't do this. It causes local disk writes when just
*** 3269,3356 **** */ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); #endif resp->status = NFS3_OK; - vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); resp->resok.cookieverf = 0; ! resp->resok.reply.entries = (entry3 *)data; ! resp->resok.reply.eof = iseof; ! resp->resok.size = count - uio.uio_resid; ! resp->resok.count = args->count; ! resp->resok.freecount = count; ! DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READDIR3res *, resp); VN_RELE(vp); return; out: if (curthread->t_flag & T_WOULDBLOCK) { curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READDIR3res *, resp); if (vp != NULL) { VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); VN_RELE(vp); } ! vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); } void * rfs3_readdir_getfh(READDIR3args *args) { - return (&args->dir); } void rfs3_readdir_free(READDIR3res *resp) { ! if (resp->status == NFS3_OK) ! kmem_free(resp->resok.reply.entries, resp->resok.freecount); } #ifdef nextdp #undef nextdp #endif #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) - /* - * This macro computes the size of a response which contains - * one directory entry including the attributes as well as file handle. - * If the incoming request is larger than this, then we are guaranteed to be - * able to return at least one more directory entry if one exists. - * - * NFS3_READDIRPLUS_ENTRY is made up of the following: - * - * boolean - 1 * BYTES_PER_XDR_UNIT - * file id - 2 * BYTES_PER_XDR_UNIT - * directory name length - 1 * BYTES_PER_XDR_UNIT - * cookie - 2 * BYTES_PER_XDR_UNIT - * attribute flag - 1 * BYTES_PER_XDR_UNIT - * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT - * status byte for file handle - 1 * BYTES_PER_XDR_UNIT - * length of a file handle - 1 * BYTES_PER_XDR_UNIT - * Maximum length of a file handle (NFS3_MAXFHSIZE) - * name length of the entry to the nearest bytes - */ - #define NFS3_READDIRPLUS_ENTRY(namelen) \ - ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \ - BYTES_PER_XDR_UNIT + \ - NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT)) - - static int rfs3_readdir_unit = MAXBSIZE; - /* ARGSUSED */ void rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) { --- 3364,3437 ---- */ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); #endif resp->status = NFS3_OK; resp->resok.cookieverf = 0; ! resp->resok.reply.eof = iseof ? TRUE : FALSE; ! vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); + DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req, + cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, + READDIR3res *, resp); + VN_RELE(vp); + if (data != NULL) + kmem_free(data, datasz); + return; out: if (curthread->t_flag & T_WOULDBLOCK) { curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); + DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req, + cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, + READDIR3res *, resp); + if (vp != NULL) { VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); VN_RELE(vp); } ! ! if (data != NULL) ! kmem_free(data, datasz); } void * rfs3_readdir_getfh(READDIR3args *args) { return (&args->dir); } void rfs3_readdir_free(READDIR3res *resp) { + if (resp->status == NFS3_OK) { + entry3 *entry, *nentry; ! for (entry = resp->resok.reply.entries; entry != NULL; ! entry = nentry) { ! nentry = entry->nextentry; ! strfree(entry->name); ! kmem_free(entry, sizeof (entry3)); ! } ! } } #ifdef nextdp #undef nextdp #endif #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) /* ARGSUSED */ void rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) {
*** 3358,3400 **** vnode_t *vp; struct vattr *vap; struct vattr va; struct iovec iov; struct uio uio; - char *data; int iseof; - struct dirent64 *dp; - vnode_t *nvp; - struct vattr *nvap; - struct vattr nva; - entryplus3_info *infop = NULL; - int size = 0; - int nents = 0; - int bufsize = 0; - int entrysize = 0; - int tofit = 0; - int rd_unit = rfs3_readdir_unit; - int prev_len; - int space_left; - int i; - uint_t *namlen = NULL; - char *ndata = NULL; - struct sockaddr *ca; - size_t ret; ! vap = NULL; vp = nfs3_fhtovp(&args->dir, exi); ! DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args); if (vp == NULL) { ! error = ESTALE; ! goto out; } if (is_system_labeled()) { bslabel_t *clabel = req->rq_label; ASSERT(clabel != NULL); DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel, --- 3439,3481 ---- vnode_t *vp; struct vattr *vap; struct vattr va; struct iovec iov; struct uio uio; int iseof; ! count3 dircount = args->dircount; ! count3 maxcount = args->maxcount; ! count3 dirsize = 0; ! count3 size; /* size of the READDIRPLUS3resok structure */ + size_t datasz; + char *data = NULL; + dirent64_t *dp; + + struct sockaddr *ca; + entryplus3 **eptr; + entryplus3 *entry; + vp = nfs3_fhtovp(&args->dir, exi); ! DTRACE_NFSV3_5(op__readdirplus__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! READDIRPLUS3args *, args); if (vp == NULL) { ! resp->status = NFS3ERR_STALE; ! vap = NULL; ! goto out1; } + if (vp->v_type != VDIR) { + resp->status = NFS3ERR_NOTDIR; + vap = NULL; + goto out1; + } + if (is_system_labeled()) { bslabel_t *clabel = req->rq_label; ASSERT(clabel != NULL); DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
*** 3403,3412 **** --- 3484,3494 ---- if (!blequal(&l_admin_low->tsl_label, clabel)) { if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, exi)) { resp->status = NFS3ERR_ACCES; + vap = NULL; goto out1; } } }
*** 3413,3647 **** (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); va.va_mask = AT_ALL; vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; - if (vp->v_type != VDIR) { - error = ENOTDIR; - goto out; - } - error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); if (error) goto out; /* * Don't allow arbitrary counts for allocation */ ! if (args->maxcount > rfs3_tsize(req)) ! args->maxcount = rfs3_tsize(req); /* ! * Make sure that there is room to read at least one entry ! * if any are available */ ! args->dircount = MIN(args->dircount, args->maxcount); ! if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN)) ! args->dircount = DIRENT64_RECLEN(MAXNAMELEN); /* ! * This allocation relies on a minimum directory entry ! * being roughly 24 bytes. Therefore, the namlen array ! * will have enough space based on the maximum number of ! * entries to read. */ - namlen = kmem_alloc(args->dircount, KM_SLEEP); ! space_left = args->dircount; ! data = kmem_alloc(args->dircount, KM_SLEEP); ! dp = (struct dirent64 *)data; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_extflg = UIO_COPY_CACHED; uio.uio_loffset = (offset_t)args->cookie; ! /* ! * bufsize is used to keep track of the size of the response as we ! * get post op attributes and filehandles for each entry. This is ! * an optimization as the server may have read more entries than will ! * fit in the buffer specified by maxcount. We stop calculating ! * post op attributes and filehandles once we have exceeded maxcount. ! * This will minimize the effect of truncation. ! * ! * It is primed with: ! * 1 for the status + ! * 1 for the dir_attributes.attributes boolean + ! * 2 for the cookie verifier ! * all times BYTES_PER_XDR_UNIT to convert from XDR units ! * to bytes. If there are directory attributes to be ! * returned, then: ! * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3 ! * time BYTES_PER_XDR_UNIT is added to account for them. ! */ ! bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT; ! if (vap != NULL) ! bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; getmoredents: ! /* ! * Here we make a check so that our read unit is not larger than ! * the space left in the buffer. ! */ ! rd_unit = MIN(rd_unit, space_left); ! iov.iov_base = (char *)dp; ! iov.iov_len = rd_unit; ! uio.uio_resid = rd_unit; ! prev_len = rd_unit; error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0); - if (error) { ! kmem_free(data, args->dircount); ! goto out; } ! if (uio.uio_resid == prev_len && !iseof) { ! if (nents == 0) { ! kmem_free(data, args->dircount); ! resp->status = NFS3ERR_TOOSMALL; ! goto out1; ! } ! /* ! * We could not get any more entries, so get the attributes ! * and filehandle for the entries already obtained. ! */ ! goto good; ! } - /* - * We estimate the size of the response by assuming the - * entry exists and attributes and filehandle are also valid - */ - for (size = prev_len - uio.uio_resid; - size > 0; - size -= dp->d_reclen, dp = nextdp(dp)) { - if (dp->d_ino == 0) { ! nents++; continue; } ! namlen[nents] = strlen(dp->d_name); ! entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]); /* ! * We need to check to see if the number of bytes left ! * to go into the buffer will actually fit into the ! * buffer. This is calculated as the size of this ! * entry plus: ! * 1 for the true/false list indicator + ! * 1 for the eof indicator ! * times BYTES_PER_XDR_UNIT to convert from XDR units ! * to bytes. ! * ! * Also check the dircount limit against the first entry read ! * */ ! tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT; ! if (bufsize + tofit > args->maxcount) { ! /* ! * We make a check here to see if this was the ! * first entry being measured. If so, then maxcount ! * was too small to begin with and so we need to ! * return with NFS3ERR_TOOSMALL. ! */ ! if (nents == 0) { ! kmem_free(data, args->dircount); ! resp->status = NFS3ERR_TOOSMALL; ! goto out1; ! } ! iseof = FALSE; ! goto good; ! } ! bufsize += entrysize; ! nents++; ! } /* ! * If there is enough room to fit at least 1 more entry including ! * post op attributes and filehandle in the buffer AND that we haven't ! * exceeded dircount then go back and get some more. */ ! if (!iseof && ! (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) { ! space_left -= (prev_len - uio.uio_resid); ! if (space_left >= DIRENT64_RECLEN(MAXNAMELEN)) ! goto getmoredents; ! /* else, fall through */ } - good: - va.va_mask = AT_ALL; - vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; ! VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); ! infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP); ! resp->resok.infop = infop; - dp = (struct dirent64 *)data; - for (i = 0; i < nents; i++) { - - if (dp->d_ino == 0) { - infop[i].attr.attributes = FALSE; - infop[i].fh.handle_follows = FALSE; - dp = nextdp(dp); - continue; - } - - infop[i].namelen = namlen[i]; - error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr, NULL, NULL, NULL); if (error) { ! infop[i].attr.attributes = FALSE; ! infop[i].fh.handle_follows = FALSE; ! dp = nextdp(dp); ! continue; ! } nva.va_mask = AT_ALL; ! nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva; /* Lie about the object type for a referral */ ! if (vn_is_nfs_reparse(nvp, cr)) nvap->va_type = VLNK; ! vattr_to_post_op_attr(nvap, &infop[i].attr); ! error = makefh3(&infop[i].fh.handle, nvp, exi); if (!error) ! infop[i].fh.handle_follows = TRUE; else ! infop[i].fh.handle_follows = FALSE; VN_RELE(nvp); - dp = nextdp(dp); } - ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; - ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata); - if (ndata == NULL) - ndata = data; - - if (ret > 0) { /* ! * We had to drop one or more entries in order to fit ! * during the character conversion. We need to patch ! * up the size and eof info. */ ! if (iseof) ! iseof = FALSE; ! ret = nfscmd_dropped_entrysize((struct dirent64 *)data, ! nents, ret); } #if 0 /* notyet */ /* * Don't do this. It causes local disk writes when just * reading the file and the overhead is deemed larger * than the benefit. --- 3495,3719 ---- (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); va.va_mask = AT_ALL; vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; error = VOP_ACCESS(vp, VREAD, 0, cr, NULL); if (error) goto out; /* * Don't allow arbitrary counts for allocation */ ! if (maxcount > rfs3_tsize(req)) ! maxcount = rfs3_tsize(req); /* ! * struct READDIRPLUS3resok: ! * dir_attributes: 1 + NFS3_SIZEOF_FATTR3 ! * cookieverf: 2 ! * entries (bool): 1 ! * eof: 1 */ ! size = (1 + NFS3_SIZEOF_FATTR3 + 2 + 1 + 1) * BYTES_PER_XDR_UNIT; ! if (size > maxcount) { ! resp->status = NFS3ERR_TOOSMALL; ! goto out1; ! } /* ! * This is simplification. The dirent64_t size is not the same as the ! * size of XDR representation of entryplus3 (excluding attributes and ! * handle), but the sizes are similar so we'll assume they are same. ! * This assumption should not cause any harm. In worst case we will ! * need to issue VOP_READDIR() once more. */ ! datasz = MIN(dircount, maxcount); ! ! /* ! * Make sure that there is room to read at least one entry ! * if any are available. ! */ ! if (datasz < DIRENT64_RECLEN(MAXNAMELEN)) ! datasz = DIRENT64_RECLEN(MAXNAMELEN); ! ! data = kmem_alloc(datasz, KM_NOSLEEP); ! if (data == NULL) { ! /* The allocation failed; downsize and wait for it this time */ ! if (datasz > MAXBSIZE) ! datasz = MAXBSIZE; ! data = kmem_alloc(datasz, KM_SLEEP); ! } ! uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_extflg = UIO_COPY_CACHED; uio.uio_loffset = (offset_t)args->cookie; + uio.uio_resid = datasz; ! ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf; ! eptr = &resp->resok.reply.entries; ! entry = NULL; getmoredents: ! iov.iov_base = data; ! iov.iov_len = datasz; error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0); if (error) { ! iseof = 0; ! goto done; } ! if (iov.iov_len == datasz) ! goto done; ! for (dp = (dirent64_t *)data; (char *)dp - data < datasz - iov.iov_len; ! dp = nextdp(dp)) { ! char *name; ! vnode_t *nvp; ! count3 edirsize; ! count3 esize; if (dp->d_ino == 0) { ! if (entry != NULL) ! entry->cookie = (cookie3)dp->d_off; continue; } ! name = nfscmd_convname(ca, exi, dp->d_name, ! NFSCMD_CONV_OUTBOUND, MAXPATHLEN + 1); ! if (name == NULL) { ! if (entry != NULL) ! entry->cookie = (cookie3)dp->d_off; ! continue; ! } /* ! * struct entryplus3: ! * fileid: 2 ! * name (length): 1 ! * name (data): length (rounded up) ! * cookie: 2 */ ! edirsize = (2 + 1 + 2) * BYTES_PER_XDR_UNIT + ! RNDUP(strlen(name)); /* ! * struct entryplus3: ! * attributes_follow: 1 ! * handle_follows: 1 ! * nextentry (bool): 1 */ ! esize = edirsize + (1 + 1 + 1) * BYTES_PER_XDR_UNIT; ! /* If the new entry does not fit, we are done */ ! if (edirsize > dircount - dirsize || esize > maxcount - size) { ! if (name != dp->d_name) ! kmem_free(name, MAXPATHLEN + 1); ! iseof = 0; ! error = 0; ! goto done; } ! entry = kmem_alloc(sizeof (entryplus3), KM_SLEEP); ! entry->fileid = (fileid3)dp->d_ino; ! entry->name = strdup(name); ! if (name != dp->d_name) ! kmem_free(name, MAXPATHLEN + 1); ! entry->cookie = (cookie3)dp->d_off; error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr, NULL, NULL, NULL); if (error) { ! entry->name_attributes.attributes = FALSE; ! entry->name_handle.handle_follows = FALSE; ! } else { ! struct vattr nva; ! struct vattr *nvap; nva.va_mask = AT_ALL; ! nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : ! &nva; /* Lie about the object type for a referral */ ! if (nvap != NULL && vn_is_nfs_reparse(nvp, cr)) nvap->va_type = VLNK; ! if (vn_ismntpt(nvp)) { ! entry->name_attributes.attributes = FALSE; ! entry->name_handle.handle_follows = FALSE; ! } else { ! vattr_to_post_op_attr(nvap, ! &entry->name_attributes); ! error = makefh3(&entry->name_handle.handle, nvp, ! exi); if (!error) ! entry->name_handle.handle_follows = ! TRUE; else ! entry->name_handle.handle_follows = ! FALSE; ! } VN_RELE(nvp); } /* ! * struct entryplus3 (optionally): ! * attributes: NFS3_SIZEOF_FATTR3 ! * handle length: 1 ! * handle data: length (rounded up) */ ! if (entry->name_attributes.attributes == TRUE) ! esize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; ! if (entry->name_handle.handle_follows == TRUE) ! esize += 1 * BYTES_PER_XDR_UNIT + ! RNDUP(entry->name_handle.handle.fh3_length); ! /* If the new entry does not fit, discard it */ ! if (esize > maxcount - size) { ! strfree(entry->name); ! kmem_free(entry, sizeof (entryplus3)); ! iseof = 0; ! error = 0; ! goto done; } + dirsize += edirsize; + size += esize; + /* Add the entry to the linked list */ + *eptr = entry; + eptr = &entry->nextentry; + } + + if (!iseof && dirsize < dircount && size < maxcount) { + uio.uio_resid = MIN(datasz, MAXBSIZE); + goto getmoredents; + } + + done: + *eptr = NULL; + + va.va_mask = AT_ALL; + vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va; + + if (!iseof && resp->resok.reply.entries == NULL) { + if (error) + goto out; + resp->status = NFS3ERR_TOOSMALL; + goto out1; + } + + VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); + #if 0 /* notyet */ /* * Don't do this. It causes local disk writes when just * reading the file and the overhead is deemed larger * than the benefit.
*** 3650,3678 **** * Force modified metadata out to stable storage. */ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); #endif - kmem_free(namlen, args->dircount); - resp->status = NFS3_OK; - vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); resp->resok.cookieverf = 0; ! resp->resok.reply.entries = (entryplus3 *)ndata; ! resp->resok.reply.eof = iseof; ! resp->resok.size = nents; ! resp->resok.count = args->dircount - ret; ! resp->resok.maxcount = args->maxcount; ! DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp); ! if (ndata != data) ! kmem_free(data, args->dircount); VN_RELE(vp); return; out: if (curthread->t_flag & T_WOULDBLOCK) { curthread->t_flag &= ~T_WOULDBLOCK; --- 3722,3746 ---- * Force modified metadata out to stable storage. */ (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL); #endif resp->status = NFS3_OK; resp->resok.cookieverf = 0; ! resp->resok.reply.eof = iseof ? TRUE : FALSE; ! vattr_to_post_op_attr(vap, &resp->resok.dir_attributes); + DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req, + cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, + READDIRPLUS3res *, resp); VN_RELE(vp); + if (data != NULL) + kmem_free(data, datasz); + return; out: if (curthread->t_flag & T_WOULDBLOCK) { curthread->t_flag &= ~T_WOULDBLOCK;
*** 3679,3718 **** resp->status = NFS3ERR_JUKEBOX; } else { resp->status = puterrno3(error); } out1: ! DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp); if (vp != NULL) { VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); VN_RELE(vp); } ! if (namlen != NULL) ! kmem_free(namlen, args->dircount); ! ! vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); } void * rfs3_readdirplus_getfh(READDIRPLUS3args *args) { - return (&args->dir); } void rfs3_readdirplus_free(READDIRPLUS3res *resp) { - if (resp->status == NFS3_OK) { ! kmem_free(resp->resok.reply.entries, resp->resok.count); ! kmem_free(resp->resok.infop, ! resp->resok.size * sizeof (struct entryplus3_info)); } } /* ARGSUSED */ void rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi, --- 3747,3790 ---- resp->status = NFS3ERR_JUKEBOX; } else { resp->status = puterrno3(error); } out1: ! vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes); + DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req, + cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, + READDIRPLUS3res *, resp); + if (vp != NULL) { VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); VN_RELE(vp); } ! if (data != NULL) ! kmem_free(data, datasz); } void * rfs3_readdirplus_getfh(READDIRPLUS3args *args) { return (&args->dir); } void rfs3_readdirplus_free(READDIRPLUS3res *resp) { if (resp->status == NFS3_OK) { ! entryplus3 *entry, *nentry; ! ! for (entry = resp->resok.reply.entries; entry != NULL; ! entry = nentry) { ! nentry = entry->nextentry; ! strfree(entry->name); ! kmem_free(entry, sizeof (entryplus3)); } + } } /* ARGSUSED */ void rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
*** 3726,3737 **** vap = NULL; vp = nfs3_fhtovp(&args->fsroot, exi); ! DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args); if (vp == NULL) { error = ESTALE; goto out; } --- 3798,3810 ---- vap = NULL; vp = nfs3_fhtovp(&args->fsroot, exi); ! DTRACE_NFSV3_5(op__fsstat__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! FSSTAT3args *, args); if (vp == NULL) { error = ESTALE; goto out; }
*** 3777,3788 **** resp->resok.tfiles = (size3)sb.f_files; resp->resok.ffiles = (size3)sb.f_ffree; resp->resok.afiles = (size3)sb.f_favail; resp->resok.invarsec = 0; ! DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp); VN_RELE(vp); return; out: --- 3850,3862 ---- resp->resok.tfiles = (size3)sb.f_files; resp->resok.ffiles = (size3)sb.f_ffree; resp->resok.afiles = (size3)sb.f_favail; resp->resok.invarsec = 0; ! DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! FSSTAT3res *, resp); VN_RELE(vp); return; out:
*** 3790,3811 **** curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp); if (vp != NULL) VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); } void * rfs3_fsstat_getfh(FSSTAT3args *args) { - return (&args->fsroot); } /* ARGSUSED */ void --- 3864,3885 ---- curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! FSSTAT3res *, resp); if (vp != NULL) VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); } void * rfs3_fsstat_getfh(FSSTAT3args *args) { return (&args->fsroot); } /* ARGSUSED */ void
*** 3819,3830 **** ulong_t l = 0; int error; vp = nfs3_fhtovp(&args->fsroot, exi); ! DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, FSINFO3args *, args); if (vp == NULL) { if (curthread->t_flag & T_WOULDBLOCK) { curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; --- 3893,3905 ---- ulong_t l = 0; int error; vp = nfs3_fhtovp(&args->fsroot, exi); ! DTRACE_NFSV3_5(op__fsinfo__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! FSINFO3args *, args); if (vp == NULL) { if (curthread->t_flag & T_WOULDBLOCK) { curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX;
*** 3894,3913 **** resp->resok.time_delta.seconds = 0; resp->resok.time_delta.nseconds = 1000; resp->resok.properties = FSF3_LINK | FSF3_SYMLINK | FSF3_HOMOGENEOUS | FSF3_CANSETTIME; ! DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp); VN_RELE(vp); return; out: ! DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp); if (vp != NULL) VN_RELE(vp); } void * --- 3969,3990 ---- resp->resok.time_delta.seconds = 0; resp->resok.time_delta.nseconds = 1000; resp->resok.properties = FSF3_LINK | FSF3_SYMLINK | FSF3_HOMOGENEOUS | FSF3_CANSETTIME; ! DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! FSINFO3res *, resp); VN_RELE(vp); return; out: ! DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi, ! FSINFO3res *, resp); if (vp != NULL) VN_RELE(vp); } void *
*** 3929,3940 **** vap = NULL; vp = nfs3_fhtovp(&args->object, exi); ! DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args); if (vp == NULL) { error = ESTALE; goto out; } --- 4006,4018 ---- vap = NULL; vp = nfs3_fhtovp(&args->object, exi); ! DTRACE_NFSV3_5(op__pathconf__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! PATHCONF3args *, args); if (vp == NULL) { error = ESTALE; goto out; }
*** 3986,3997 **** resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); resp->resok.info.case_insensitive = FALSE; resp->resok.info.case_preserving = TRUE; ! DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp); VN_RELE(vp); return; out: if (curthread->t_flag & T_WOULDBLOCK) { --- 4064,4076 ---- resp->status = NFS3_OK; vattr_to_post_op_attr(vap, &resp->resok.obj_attributes); resp->resok.info.case_insensitive = FALSE; resp->resok.info.case_preserving = TRUE; ! DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! PATHCONF3res *, resp); VN_RELE(vp); return; out: if (curthread->t_flag & T_WOULDBLOCK) {
*** 3998,4025 **** curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp); if (vp != NULL) VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); } void * rfs3_pathconf_getfh(PATHCONF3args *args) { - return (&args->object); } void rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) { int error; vnode_t *vp; struct vattr *bvap; struct vattr bva; struct vattr *avap; --- 4077,4105 ---- curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! PATHCONF3res *, resp); if (vp != NULL) VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); } void * rfs3_pathconf_getfh(PATHCONF3args *args) { return (&args->object); } void rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro) { + nfs3_srv_t *ns; int error; vnode_t *vp; struct vattr *bvap; struct vattr bva; struct vattr *avap;
*** 4028,4045 **** bvap = NULL; avap = NULL; vp = nfs3_fhtovp(&args->file, exi); ! DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, COMMIT3args *, args); if (vp == NULL) { error = ESTALE; goto out; } bva.va_mask = AT_ALL; error = VOP_GETATTR(vp, &bva, 0, cr, NULL); /* * If we can't get the attributes, then we can't do the --- 4108,4127 ---- bvap = NULL; avap = NULL; vp = nfs3_fhtovp(&args->file, exi); ! DTRACE_NFSV3_5(op__commit__start, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! COMMIT3args *, args); if (vp == NULL) { error = ESTALE; goto out; } + ns = zone_getspecific(rfs3_zone_key, curzone); bva.va_mask = AT_ALL; error = VOP_GETATTR(vp, &bva, 0, cr, NULL); /* * If we can't get the attributes, then we can't do the
*** 4088,4101 **** if (error) goto out; resp->status = NFS3_OK; vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); ! resp->resok.verf = write3verf; ! DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp); VN_RELE(vp); return; --- 4170,4184 ---- if (error) goto out; resp->status = NFS3_OK; vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc); ! resp->resok.verf = ns->write3verf; ! DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! COMMIT3res *, resp); VN_RELE(vp); return;
*** 4104,4125 **** curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp); if (vp != NULL) VN_RELE(vp); vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); } void * rfs3_commit_getfh(COMMIT3args *args) { - return (&args->file); } static int sattr3_to_vattr(sattr3 *sap, struct vattr *vap) --- 4187,4208 ---- curthread->t_flag &= ~T_WOULDBLOCK; resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); out1: ! DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req, ! cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi, ! COMMIT3res *, resp); if (vp != NULL) VN_RELE(vp); vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc); } void * rfs3_commit_getfh(COMMIT3args *args) { return (&args->file); } static int sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
*** 4183,4193 **** } return (0); } ! static ftype3 vt_to_nf3[] = { 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0 }; static int vattr_to_fattr3(struct vattr *vap, fattr3 *fap) --- 4266,4276 ---- } return (0); } ! static const ftype3 vt_to_nf3[] = { 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0 }; static int vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
*** 4265,4288 **** } static void vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp) { - vattr_to_pre_op_attr(bvap, &wccp->before); vattr_to_post_op_attr(avap, &wccp->after); } ! void ! rfs3_srvrinit(void) { struct rfs3_verf_overlay { uint_t id; /* a "unique" identifier */ int ts; /* a unique timestamp */ } *verfp; timestruc_t now; /* * The following algorithm attempts to find a unique verifier * to be used as the write verifier returned from the server * to the client. It is important that this verifier change * whenever the server reboots. Of secondary importance, it --- 4348,4391 ---- } static void vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp) { vattr_to_pre_op_attr(bvap, &wccp->before); vattr_to_post_op_attr(avap, &wccp->after); } ! static int ! rdma_setup_read_data3(READ3args *args, READ3resok *rok) { + struct clist *wcl; + int wlist_len; + count3 count = rok->count; + + wcl = args->wlist; + if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) + return (FALSE); + + wcl = args->wlist; + rok->wlist_len = wlist_len; + rok->wlist = wcl; + return (TRUE); + } + + /* ARGSUSED */ + static void * + rfs3_zone_init(zoneid_t zoneid) + { + nfs3_srv_t *ns; struct rfs3_verf_overlay { uint_t id; /* a "unique" identifier */ int ts; /* a unique timestamp */ } *verfp; timestruc_t now; + ns = kmem_zalloc(sizeof (*ns), KM_SLEEP); + /* * The following algorithm attempts to find a unique verifier * to be used as the write verifier returned from the server * to the client. It is important that this verifier change * whenever the server reboots. Of secondary importance, it
*** 4302,4342 **** #ifndef lint /* * We ASSERT that this constant logic expression is * always true because in the past, it wasn't. */ ! ASSERT(sizeof (*verfp) <= sizeof (write3verf)); #endif gethrestime(&now); ! verfp = (struct rfs3_verf_overlay *)&write3verf; verfp->ts = (int)now.tv_sec; verfp->id = zone_get_hostid(NULL); if (verfp->id == 0) verfp->id = (uint_t)now.tv_nsec; ! nfs3_srv_caller_id = fs_new_caller_id(); ! } ! static int ! rdma_setup_read_data3(READ3args *args, READ3resok *rok) { ! struct clist *wcl; ! int wlist_len; ! count3 count = rok->count; ! wcl = args->wlist; ! if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) { ! return (FALSE); ! } ! wcl = args->wlist; ! rok->wlist_len = wlist_len; ! rok->wlist = wcl; ! return (TRUE); } void rfs3_srvrfini(void) { --- 4405,4442 ---- #ifndef lint /* * We ASSERT that this constant logic expression is * always true because in the past, it wasn't. */ ! ASSERT(sizeof (*verfp) <= sizeof (ns->write3verf)); #endif gethrestime(&now); ! verfp = (struct rfs3_verf_overlay *)&ns->write3verf; verfp->ts = (int)now.tv_sec; verfp->id = zone_get_hostid(NULL); if (verfp->id == 0) verfp->id = (uint_t)now.tv_nsec; ! return (ns); } ! /* ARGSUSED */ ! static void ! rfs3_zone_fini(zoneid_t zoneid, void *data) { ! nfs3_srv_t *ns = data; ! kmem_free(ns, sizeof (*ns)); ! } ! void ! rfs3_srvrinit(void) ! { ! nfs3_srv_caller_id = fs_new_caller_id(); ! zone_key_create(&rfs3_zone_key, rfs3_zone_init, NULL, rfs3_zone_fini); } void rfs3_srvrfini(void) {