10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51610Sthurlow * Common Development and Distribution License (the "License").
61610Sthurlow * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*13002SKaren.Rochford@Sun.COM * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
260Sstevel@tonic-gate /* All Rights Reserved */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/cred.h>
320Sstevel@tonic-gate #include <sys/buf.h>
330Sstevel@tonic-gate #include <sys/vfs.h>
340Sstevel@tonic-gate #include <sys/vnode.h>
350Sstevel@tonic-gate #include <sys/uio.h>
360Sstevel@tonic-gate #include <sys/errno.h>
370Sstevel@tonic-gate #include <sys/sysmacros.h>
380Sstevel@tonic-gate #include <sys/statvfs.h>
390Sstevel@tonic-gate #include <sys/kmem.h>
400Sstevel@tonic-gate #include <sys/dirent.h>
410Sstevel@tonic-gate #include <sys/cmn_err.h>
420Sstevel@tonic-gate #include <sys/debug.h>
430Sstevel@tonic-gate #include <sys/systeminfo.h>
440Sstevel@tonic-gate #include <sys/flock.h>
450Sstevel@tonic-gate #include <sys/nbmlock.h>
460Sstevel@tonic-gate #include <sys/policy.h>
474971Sjarrett #include <sys/sdt.h>
480Sstevel@tonic-gate
490Sstevel@tonic-gate #include <rpc/types.h>
500Sstevel@tonic-gate #include <rpc/auth.h>
510Sstevel@tonic-gate #include <rpc/svc.h>
527387SRobert.Gordon@Sun.COM #include <rpc/rpc_rdma.h>
530Sstevel@tonic-gate
540Sstevel@tonic-gate #include <nfs/nfs.h>
550Sstevel@tonic-gate #include <nfs/export.h>
567961SNatalie.Li@Sun.COM #include <nfs/nfs_cmd.h>
570Sstevel@tonic-gate
580Sstevel@tonic-gate #include <sys/strsubr.h>
590Sstevel@tonic-gate
604971Sjarrett #include <sys/tsol/label.h>
614971Sjarrett #include <sys/tsol/tndb.h>
624971Sjarrett
638662SJordan.Vaughan@Sun.com #include <sys/zone.h>
648662SJordan.Vaughan@Sun.com
654971Sjarrett #include <inet/ip.h>
664971Sjarrett #include <inet/ip6.h>
674971Sjarrett
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate * These are the interface routines for the server side of the
700Sstevel@tonic-gate * Network File System. See the NFS version 3 protocol specification
710Sstevel@tonic-gate * for a description of this interface.
720Sstevel@tonic-gate */
730Sstevel@tonic-gate
740Sstevel@tonic-gate #ifdef DEBUG
750Sstevel@tonic-gate int rfs3_do_pre_op_attr = 1;
760Sstevel@tonic-gate int rfs3_do_post_op_attr = 1;
770Sstevel@tonic-gate int rfs3_do_post_op_fh3 = 1;
780Sstevel@tonic-gate #endif
790Sstevel@tonic-gate
800Sstevel@tonic-gate static writeverf3 write3verf;
810Sstevel@tonic-gate
820Sstevel@tonic-gate static int sattr3_to_vattr(sattr3 *, struct vattr *);
830Sstevel@tonic-gate static int vattr_to_fattr3(struct vattr *, fattr3 *);
840Sstevel@tonic-gate static int vattr_to_wcc_attr(struct vattr *, wcc_attr *);
850Sstevel@tonic-gate static void vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
860Sstevel@tonic-gate static void vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
877387SRobert.Gordon@Sun.COM static int rdma_setup_read_data3(READ3args *, READ3resok *);
880Sstevel@tonic-gate
8911539SChunli.Zhang@Sun.COM extern int nfs_loaned_buffers;
9011539SChunli.Zhang@Sun.COM
915599Sjwahlig u_longlong_t nfs3_srv_caller_id;
925599Sjwahlig
930Sstevel@tonic-gate /* ARGSUSED */
940Sstevel@tonic-gate void
rfs3_getattr(GETATTR3args * args,GETATTR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)950Sstevel@tonic-gate rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
960Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
970Sstevel@tonic-gate {
980Sstevel@tonic-gate int error;
990Sstevel@tonic-gate vnode_t *vp;
1000Sstevel@tonic-gate struct vattr va;
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate vp = nfs3_fhtovp(&args->object, exi);
1035982Sahl
1045982Sahl DTRACE_NFSV3_4(op__getattr__start, struct svc_req *, req,
1055982Sahl cred_t *, cr, vnode_t *, vp, GETATTR3args *, args);
1065982Sahl
1070Sstevel@tonic-gate if (vp == NULL) {
1080Sstevel@tonic-gate error = ESTALE;
1090Sstevel@tonic-gate goto out;
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate va.va_mask = AT_ALL;
1130Sstevel@tonic-gate error = rfs4_delegated_getattr(vp, &va, 0, cr);
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate if (!error) {
11611291SRobert.Thurlow@Sun.COM /* Lie about the object type for a referral */
11711291SRobert.Thurlow@Sun.COM if (vn_is_nfs_reparse(vp, cr))
11811291SRobert.Thurlow@Sun.COM va.va_type = VLNK;
11911291SRobert.Thurlow@Sun.COM
1200Sstevel@tonic-gate /* overflow error if time or size is out of range */
1210Sstevel@tonic-gate error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
1220Sstevel@tonic-gate if (error)
1230Sstevel@tonic-gate goto out;
1240Sstevel@tonic-gate resp->status = NFS3_OK;
1255982Sahl
1265982Sahl DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
1275982Sahl cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
1285982Sahl
1295982Sahl VN_RELE(vp);
1305982Sahl
1310Sstevel@tonic-gate return;
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate out:
1350Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
1360Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
1370Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
1380Sstevel@tonic-gate } else
1390Sstevel@tonic-gate resp->status = puterrno3(error);
1405982Sahl
1415982Sahl DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
1425982Sahl cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
1435982Sahl
1445982Sahl if (vp != NULL)
1455982Sahl VN_RELE(vp);
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate
1481610Sthurlow void *
rfs3_getattr_getfh(GETATTR3args * args)1490Sstevel@tonic-gate rfs3_getattr_getfh(GETATTR3args *args)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate
1521610Sthurlow return (&args->object);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate void
rfs3_setattr(SETATTR3args * args,SETATTR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)1560Sstevel@tonic-gate rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
1570Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate int error;
1600Sstevel@tonic-gate vnode_t *vp;
1610Sstevel@tonic-gate struct vattr *bvap;
1620Sstevel@tonic-gate struct vattr bva;
1630Sstevel@tonic-gate struct vattr *avap;
1640Sstevel@tonic-gate struct vattr ava;
1650Sstevel@tonic-gate int flag;
1660Sstevel@tonic-gate int in_crit = 0;
1670Sstevel@tonic-gate struct flock64 bf;
1685599Sjwahlig caller_context_t ct;
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate bvap = NULL;
1710Sstevel@tonic-gate avap = NULL;
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate vp = nfs3_fhtovp(&args->object, exi);
1745982Sahl
1755982Sahl DTRACE_NFSV3_4(op__setattr__start, struct svc_req *, req,
1765982Sahl cred_t *, cr, vnode_t *, vp, SETATTR3args *, args);
1775982Sahl
1780Sstevel@tonic-gate if (vp == NULL) {
1790Sstevel@tonic-gate error = ESTALE;
1800Sstevel@tonic-gate goto out;
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate error = sattr3_to_vattr(&args->new_attributes, &ava);
1840Sstevel@tonic-gate if (error)
1850Sstevel@tonic-gate goto out;
1860Sstevel@tonic-gate
1874971Sjarrett if (is_system_labeled()) {
1884971Sjarrett bslabel_t *clabel = req->rq_label;
1894971Sjarrett
1904971Sjarrett ASSERT(clabel != NULL);
1914971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
1924971Sjarrett "got client label from request(1)", struct svc_req *, req);
1934971Sjarrett
1944971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
1959871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1969871SJarrett.Lu@Sun.COM exi)) {
1974971Sjarrett resp->status = NFS3ERR_ACCES;
1984971Sjarrett goto out1;
1994971Sjarrett }
2004971Sjarrett }
2014971Sjarrett }
2024971Sjarrett
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate * We need to specially handle size changes because of
2050Sstevel@tonic-gate * possible conflicting NBMAND locks. Get into critical
2060Sstevel@tonic-gate * region before VOP_GETATTR, so the size attribute is
2070Sstevel@tonic-gate * valid when checking conflicts.
2080Sstevel@tonic-gate *
2090Sstevel@tonic-gate * Also, check to see if the v4 side of the server has
2100Sstevel@tonic-gate * delegated this file. If so, then we return JUKEBOX to
2110Sstevel@tonic-gate * allow the client to retrasmit its request.
2120Sstevel@tonic-gate */
2130Sstevel@tonic-gate if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
2140Sstevel@tonic-gate if (nbl_need_check(vp)) {
2150Sstevel@tonic-gate nbl_start_crit(vp, RW_READER);
2160Sstevel@tonic-gate in_crit = 1;
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate bva.va_mask = AT_ALL;
2210Sstevel@tonic-gate error = rfs4_delegated_getattr(vp, &bva, 0, cr);
2220Sstevel@tonic-gate
2230Sstevel@tonic-gate /*
2240Sstevel@tonic-gate * If we can't get the attributes, then we can't do the
2250Sstevel@tonic-gate * right access checking. So, we'll fail the request.
2260Sstevel@tonic-gate */
2270Sstevel@tonic-gate if (error)
2280Sstevel@tonic-gate goto out;
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate #ifdef DEBUG
2310Sstevel@tonic-gate if (rfs3_do_pre_op_attr)
2320Sstevel@tonic-gate bvap = &bva;
2330Sstevel@tonic-gate #else
2340Sstevel@tonic-gate bvap = &bva;
2350Sstevel@tonic-gate #endif
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate if (rdonly(exi, req) || vn_is_readonly(vp)) {
2380Sstevel@tonic-gate resp->status = NFS3ERR_ROFS;
2390Sstevel@tonic-gate goto out1;
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate if (args->guard.check &&
2430Sstevel@tonic-gate (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec ||
2440Sstevel@tonic-gate args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) {
2450Sstevel@tonic-gate resp->status = NFS3ERR_NOT_SYNC;
2460Sstevel@tonic-gate goto out1;
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME)
2500Sstevel@tonic-gate flag = ATTR_UTIME;
2510Sstevel@tonic-gate else
2520Sstevel@tonic-gate flag = 0;
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate * If the filesystem is exported with nosuid, then mask off
2560Sstevel@tonic-gate * the setuid and setgid bits.
2570Sstevel@tonic-gate */
2580Sstevel@tonic-gate if ((ava.va_mask & AT_MODE) && vp->v_type == VREG &&
2590Sstevel@tonic-gate (exi->exi_export.ex_flags & EX_NOSUID))
2600Sstevel@tonic-gate ava.va_mode &= ~(VSUID | VSGID);
2610Sstevel@tonic-gate
2625599Sjwahlig ct.cc_sysid = 0;
2635599Sjwahlig ct.cc_pid = 0;
2645599Sjwahlig ct.cc_caller_id = nfs3_srv_caller_id;
2655599Sjwahlig ct.cc_flags = CC_DONTBLOCK;
2665599Sjwahlig
2670Sstevel@tonic-gate /*
2680Sstevel@tonic-gate * We need to specially handle size changes because it is
2690Sstevel@tonic-gate * possible for the client to create a file with modes
2700Sstevel@tonic-gate * which indicate read-only, but with the file opened for
2710Sstevel@tonic-gate * writing. If the client then tries to set the size of
2720Sstevel@tonic-gate * the file, then the normal access checking done in
2730Sstevel@tonic-gate * VOP_SETATTR would prevent the client from doing so,
2740Sstevel@tonic-gate * although it should be legal for it to do so. To get
2750Sstevel@tonic-gate * around this, we do the access checking for ourselves
2760Sstevel@tonic-gate * and then use VOP_SPACE which doesn't do the access
2770Sstevel@tonic-gate * checking which VOP_SETATTR does. VOP_SPACE can only
2780Sstevel@tonic-gate * operate on VREG files, let VOP_SETATTR handle the other
2790Sstevel@tonic-gate * extremely rare cases.
2800Sstevel@tonic-gate * Also the client should not be allowed to change the
2810Sstevel@tonic-gate * size of the file if there is a conflicting non-blocking
2820Sstevel@tonic-gate * mandatory lock in the region the change.
2830Sstevel@tonic-gate */
2840Sstevel@tonic-gate if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
2850Sstevel@tonic-gate if (in_crit) {
2860Sstevel@tonic-gate u_offset_t offset;
2870Sstevel@tonic-gate ssize_t length;
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate if (ava.va_size < bva.va_size) {
2900Sstevel@tonic-gate offset = ava.va_size;
2910Sstevel@tonic-gate length = bva.va_size - ava.va_size;
2920Sstevel@tonic-gate } else {
2930Sstevel@tonic-gate offset = bva.va_size;
2940Sstevel@tonic-gate length = ava.va_size - bva.va_size;
2950Sstevel@tonic-gate }
2965331Samw if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
2975331Samw NULL)) {
2980Sstevel@tonic-gate error = EACCES;
2990Sstevel@tonic-gate goto out;
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate if (crgetuid(cr) == bva.va_uid && ava.va_size != bva.va_size) {
3040Sstevel@tonic-gate ava.va_mask &= ~AT_SIZE;
3050Sstevel@tonic-gate bf.l_type = F_WRLCK;
3060Sstevel@tonic-gate bf.l_whence = 0;
3070Sstevel@tonic-gate bf.l_start = (off64_t)ava.va_size;
3080Sstevel@tonic-gate bf.l_len = 0;
3090Sstevel@tonic-gate bf.l_sysid = 0;
3100Sstevel@tonic-gate bf.l_pid = 0;
3110Sstevel@tonic-gate error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
3125599Sjwahlig (offset_t)ava.va_size, cr, &ct);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate if (!error && ava.va_mask)
3175599Sjwahlig error = VOP_SETATTR(vp, &ava, flag, cr, &ct);
3185599Sjwahlig
3195599Sjwahlig /* check if a monitor detected a delegation conflict */
3205599Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
3215599Sjwahlig resp->status = NFS3ERR_JUKEBOX;
3225599Sjwahlig goto out1;
3235599Sjwahlig }
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate #ifdef DEBUG
3260Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
3270Sstevel@tonic-gate ava.va_mask = AT_ALL;
3280Sstevel@tonic-gate avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
3290Sstevel@tonic-gate } else
3300Sstevel@tonic-gate avap = NULL;
3310Sstevel@tonic-gate #else
3320Sstevel@tonic-gate ava.va_mask = AT_ALL;
3330Sstevel@tonic-gate avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
3340Sstevel@tonic-gate #endif
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate /*
3370Sstevel@tonic-gate * Force modified metadata out to stable storage.
3380Sstevel@tonic-gate */
3395599Sjwahlig (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate if (error)
3420Sstevel@tonic-gate goto out;
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate if (in_crit)
3450Sstevel@tonic-gate nbl_end_crit(vp);
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate resp->status = NFS3_OK;
3480Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
3495982Sahl
3505982Sahl DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
3515982Sahl cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
3525982Sahl
3535982Sahl VN_RELE(vp);
3545982Sahl
3550Sstevel@tonic-gate return;
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate out:
3580Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
3590Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
3600Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
3610Sstevel@tonic-gate } else
3620Sstevel@tonic-gate resp->status = puterrno3(error);
3630Sstevel@tonic-gate out1:
3645982Sahl DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
3655982Sahl cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
3665982Sahl
3670Sstevel@tonic-gate if (vp != NULL) {
3680Sstevel@tonic-gate if (in_crit)
3690Sstevel@tonic-gate nbl_end_crit(vp);
3700Sstevel@tonic-gate VN_RELE(vp);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate
3751610Sthurlow void *
rfs3_setattr_getfh(SETATTR3args * args)3760Sstevel@tonic-gate rfs3_setattr_getfh(SETATTR3args *args)
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate
3791610Sthurlow return (&args->object);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate /* ARGSUSED */
3830Sstevel@tonic-gate void
rfs3_lookup(LOOKUP3args * args,LOOKUP3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)3840Sstevel@tonic-gate rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
3850Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate int error;
3880Sstevel@tonic-gate vnode_t *vp;
3890Sstevel@tonic-gate vnode_t *dvp;
3900Sstevel@tonic-gate struct vattr *vap;
3910Sstevel@tonic-gate struct vattr va;
3920Sstevel@tonic-gate struct vattr *dvap;
3930Sstevel@tonic-gate struct vattr dva;
3940Sstevel@tonic-gate nfs_fh3 *fhp;
3950Sstevel@tonic-gate struct sec_ol sec = {0, 0};
3960Sstevel@tonic-gate bool_t publicfh_flag = FALSE, auth_weak = FALSE;
3977961SNatalie.Li@Sun.COM struct sockaddr *ca;
3987961SNatalie.Li@Sun.COM char *name = NULL;
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate dvap = NULL;
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate * Allow lookups from the root - the default
4040Sstevel@tonic-gate * location of the public filehandle.
4050Sstevel@tonic-gate */
4060Sstevel@tonic-gate if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
4070Sstevel@tonic-gate dvp = rootdir;
4080Sstevel@tonic-gate VN_HOLD(dvp);
4095982Sahl
4105982Sahl DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
4115982Sahl cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
4120Sstevel@tonic-gate } else {
4131610Sthurlow dvp = nfs3_fhtovp(&args->what.dir, exi);
4145982Sahl
4155982Sahl DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
4165982Sahl cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
4175982Sahl
4180Sstevel@tonic-gate if (dvp == NULL) {
4190Sstevel@tonic-gate error = ESTALE;
4200Sstevel@tonic-gate goto out;
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate #ifdef DEBUG
4250Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
4260Sstevel@tonic-gate dva.va_mask = AT_ALL;
4275331Samw dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate #else
4300Sstevel@tonic-gate dva.va_mask = AT_ALL;
4315331Samw dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
4320Sstevel@tonic-gate #endif
4330Sstevel@tonic-gate
4340Sstevel@tonic-gate if (args->what.name == nfs3nametoolong) {
4350Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG;
4360Sstevel@tonic-gate goto out1;
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate if (args->what.name == NULL || *(args->what.name) == '\0') {
4400Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
4410Sstevel@tonic-gate goto out1;
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate
4441610Sthurlow fhp = &args->what.dir;
4450Sstevel@tonic-gate if (strcmp(args->what.name, "..") == 0 &&
4461610Sthurlow EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
4470Sstevel@tonic-gate resp->status = NFS3ERR_NOENT;
4480Sstevel@tonic-gate goto out1;
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate
4517961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
4527961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, args->what.name,
4537961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
4547961SNatalie.Li@Sun.COM
4557961SNatalie.Li@Sun.COM if (name == NULL) {
4567961SNatalie.Li@Sun.COM resp->status = NFS3ERR_ACCES;
4577961SNatalie.Li@Sun.COM goto out1;
4587961SNatalie.Li@Sun.COM }
4597961SNatalie.Li@Sun.COM
4600Sstevel@tonic-gate /*
4610Sstevel@tonic-gate * If the public filehandle is used then allow
4620Sstevel@tonic-gate * a multi-component lookup
4630Sstevel@tonic-gate */
4641610Sthurlow if (PUBLIC_FH3(&args->what.dir)) {
4650Sstevel@tonic-gate publicfh_flag = TRUE;
4667961SNatalie.Li@Sun.COM error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
4675599Sjwahlig &exi, &sec);
4680Sstevel@tonic-gate if (error && exi != NULL)
4694971Sjarrett exi_rele(exi); /* See comment below Re: publicfh_flag */
4704971Sjarrett /*
4714971Sjarrett * Since WebNFS may bypass MOUNT, we need to ensure this
4724971Sjarrett * request didn't come from an unlabeled admin_low client.
4734971Sjarrett */
4744971Sjarrett if (is_system_labeled() && error == 0) {
4754971Sjarrett int addr_type;
4764971Sjarrett void *ipaddr;
4774971Sjarrett tsol_tpc_t *tp;
4784971Sjarrett
4794971Sjarrett if (ca->sa_family == AF_INET) {
4804971Sjarrett addr_type = IPV4_VERSION;
4814971Sjarrett ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
4824971Sjarrett } else if (ca->sa_family == AF_INET6) {
4834971Sjarrett addr_type = IPV6_VERSION;
4844971Sjarrett ipaddr = &((struct sockaddr_in6 *)
4854971Sjarrett ca)->sin6_addr;
4864971Sjarrett }
4874971Sjarrett tp = find_tpc(ipaddr, addr_type, B_FALSE);
4884971Sjarrett if (tp == NULL || tp->tpc_tp.tp_doi !=
4894971Sjarrett l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
4904971Sjarrett SUN_CIPSO) {
4914971Sjarrett if (exi != NULL)
4924971Sjarrett exi_rele(exi);
4934971Sjarrett VN_RELE(vp);
4944971Sjarrett resp->status = NFS3ERR_ACCES;
4954971Sjarrett error = 1;
4964971Sjarrett }
4974971Sjarrett if (tp != NULL)
4984971Sjarrett TPC_RELE(tp);
4994971Sjarrett }
5000Sstevel@tonic-gate } else {
5017961SNatalie.Li@Sun.COM error = VOP_LOOKUP(dvp, name, &vp,
5025599Sjwahlig NULL, 0, NULL, cr, NULL, NULL, NULL);
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate
5057961SNatalie.Li@Sun.COM if (name != args->what.name)
5067961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN + 1);
5077961SNatalie.Li@Sun.COM
5084971Sjarrett if (is_system_labeled() && error == 0) {
5094971Sjarrett bslabel_t *clabel = req->rq_label;
5104971Sjarrett
5114971Sjarrett ASSERT(clabel != NULL);
5124971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
5134971Sjarrett "got client label from request(1)", struct svc_req *, req);
5144971Sjarrett
5154971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
5164971Sjarrett if (!do_rfs_label_check(clabel, dvp,
5179871SJarrett.Lu@Sun.COM DOMINANCE_CHECK, exi)) {
5184971Sjarrett if (publicfh_flag && exi != NULL)
5194971Sjarrett exi_rele(exi);
5204971Sjarrett VN_RELE(vp);
5214971Sjarrett resp->status = NFS3ERR_ACCES;
5224971Sjarrett error = 1;
5234971Sjarrett }
5244971Sjarrett }
5254971Sjarrett }
5264971Sjarrett
5270Sstevel@tonic-gate #ifdef DEBUG
5280Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
5290Sstevel@tonic-gate dva.va_mask = AT_ALL;
5305331Samw dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
5310Sstevel@tonic-gate } else
5320Sstevel@tonic-gate dvap = NULL;
5330Sstevel@tonic-gate #else
5340Sstevel@tonic-gate dva.va_mask = AT_ALL;
5355331Samw dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
5360Sstevel@tonic-gate #endif
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate if (error)
5390Sstevel@tonic-gate goto out;
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate if (sec.sec_flags & SEC_QUERY) {
5420Sstevel@tonic-gate error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
5430Sstevel@tonic-gate } else {
5440Sstevel@tonic-gate error = makefh3(&resp->resok.object, vp, exi);
5450Sstevel@tonic-gate if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
5460Sstevel@tonic-gate auth_weak = TRUE;
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate if (error) {
5500Sstevel@tonic-gate VN_RELE(vp);
5510Sstevel@tonic-gate goto out;
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate /*
5550Sstevel@tonic-gate * If publicfh_flag is true then we have called rfs_publicfh_mclookup
5560Sstevel@tonic-gate * and have obtained a new exportinfo in exi which needs to be
5570Sstevel@tonic-gate * released. Note the the original exportinfo pointed to by exi
5580Sstevel@tonic-gate * will be released by the caller, common_dispatch.
5590Sstevel@tonic-gate */
5600Sstevel@tonic-gate if (publicfh_flag)
5610Sstevel@tonic-gate exi_rele(exi);
5620Sstevel@tonic-gate
5630Sstevel@tonic-gate #ifdef DEBUG
5640Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
5650Sstevel@tonic-gate va.va_mask = AT_ALL;
5660Sstevel@tonic-gate vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
5670Sstevel@tonic-gate } else
5680Sstevel@tonic-gate vap = NULL;
5690Sstevel@tonic-gate #else
5700Sstevel@tonic-gate va.va_mask = AT_ALL;
5710Sstevel@tonic-gate vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
5720Sstevel@tonic-gate #endif
5730Sstevel@tonic-gate
5740Sstevel@tonic-gate VN_RELE(vp);
5750Sstevel@tonic-gate
5760Sstevel@tonic-gate resp->status = NFS3_OK;
5770Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
5780Sstevel@tonic-gate vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate /*
5810Sstevel@tonic-gate * If it's public fh, no 0x81, and client's flavor is
5820Sstevel@tonic-gate * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
5830Sstevel@tonic-gate * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
5840Sstevel@tonic-gate */
5850Sstevel@tonic-gate if (auth_weak)
5860Sstevel@tonic-gate resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
5870Sstevel@tonic-gate
5885982Sahl DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
5895982Sahl cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
5905982Sahl VN_RELE(dvp);
5915982Sahl
5920Sstevel@tonic-gate return;
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate out:
5950Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
5960Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
5970Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
5980Sstevel@tonic-gate } else
5990Sstevel@tonic-gate resp->status = puterrno3(error);
6000Sstevel@tonic-gate out1:
6015982Sahl DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
6025982Sahl cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
6035982Sahl
6040Sstevel@tonic-gate if (dvp != NULL)
6050Sstevel@tonic-gate VN_RELE(dvp);
6060Sstevel@tonic-gate vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
6070Sstevel@tonic-gate
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate
6101610Sthurlow void *
rfs3_lookup_getfh(LOOKUP3args * args)6110Sstevel@tonic-gate rfs3_lookup_getfh(LOOKUP3args *args)
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate
6141610Sthurlow return (&args->what.dir);
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate
6170Sstevel@tonic-gate /* ARGSUSED */
6180Sstevel@tonic-gate void
rfs3_access(ACCESS3args * args,ACCESS3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)6190Sstevel@tonic-gate rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
6200Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
6210Sstevel@tonic-gate {
6220Sstevel@tonic-gate int error;
6230Sstevel@tonic-gate vnode_t *vp;
6240Sstevel@tonic-gate struct vattr *vap;
6250Sstevel@tonic-gate struct vattr va;
6260Sstevel@tonic-gate int checkwriteperm;
6274971Sjarrett boolean_t dominant_label = B_FALSE;
6284971Sjarrett boolean_t equal_label = B_FALSE;
6294971Sjarrett boolean_t admin_low_client;
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate vap = NULL;
6320Sstevel@tonic-gate
6330Sstevel@tonic-gate vp = nfs3_fhtovp(&args->object, exi);
6345982Sahl
6355982Sahl DTRACE_NFSV3_4(op__access__start, struct svc_req *, req,
6365982Sahl cred_t *, cr, vnode_t *, vp, ACCESS3args *, args);
6375982Sahl
6380Sstevel@tonic-gate if (vp == NULL) {
6390Sstevel@tonic-gate error = ESTALE;
6400Sstevel@tonic-gate goto out;
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate
6430Sstevel@tonic-gate /*
6440Sstevel@tonic-gate * If the file system is exported read only, it is not appropriate
6450Sstevel@tonic-gate * to check write permissions for regular files and directories.
6460Sstevel@tonic-gate * Special files are interpreted by the client, so the underlying
6470Sstevel@tonic-gate * permissions are sent back to the client for interpretation.
6480Sstevel@tonic-gate */
6490Sstevel@tonic-gate if (rdonly(exi, req) && (vp->v_type == VREG || vp->v_type == VDIR))
6500Sstevel@tonic-gate checkwriteperm = 0;
6510Sstevel@tonic-gate else
6520Sstevel@tonic-gate checkwriteperm = 1;
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate /*
6550Sstevel@tonic-gate * We need the mode so that we can correctly determine access
6560Sstevel@tonic-gate * permissions relative to a mandatory lock file. Access to
6570Sstevel@tonic-gate * mandatory lock files is denied on the server, so it might
6580Sstevel@tonic-gate * as well be reflected to the server during the open.
6590Sstevel@tonic-gate */
6600Sstevel@tonic-gate va.va_mask = AT_MODE;
6615331Samw error = VOP_GETATTR(vp, &va, 0, cr, NULL);
6620Sstevel@tonic-gate if (error)
6630Sstevel@tonic-gate goto out;
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate #ifdef DEBUG
6660Sstevel@tonic-gate if (rfs3_do_post_op_attr)
6670Sstevel@tonic-gate vap = &va;
6680Sstevel@tonic-gate #else
6690Sstevel@tonic-gate vap = &va;
6700Sstevel@tonic-gate #endif
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate resp->resok.access = 0;
6730Sstevel@tonic-gate
6744971Sjarrett if (is_system_labeled()) {
6754971Sjarrett bslabel_t *clabel = req->rq_label;
6764971Sjarrett
6774971Sjarrett ASSERT(clabel != NULL);
6784971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *,
6794971Sjarrett "got client label from request(1)", struct svc_req *, req);
6804971Sjarrett
6814971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
6824971Sjarrett if ((equal_label = do_rfs_label_check(clabel, vp,
6839871SJarrett.Lu@Sun.COM EQUALITY_CHECK, exi)) == B_FALSE) {
6844971Sjarrett dominant_label = do_rfs_label_check(clabel,
6859871SJarrett.Lu@Sun.COM vp, DOMINANCE_CHECK, exi);
6864971Sjarrett } else
6874971Sjarrett dominant_label = B_TRUE;
6884971Sjarrett admin_low_client = B_FALSE;
6894971Sjarrett } else
6904971Sjarrett admin_low_client = B_TRUE;
6914971Sjarrett }
6924971Sjarrett
6930Sstevel@tonic-gate if (args->access & ACCESS3_READ) {
6945331Samw error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
6950Sstevel@tonic-gate if (error) {
6960Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK)
6970Sstevel@tonic-gate goto out;
6984971Sjarrett } else if (!MANDLOCK(vp, va.va_mode) &&
6994971Sjarrett (!is_system_labeled() || admin_low_client ||
7004971Sjarrett dominant_label))
7010Sstevel@tonic-gate resp->resok.access |= ACCESS3_READ;
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) {
7045331Samw error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
7050Sstevel@tonic-gate if (error) {
7060Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK)
7070Sstevel@tonic-gate goto out;
7084971Sjarrett } else if (!is_system_labeled() || admin_low_client ||
7094971Sjarrett dominant_label)
7100Sstevel@tonic-gate resp->resok.access |= ACCESS3_LOOKUP;
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate if (checkwriteperm &&
7130Sstevel@tonic-gate (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) {
7145331Samw error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
7150Sstevel@tonic-gate if (error) {
7160Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK)
7170Sstevel@tonic-gate goto out;
7184971Sjarrett } else if (!MANDLOCK(vp, va.va_mode) &&
7194971Sjarrett (!is_system_labeled() || admin_low_client || equal_label)) {
7200Sstevel@tonic-gate resp->resok.access |=
7210Sstevel@tonic-gate (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND));
7220Sstevel@tonic-gate }
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate if (checkwriteperm &&
7250Sstevel@tonic-gate (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
7265331Samw error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
7270Sstevel@tonic-gate if (error) {
7280Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK)
7290Sstevel@tonic-gate goto out;
7304971Sjarrett } else if (!is_system_labeled() || admin_low_client ||
7314971Sjarrett equal_label)
7320Sstevel@tonic-gate resp->resok.access |= ACCESS3_DELETE;
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate if (args->access & ACCESS3_EXECUTE) {
7355331Samw error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
7360Sstevel@tonic-gate if (error) {
7370Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK)
7380Sstevel@tonic-gate goto out;
7394971Sjarrett } else if (!MANDLOCK(vp, va.va_mode) &&
7404971Sjarrett (!is_system_labeled() || admin_low_client ||
7414971Sjarrett dominant_label))
7420Sstevel@tonic-gate resp->resok.access |= ACCESS3_EXECUTE;
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate
7450Sstevel@tonic-gate #ifdef DEBUG
7460Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
7470Sstevel@tonic-gate va.va_mask = AT_ALL;
7480Sstevel@tonic-gate vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
7490Sstevel@tonic-gate } else
7500Sstevel@tonic-gate vap = NULL;
7510Sstevel@tonic-gate #else
7520Sstevel@tonic-gate va.va_mask = AT_ALL;
7530Sstevel@tonic-gate vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
7540Sstevel@tonic-gate #endif
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate resp->status = NFS3_OK;
7570Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
7585982Sahl
7595982Sahl DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
7605982Sahl cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
7615982Sahl
7625982Sahl VN_RELE(vp);
7635982Sahl
7640Sstevel@tonic-gate return;
7650Sstevel@tonic-gate
7660Sstevel@tonic-gate out:
7670Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
7680Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
7690Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
7700Sstevel@tonic-gate } else
7710Sstevel@tonic-gate resp->status = puterrno3(error);
7725982Sahl DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
7735982Sahl cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
7740Sstevel@tonic-gate if (vp != NULL)
7750Sstevel@tonic-gate VN_RELE(vp);
7760Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate
7791610Sthurlow void *
rfs3_access_getfh(ACCESS3args * args)7800Sstevel@tonic-gate rfs3_access_getfh(ACCESS3args *args)
7810Sstevel@tonic-gate {
7820Sstevel@tonic-gate
7831610Sthurlow return (&args->object);
7840Sstevel@tonic-gate }
7850Sstevel@tonic-gate
7860Sstevel@tonic-gate /* ARGSUSED */
7870Sstevel@tonic-gate void
rfs3_readlink(READLINK3args * args,READLINK3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)7880Sstevel@tonic-gate rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
7890Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
7900Sstevel@tonic-gate {
7910Sstevel@tonic-gate int error;
7920Sstevel@tonic-gate vnode_t *vp;
7930Sstevel@tonic-gate struct vattr *vap;
7940Sstevel@tonic-gate struct vattr va;
7950Sstevel@tonic-gate struct iovec iov;
7960Sstevel@tonic-gate struct uio uio;
7970Sstevel@tonic-gate char *data;
7987961SNatalie.Li@Sun.COM struct sockaddr *ca;
7997961SNatalie.Li@Sun.COM char *name = NULL;
80011291SRobert.Thurlow@Sun.COM int is_referral = 0;
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate vap = NULL;
8030Sstevel@tonic-gate
8040Sstevel@tonic-gate vp = nfs3_fhtovp(&args->symlink, exi);
8055982Sahl
8065982Sahl DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
8075982Sahl cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
8085982Sahl
8090Sstevel@tonic-gate if (vp == NULL) {
8100Sstevel@tonic-gate error = ESTALE;
8110Sstevel@tonic-gate goto out;
8120Sstevel@tonic-gate }
8130Sstevel@tonic-gate
8140Sstevel@tonic-gate va.va_mask = AT_ALL;
8155331Samw error = VOP_GETATTR(vp, &va, 0, cr, NULL);
8160Sstevel@tonic-gate if (error)
8170Sstevel@tonic-gate goto out;
8180Sstevel@tonic-gate
8190Sstevel@tonic-gate #ifdef DEBUG
8200Sstevel@tonic-gate if (rfs3_do_post_op_attr)
8210Sstevel@tonic-gate vap = &va;
8220Sstevel@tonic-gate #else
8230Sstevel@tonic-gate vap = &va;
8240Sstevel@tonic-gate #endif
8250Sstevel@tonic-gate
82611291SRobert.Thurlow@Sun.COM /* We lied about the object type for a referral */
82711291SRobert.Thurlow@Sun.COM if (vn_is_nfs_reparse(vp, cr))
82811291SRobert.Thurlow@Sun.COM is_referral = 1;
82911291SRobert.Thurlow@Sun.COM
83011291SRobert.Thurlow@Sun.COM if (vp->v_type != VLNK && !is_referral) {
8310Sstevel@tonic-gate resp->status = NFS3ERR_INVAL;
8320Sstevel@tonic-gate goto out1;
8330Sstevel@tonic-gate }
8340Sstevel@tonic-gate
8350Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) {
8360Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
8370Sstevel@tonic-gate goto out1;
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate
8404971Sjarrett if (is_system_labeled()) {
8414971Sjarrett bslabel_t *clabel = req->rq_label;
8424971Sjarrett
8434971Sjarrett ASSERT(clabel != NULL);
8444971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
8454971Sjarrett "got client label from request(1)", struct svc_req *, req);
8464971Sjarrett
8474971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
8489871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
8499871SJarrett.Lu@Sun.COM exi)) {
8504971Sjarrett resp->status = NFS3ERR_ACCES;
8514971Sjarrett goto out1;
8524971Sjarrett }
8534971Sjarrett }
8544971Sjarrett }
8554971Sjarrett
8560Sstevel@tonic-gate data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
8570Sstevel@tonic-gate
85811291SRobert.Thurlow@Sun.COM if (is_referral) {
85911291SRobert.Thurlow@Sun.COM char *s;
86011291SRobert.Thurlow@Sun.COM size_t strsz;
86111291SRobert.Thurlow@Sun.COM
86211291SRobert.Thurlow@Sun.COM /* Get an artificial symlink based on a referral */
86311291SRobert.Thurlow@Sun.COM s = build_symlink(vp, cr, &strsz);
86411291SRobert.Thurlow@Sun.COM global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++;
86511291SRobert.Thurlow@Sun.COM DTRACE_PROBE2(nfs3serv__func__referral__reflink,
86611291SRobert.Thurlow@Sun.COM vnode_t *, vp, char *, s);
86711291SRobert.Thurlow@Sun.COM if (s == NULL)
86811291SRobert.Thurlow@Sun.COM error = EINVAL;
86911291SRobert.Thurlow@Sun.COM else {
87011291SRobert.Thurlow@Sun.COM error = 0;
87111291SRobert.Thurlow@Sun.COM (void) strlcpy(data, s, MAXPATHLEN + 1);
87211291SRobert.Thurlow@Sun.COM kmem_free(s, strsz);
87311291SRobert.Thurlow@Sun.COM }
87411291SRobert.Thurlow@Sun.COM
87511291SRobert.Thurlow@Sun.COM } else {
87611291SRobert.Thurlow@Sun.COM
87711291SRobert.Thurlow@Sun.COM iov.iov_base = data;
87811291SRobert.Thurlow@Sun.COM iov.iov_len = MAXPATHLEN;
87911291SRobert.Thurlow@Sun.COM uio.uio_iov = &iov;
88011291SRobert.Thurlow@Sun.COM uio.uio_iovcnt = 1;
88111291SRobert.Thurlow@Sun.COM uio.uio_segflg = UIO_SYSSPACE;
88211291SRobert.Thurlow@Sun.COM uio.uio_extflg = UIO_COPY_CACHED;
88311291SRobert.Thurlow@Sun.COM uio.uio_loffset = 0;
88411291SRobert.Thurlow@Sun.COM uio.uio_resid = MAXPATHLEN;
88511291SRobert.Thurlow@Sun.COM
88611291SRobert.Thurlow@Sun.COM error = VOP_READLINK(vp, &uio, cr, NULL);
88711291SRobert.Thurlow@Sun.COM
88811291SRobert.Thurlow@Sun.COM if (!error)
88911291SRobert.Thurlow@Sun.COM *(data + MAXPATHLEN - uio.uio_resid) = '\0';
89011291SRobert.Thurlow@Sun.COM }
8910Sstevel@tonic-gate
8920Sstevel@tonic-gate #ifdef DEBUG
8930Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
8940Sstevel@tonic-gate va.va_mask = AT_ALL;
8955331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
8960Sstevel@tonic-gate } else
8970Sstevel@tonic-gate vap = NULL;
8980Sstevel@tonic-gate #else
8990Sstevel@tonic-gate va.va_mask = AT_ALL;
9005331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
9010Sstevel@tonic-gate #endif
90211291SRobert.Thurlow@Sun.COM /* Lie about object type again just to be consistent */
90311291SRobert.Thurlow@Sun.COM if (is_referral && vap != NULL)
90411291SRobert.Thurlow@Sun.COM vap->va_type = VLNK;
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate #if 0 /* notyet */
9070Sstevel@tonic-gate /*
9080Sstevel@tonic-gate * Don't do this. It causes local disk writes when just
9090Sstevel@tonic-gate * reading the file and the overhead is deemed larger
9100Sstevel@tonic-gate * than the benefit.
9110Sstevel@tonic-gate */
9120Sstevel@tonic-gate /*
9130Sstevel@tonic-gate * Force modified metadata out to stable storage.
9140Sstevel@tonic-gate */
9155331Samw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
9160Sstevel@tonic-gate #endif
9170Sstevel@tonic-gate
9180Sstevel@tonic-gate if (error) {
9190Sstevel@tonic-gate kmem_free(data, MAXPATHLEN + 1);
9200Sstevel@tonic-gate goto out;
9210Sstevel@tonic-gate }
9220Sstevel@tonic-gate
9237961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
9247961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
9257961SNatalie.Li@Sun.COM MAXPATHLEN + 1);
9267961SNatalie.Li@Sun.COM
9277961SNatalie.Li@Sun.COM if (name == NULL) {
9287961SNatalie.Li@Sun.COM /*
9297961SNatalie.Li@Sun.COM * Even though the conversion failed, we return
9307961SNatalie.Li@Sun.COM * something. We just don't translate it.
9317961SNatalie.Li@Sun.COM */
9327961SNatalie.Li@Sun.COM name = data;
9337961SNatalie.Li@Sun.COM }
9347961SNatalie.Li@Sun.COM
9350Sstevel@tonic-gate resp->status = NFS3_OK;
9360Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
9377961SNatalie.Li@Sun.COM resp->resok.data = name;
9385982Sahl
9395982Sahl DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
9405982Sahl cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
9415982Sahl VN_RELE(vp);
9425982Sahl
9437961SNatalie.Li@Sun.COM if (name != data)
9447961SNatalie.Li@Sun.COM kmem_free(data, MAXPATHLEN + 1);
9457961SNatalie.Li@Sun.COM
9460Sstevel@tonic-gate return;
9470Sstevel@tonic-gate
9480Sstevel@tonic-gate out:
9490Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
9500Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
9510Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
9520Sstevel@tonic-gate } else
9530Sstevel@tonic-gate resp->status = puterrno3(error);
9540Sstevel@tonic-gate out1:
9555982Sahl DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
9565982Sahl cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
9570Sstevel@tonic-gate if (vp != NULL)
9580Sstevel@tonic-gate VN_RELE(vp);
9590Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate
9621610Sthurlow void *
rfs3_readlink_getfh(READLINK3args * args)9630Sstevel@tonic-gate rfs3_readlink_getfh(READLINK3args *args)
9640Sstevel@tonic-gate {
9650Sstevel@tonic-gate
9661610Sthurlow return (&args->symlink);
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate
9690Sstevel@tonic-gate void
rfs3_readlink_free(READLINK3res * resp)9700Sstevel@tonic-gate rfs3_readlink_free(READLINK3res *resp)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate
9730Sstevel@tonic-gate if (resp->status == NFS3_OK)
9740Sstevel@tonic-gate kmem_free(resp->resok.data, MAXPATHLEN + 1);
9750Sstevel@tonic-gate }
9760Sstevel@tonic-gate
9777387SRobert.Gordon@Sun.COM /*
9787387SRobert.Gordon@Sun.COM * Server routine to handle read
9797387SRobert.Gordon@Sun.COM * May handle RDMA data as well as mblks
9807387SRobert.Gordon@Sun.COM */
9810Sstevel@tonic-gate /* ARGSUSED */
9820Sstevel@tonic-gate void
rfs3_read(READ3args * args,READ3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)9830Sstevel@tonic-gate rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
9840Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
9850Sstevel@tonic-gate {
9860Sstevel@tonic-gate int error;
9870Sstevel@tonic-gate vnode_t *vp;
9880Sstevel@tonic-gate struct vattr *vap;
9890Sstevel@tonic-gate struct vattr va;
9900Sstevel@tonic-gate struct iovec iov;
9910Sstevel@tonic-gate struct uio uio;
9920Sstevel@tonic-gate u_offset_t offset;
99311610SChunli.Zhang@Sun.COM mblk_t *mp = NULL;
9940Sstevel@tonic-gate int alloc_err = 0;
9950Sstevel@tonic-gate int in_crit = 0;
9960Sstevel@tonic-gate int need_rwunlock = 0;
9975599Sjwahlig caller_context_t ct;
99811539SChunli.Zhang@Sun.COM int rdma_used = 0;
99911539SChunli.Zhang@Sun.COM int loaned_buffers;
100011539SChunli.Zhang@Sun.COM struct uio *uiop;
10010Sstevel@tonic-gate
10020Sstevel@tonic-gate vap = NULL;
10030Sstevel@tonic-gate
10040Sstevel@tonic-gate vp = nfs3_fhtovp(&args->file, exi);
10055982Sahl
10065982Sahl DTRACE_NFSV3_4(op__read__start, struct svc_req *, req,
10075982Sahl cred_t *, cr, vnode_t *, vp, READ3args *, args);
10085982Sahl
10090Sstevel@tonic-gate if (vp == NULL) {
10100Sstevel@tonic-gate error = ESTALE;
10110Sstevel@tonic-gate goto out;
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate
1014*13002SKaren.Rochford@Sun.COM if (args->wlist) {
1015*13002SKaren.Rochford@Sun.COM if (args->count > clist_len(args->wlist)) {
1016*13002SKaren.Rochford@Sun.COM error = EINVAL;
1017*13002SKaren.Rochford@Sun.COM goto out;
1018*13002SKaren.Rochford@Sun.COM }
101911539SChunli.Zhang@Sun.COM rdma_used = 1;
1020*13002SKaren.Rochford@Sun.COM }
102111539SChunli.Zhang@Sun.COM
102211539SChunli.Zhang@Sun.COM /* use loaned buffers for TCP */
102311539SChunli.Zhang@Sun.COM loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
102411539SChunli.Zhang@Sun.COM
10254971Sjarrett if (is_system_labeled()) {
10264971Sjarrett bslabel_t *clabel = req->rq_label;
10274971Sjarrett
10284971Sjarrett ASSERT(clabel != NULL);
10294971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opread__clabel, char *,
10304971Sjarrett "got client label from request(1)", struct svc_req *, req);
10314971Sjarrett
10324971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
10339871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
10349871SJarrett.Lu@Sun.COM exi)) {
10354971Sjarrett resp->status = NFS3ERR_ACCES;
10364971Sjarrett goto out1;
10374971Sjarrett }
10384971Sjarrett }
10394971Sjarrett }
10404971Sjarrett
10415599Sjwahlig ct.cc_sysid = 0;
10425599Sjwahlig ct.cc_pid = 0;
10435599Sjwahlig ct.cc_caller_id = nfs3_srv_caller_id;
10445599Sjwahlig ct.cc_flags = CC_DONTBLOCK;
10450Sstevel@tonic-gate
10460Sstevel@tonic-gate /*
10470Sstevel@tonic-gate * Enter the critical region before calling VOP_RWLOCK
10480Sstevel@tonic-gate * to avoid a deadlock with write requests.
10490Sstevel@tonic-gate */
10500Sstevel@tonic-gate if (nbl_need_check(vp)) {
10510Sstevel@tonic-gate nbl_start_crit(vp, RW_READER);
10520Sstevel@tonic-gate in_crit = 1;
10535331Samw if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
10545331Samw NULL)) {
10550Sstevel@tonic-gate error = EACCES;
10560Sstevel@tonic-gate goto out;
10570Sstevel@tonic-gate }
10580Sstevel@tonic-gate }
10590Sstevel@tonic-gate
10605599Sjwahlig error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
10615599Sjwahlig
10625599Sjwahlig /* check if a monitor detected a delegation conflict */
10635599Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
10645599Sjwahlig resp->status = NFS3ERR_JUKEBOX;
10655599Sjwahlig goto out1;
10665599Sjwahlig }
10675599Sjwahlig
10680Sstevel@tonic-gate need_rwunlock = 1;
10690Sstevel@tonic-gate
10700Sstevel@tonic-gate va.va_mask = AT_ALL;
10715599Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct);
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate * If we can't get the attributes, then we can't do the
10750Sstevel@tonic-gate * right access checking. So, we'll fail the request.
10760Sstevel@tonic-gate */
10770Sstevel@tonic-gate if (error)
10780Sstevel@tonic-gate goto out;
10790Sstevel@tonic-gate
10800Sstevel@tonic-gate #ifdef DEBUG
10810Sstevel@tonic-gate if (rfs3_do_post_op_attr)
10820Sstevel@tonic-gate vap = &va;
10830Sstevel@tonic-gate #else
10840Sstevel@tonic-gate vap = &va;
10850Sstevel@tonic-gate #endif
10860Sstevel@tonic-gate
10870Sstevel@tonic-gate if (vp->v_type != VREG) {
10880Sstevel@tonic-gate resp->status = NFS3ERR_INVAL;
10890Sstevel@tonic-gate goto out1;
10900Sstevel@tonic-gate }
10910Sstevel@tonic-gate
10920Sstevel@tonic-gate if (crgetuid(cr) != va.va_uid) {
10935599Sjwahlig error = VOP_ACCESS(vp, VREAD, 0, cr, &ct);
10940Sstevel@tonic-gate if (error) {
10950Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK)
10960Sstevel@tonic-gate goto out;
10975599Sjwahlig error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct);
10980Sstevel@tonic-gate if (error)
10990Sstevel@tonic-gate goto out;
11000Sstevel@tonic-gate }
11010Sstevel@tonic-gate }
11020Sstevel@tonic-gate
11030Sstevel@tonic-gate if (MANDLOCK(vp, va.va_mode)) {
11040Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
11050Sstevel@tonic-gate goto out1;
11060Sstevel@tonic-gate }
11070Sstevel@tonic-gate
11080Sstevel@tonic-gate offset = args->offset;
11090Sstevel@tonic-gate if (offset >= va.va_size) {
11105599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
11110Sstevel@tonic-gate if (in_crit)
11120Sstevel@tonic-gate nbl_end_crit(vp);
11130Sstevel@tonic-gate resp->status = NFS3_OK;
11140Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
11150Sstevel@tonic-gate resp->resok.count = 0;
11160Sstevel@tonic-gate resp->resok.eof = TRUE;
11170Sstevel@tonic-gate resp->resok.data.data_len = 0;
11180Sstevel@tonic-gate resp->resok.data.data_val = NULL;
11190Sstevel@tonic-gate resp->resok.data.mp = NULL;
11207387SRobert.Gordon@Sun.COM /* RDMA */
11217387SRobert.Gordon@Sun.COM resp->resok.wlist = args->wlist;
11227387SRobert.Gordon@Sun.COM resp->resok.wlist_len = resp->resok.count;
11239348SSiddheshwar.Mahesh@Sun.COM if (resp->resok.wlist)
11249348SSiddheshwar.Mahesh@Sun.COM clist_zero_len(resp->resok.wlist);
11255982Sahl goto done;
11260Sstevel@tonic-gate }
11270Sstevel@tonic-gate
11280Sstevel@tonic-gate if (args->count == 0) {
11295599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
11300Sstevel@tonic-gate if (in_crit)
11310Sstevel@tonic-gate nbl_end_crit(vp);
11320Sstevel@tonic-gate resp->status = NFS3_OK;
11330Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
11340Sstevel@tonic-gate resp->resok.count = 0;
11350Sstevel@tonic-gate resp->resok.eof = FALSE;
11360Sstevel@tonic-gate resp->resok.data.data_len = 0;
11370Sstevel@tonic-gate resp->resok.data.data_val = NULL;
11380Sstevel@tonic-gate resp->resok.data.mp = NULL;
11397387SRobert.Gordon@Sun.COM /* RDMA */
11407387SRobert.Gordon@Sun.COM resp->resok.wlist = args->wlist;
11417387SRobert.Gordon@Sun.COM resp->resok.wlist_len = resp->resok.count;
11429348SSiddheshwar.Mahesh@Sun.COM if (resp->resok.wlist)
11439348SSiddheshwar.Mahesh@Sun.COM clist_zero_len(resp->resok.wlist);
11445982Sahl goto done;
11450Sstevel@tonic-gate }
11460Sstevel@tonic-gate
11470Sstevel@tonic-gate /*
11480Sstevel@tonic-gate * do not allocate memory more the max. allowed
11490Sstevel@tonic-gate * transfer size
11500Sstevel@tonic-gate */
11510Sstevel@tonic-gate if (args->count > rfs3_tsize(req))
11520Sstevel@tonic-gate args->count = rfs3_tsize(req);
11530Sstevel@tonic-gate
115411539SChunli.Zhang@Sun.COM if (loaned_buffers) {
115511539SChunli.Zhang@Sun.COM uiop = (uio_t *)rfs_setup_xuio(vp);
115611539SChunli.Zhang@Sun.COM ASSERT(uiop != NULL);
115711539SChunli.Zhang@Sun.COM uiop->uio_segflg = UIO_SYSSPACE;
115811539SChunli.Zhang@Sun.COM uiop->uio_loffset = args->offset;
115911539SChunli.Zhang@Sun.COM uiop->uio_resid = args->count;
116011539SChunli.Zhang@Sun.COM
116111539SChunli.Zhang@Sun.COM /* Jump to do the read if successful */
116211539SChunli.Zhang@Sun.COM if (VOP_REQZCBUF(vp, UIO_READ, (xuio_t *)uiop, cr, &ct) == 0) {
116311539SChunli.Zhang@Sun.COM /*
116411539SChunli.Zhang@Sun.COM * Need to hold the vnode until after VOP_RETZCBUF()
116511539SChunli.Zhang@Sun.COM * is called.
116611539SChunli.Zhang@Sun.COM */
116711539SChunli.Zhang@Sun.COM VN_HOLD(vp);
116811539SChunli.Zhang@Sun.COM goto doio_read;
116911539SChunli.Zhang@Sun.COM }
117011539SChunli.Zhang@Sun.COM
117111539SChunli.Zhang@Sun.COM DTRACE_PROBE2(nfss__i__reqzcbuf_failed, int,
117211539SChunli.Zhang@Sun.COM uiop->uio_loffset, int, uiop->uio_resid);
117311539SChunli.Zhang@Sun.COM
117411539SChunli.Zhang@Sun.COM uiop->uio_extflg = 0;
117511539SChunli.Zhang@Sun.COM /* failure to setup for zero copy */
117611539SChunli.Zhang@Sun.COM rfs_free_xuio((void *)uiop);
117711539SChunli.Zhang@Sun.COM loaned_buffers = 0;
117811539SChunli.Zhang@Sun.COM }
117911539SChunli.Zhang@Sun.COM
11800Sstevel@tonic-gate /*
11817387SRobert.Gordon@Sun.COM * If returning data via RDMA Write, then grab the chunk list.
11827387SRobert.Gordon@Sun.COM * If we aren't returning READ data w/RDMA_WRITE, then grab
11837387SRobert.Gordon@Sun.COM * a mblk.
11840Sstevel@tonic-gate */
118511539SChunli.Zhang@Sun.COM if (rdma_used) {
11867387SRobert.Gordon@Sun.COM (void) rdma_get_wchunk(req, &iov, args->wlist);
11877387SRobert.Gordon@Sun.COM } else {
11887387SRobert.Gordon@Sun.COM /*
11897387SRobert.Gordon@Sun.COM * mp will contain the data to be sent out in the read reply.
11907387SRobert.Gordon@Sun.COM * This will be freed after the reply has been sent out (by the
11917387SRobert.Gordon@Sun.COM * driver).
11927387SRobert.Gordon@Sun.COM * Let's roundup the data to a BYTES_PER_XDR_UNIT multiple, so
11937387SRobert.Gordon@Sun.COM * that the call to xdrmblk_putmblk() never fails.
11947387SRobert.Gordon@Sun.COM */
11957387SRobert.Gordon@Sun.COM mp = allocb_wait(RNDUP(args->count), BPRI_MED, STR_NOSIG,
11967387SRobert.Gordon@Sun.COM &alloc_err);
11977387SRobert.Gordon@Sun.COM ASSERT(mp != NULL);
11987387SRobert.Gordon@Sun.COM ASSERT(alloc_err == 0);
11997387SRobert.Gordon@Sun.COM
12007387SRobert.Gordon@Sun.COM iov.iov_base = (caddr_t)mp->b_datap->db_base;
12017387SRobert.Gordon@Sun.COM iov.iov_len = args->count;
12027387SRobert.Gordon@Sun.COM }
12037387SRobert.Gordon@Sun.COM
12040Sstevel@tonic-gate uio.uio_iov = &iov;
12050Sstevel@tonic-gate uio.uio_iovcnt = 1;
12060Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
12070Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED;
12080Sstevel@tonic-gate uio.uio_loffset = args->offset;
12090Sstevel@tonic-gate uio.uio_resid = args->count;
121011539SChunli.Zhang@Sun.COM uiop = &uio;
121111539SChunli.Zhang@Sun.COM
121211539SChunli.Zhang@Sun.COM doio_read:
121311539SChunli.Zhang@Sun.COM error = VOP_READ(vp, uiop, 0, cr, &ct);
12140Sstevel@tonic-gate
12150Sstevel@tonic-gate if (error) {
121611539SChunli.Zhang@Sun.COM if (mp)
121711539SChunli.Zhang@Sun.COM freemsg(mp);
12185599Sjwahlig /* check if a monitor detected a delegation conflict */
12195599Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
12205599Sjwahlig resp->status = NFS3ERR_JUKEBOX;
12215599Sjwahlig goto out1;
12225599Sjwahlig }
12230Sstevel@tonic-gate goto out;
12240Sstevel@tonic-gate }
12250Sstevel@tonic-gate
122611539SChunli.Zhang@Sun.COM /* make mblk using zc buffers */
122711539SChunli.Zhang@Sun.COM if (loaned_buffers) {
122811539SChunli.Zhang@Sun.COM mp = uio_to_mblk(uiop);
122911539SChunli.Zhang@Sun.COM ASSERT(mp != NULL);
123011539SChunli.Zhang@Sun.COM }
123111539SChunli.Zhang@Sun.COM
12320Sstevel@tonic-gate va.va_mask = AT_ALL;
12335599Sjwahlig error = VOP_GETATTR(vp, &va, 0, cr, &ct);
12340Sstevel@tonic-gate
12350Sstevel@tonic-gate #ifdef DEBUG
12360Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
12370Sstevel@tonic-gate if (error)
12380Sstevel@tonic-gate vap = NULL;
12390Sstevel@tonic-gate else
12400Sstevel@tonic-gate vap = &va;
12410Sstevel@tonic-gate } else
12420Sstevel@tonic-gate vap = NULL;
12430Sstevel@tonic-gate #else
12440Sstevel@tonic-gate if (error)
12450Sstevel@tonic-gate vap = NULL;
12460Sstevel@tonic-gate else
12470Sstevel@tonic-gate vap = &va;
12480Sstevel@tonic-gate #endif
12490Sstevel@tonic-gate
12505599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
12510Sstevel@tonic-gate
12520Sstevel@tonic-gate if (in_crit)
12530Sstevel@tonic-gate nbl_end_crit(vp);
12540Sstevel@tonic-gate
12550Sstevel@tonic-gate resp->status = NFS3_OK;
12560Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
125711539SChunli.Zhang@Sun.COM resp->resok.count = args->count - uiop->uio_resid;
12580Sstevel@tonic-gate if (!error && offset + resp->resok.count == va.va_size)
12590Sstevel@tonic-gate resp->resok.eof = TRUE;
12600Sstevel@tonic-gate else
12610Sstevel@tonic-gate resp->resok.eof = FALSE;
12620Sstevel@tonic-gate resp->resok.data.data_len = resp->resok.count;
126311539SChunli.Zhang@Sun.COM
126411539SChunli.Zhang@Sun.COM if (mp)
126511539SChunli.Zhang@Sun.COM rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
126611539SChunli.Zhang@Sun.COM
12670Sstevel@tonic-gate resp->resok.data.mp = mp;
12680Sstevel@tonic-gate resp->resok.size = (uint_t)args->count;
12695982Sahl
127011539SChunli.Zhang@Sun.COM if (rdma_used) {
12717387SRobert.Gordon@Sun.COM resp->resok.data.data_val = (caddr_t)iov.iov_base;
12727387SRobert.Gordon@Sun.COM if (!rdma_setup_read_data3(args, &(resp->resok))) {
12737387SRobert.Gordon@Sun.COM resp->status = NFS3ERR_INVAL;
12747387SRobert.Gordon@Sun.COM }
12757387SRobert.Gordon@Sun.COM } else {
12767387SRobert.Gordon@Sun.COM resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
12777387SRobert.Gordon@Sun.COM (resp->resok).wlist = NULL;
12787387SRobert.Gordon@Sun.COM }
12797387SRobert.Gordon@Sun.COM
12805982Sahl done:
12815982Sahl DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
12825982Sahl cred_t *, cr, vnode_t *, vp, READ3res *, resp);
12835982Sahl
12845982Sahl VN_RELE(vp);
12855982Sahl
12860Sstevel@tonic-gate return;
12870Sstevel@tonic-gate
12880Sstevel@tonic-gate out:
12890Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
12900Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
12910Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
12920Sstevel@tonic-gate } else
12930Sstevel@tonic-gate resp->status = puterrno3(error);
12940Sstevel@tonic-gate out1:
12955982Sahl DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
12965982Sahl cred_t *, cr, vnode_t *, vp, READ3res *, resp);
12975982Sahl
12980Sstevel@tonic-gate if (vp != NULL) {
12990Sstevel@tonic-gate if (need_rwunlock)
13005599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
13010Sstevel@tonic-gate if (in_crit)
13020Sstevel@tonic-gate nbl_end_crit(vp);
13030Sstevel@tonic-gate VN_RELE(vp);
13040Sstevel@tonic-gate }
13050Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
13060Sstevel@tonic-gate }
13070Sstevel@tonic-gate
13080Sstevel@tonic-gate void
rfs3_read_free(READ3res * resp)13090Sstevel@tonic-gate rfs3_read_free(READ3res *resp)
13100Sstevel@tonic-gate {
13110Sstevel@tonic-gate mblk_t *mp;
13120Sstevel@tonic-gate
13130Sstevel@tonic-gate if (resp->status == NFS3_OK) {
13140Sstevel@tonic-gate mp = resp->resok.data.mp;
13150Sstevel@tonic-gate if (mp != NULL)
131611539SChunli.Zhang@Sun.COM freemsg(mp);
13170Sstevel@tonic-gate }
13180Sstevel@tonic-gate }
13190Sstevel@tonic-gate
13201610Sthurlow void *
rfs3_read_getfh(READ3args * args)13210Sstevel@tonic-gate rfs3_read_getfh(READ3args *args)
13220Sstevel@tonic-gate {
13230Sstevel@tonic-gate
13241610Sthurlow return (&args->file);
13250Sstevel@tonic-gate }
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate #define MAX_IOVECS 12
13280Sstevel@tonic-gate
13290Sstevel@tonic-gate #ifdef DEBUG
13300Sstevel@tonic-gate static int rfs3_write_hits = 0;
13310Sstevel@tonic-gate static int rfs3_write_misses = 0;
13320Sstevel@tonic-gate #endif
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate void
rfs3_write(WRITE3args * args,WRITE3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)13350Sstevel@tonic-gate rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
13360Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
13370Sstevel@tonic-gate {
13380Sstevel@tonic-gate int error;
13390Sstevel@tonic-gate vnode_t *vp;
13400Sstevel@tonic-gate struct vattr *bvap = NULL;
13410Sstevel@tonic-gate struct vattr bva;
13420Sstevel@tonic-gate struct vattr *avap = NULL;
13430Sstevel@tonic-gate struct vattr ava;
13440Sstevel@tonic-gate u_offset_t rlimit;
13450Sstevel@tonic-gate struct uio uio;
13460Sstevel@tonic-gate struct iovec iov[MAX_IOVECS];
13470Sstevel@tonic-gate mblk_t *m;
13480Sstevel@tonic-gate struct iovec *iovp;
13490Sstevel@tonic-gate int iovcnt;
13500Sstevel@tonic-gate int ioflag;
13510Sstevel@tonic-gate cred_t *savecred;
13520Sstevel@tonic-gate int in_crit = 0;
13530Sstevel@tonic-gate int rwlock_ret = -1;
13545599Sjwahlig caller_context_t ct;
13550Sstevel@tonic-gate
13560Sstevel@tonic-gate vp = nfs3_fhtovp(&args->file, exi);
13575982Sahl
13585982Sahl DTRACE_NFSV3_4(op__write__start, struct svc_req *, req,
13595982Sahl cred_t *, cr, vnode_t *, vp, WRITE3args *, args);
13605982Sahl
13610Sstevel@tonic-gate if (vp == NULL) {
13620Sstevel@tonic-gate error = ESTALE;
13635982Sahl goto err;
13640Sstevel@tonic-gate }
13650Sstevel@tonic-gate
13664971Sjarrett if (is_system_labeled()) {
13674971Sjarrett bslabel_t *clabel = req->rq_label;
13684971Sjarrett
13694971Sjarrett ASSERT(clabel != NULL);
13704971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
13714971Sjarrett "got client label from request(1)", struct svc_req *, req);
13724971Sjarrett
13734971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
13749871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
13759871SJarrett.Lu@Sun.COM exi)) {
13764971Sjarrett resp->status = NFS3ERR_ACCES;
13775982Sahl goto err1;
13784971Sjarrett }
13794971Sjarrett }
13804971Sjarrett }
13814971Sjarrett
13825599Sjwahlig ct.cc_sysid = 0;
13835599Sjwahlig ct.cc_pid = 0;
13845599Sjwahlig ct.cc_caller_id = nfs3_srv_caller_id;
13855599Sjwahlig ct.cc_flags = CC_DONTBLOCK;
13860Sstevel@tonic-gate
13870Sstevel@tonic-gate /*
13880Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK
13890Sstevel@tonic-gate * to avoid a deadlock with ufs.
13900Sstevel@tonic-gate */
13910Sstevel@tonic-gate if (nbl_need_check(vp)) {
13920Sstevel@tonic-gate nbl_start_crit(vp, RW_READER);
13930Sstevel@tonic-gate in_crit = 1;
13945331Samw if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0,
13955331Samw NULL)) {
13960Sstevel@tonic-gate error = EACCES;
13975982Sahl goto err;
13980Sstevel@tonic-gate }
13990Sstevel@tonic-gate }
14000Sstevel@tonic-gate
14015599Sjwahlig rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
14025599Sjwahlig
14035599Sjwahlig /* check if a monitor detected a delegation conflict */
14045599Sjwahlig if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
14055599Sjwahlig resp->status = NFS3ERR_JUKEBOX;
14065599Sjwahlig rwlock_ret = -1;
14075982Sahl goto err1;
14085599Sjwahlig }
14095599Sjwahlig
14100Sstevel@tonic-gate
14110Sstevel@tonic-gate bva.va_mask = AT_ALL;
14125599Sjwahlig error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
14130Sstevel@tonic-gate
14140Sstevel@tonic-gate /*
14150Sstevel@tonic-gate * If we can't get the attributes, then we can't do the
14160Sstevel@tonic-gate * right access checking. So, we'll fail the request.
14170Sstevel@tonic-gate */
14180Sstevel@tonic-gate if (error)
14195982Sahl goto err;
14200Sstevel@tonic-gate
14210Sstevel@tonic-gate bvap = &bva;
14220Sstevel@tonic-gate #ifdef DEBUG
14230Sstevel@tonic-gate if (!rfs3_do_pre_op_attr)
14240Sstevel@tonic-gate bvap = NULL;
14250Sstevel@tonic-gate #endif
14260Sstevel@tonic-gate avap = bvap;
14270Sstevel@tonic-gate
14280Sstevel@tonic-gate if (args->count != args->data.data_len) {
14290Sstevel@tonic-gate resp->status = NFS3ERR_INVAL;
14305982Sahl goto err1;
14310Sstevel@tonic-gate }
14320Sstevel@tonic-gate
14330Sstevel@tonic-gate if (rdonly(exi, req)) {
14340Sstevel@tonic-gate resp->status = NFS3ERR_ROFS;
14355982Sahl goto err1;
14360Sstevel@tonic-gate }
14370Sstevel@tonic-gate
14380Sstevel@tonic-gate if (vp->v_type != VREG) {
14390Sstevel@tonic-gate resp->status = NFS3ERR_INVAL;
14405982Sahl goto err1;
14410Sstevel@tonic-gate }
14420Sstevel@tonic-gate
14430Sstevel@tonic-gate if (crgetuid(cr) != bva.va_uid &&
14445599Sjwahlig (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
14455982Sahl goto err;
14460Sstevel@tonic-gate
14470Sstevel@tonic-gate if (MANDLOCK(vp, bva.va_mode)) {
14480Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
14495982Sahl goto err1;
14500Sstevel@tonic-gate }
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate if (args->count == 0) {
14530Sstevel@tonic-gate resp->status = NFS3_OK;
14540Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
14550Sstevel@tonic-gate resp->resok.count = 0;
14560Sstevel@tonic-gate resp->resok.committed = args->stable;
14570Sstevel@tonic-gate resp->resok.verf = write3verf;
14585982Sahl goto out;
14590Sstevel@tonic-gate }
14600Sstevel@tonic-gate
14610Sstevel@tonic-gate if (args->mblk != NULL) {
14620Sstevel@tonic-gate iovcnt = 0;
14630Sstevel@tonic-gate for (m = args->mblk; m != NULL; m = m->b_cont)
14640Sstevel@tonic-gate iovcnt++;
14650Sstevel@tonic-gate if (iovcnt <= MAX_IOVECS) {
14660Sstevel@tonic-gate #ifdef DEBUG
14670Sstevel@tonic-gate rfs3_write_hits++;
14680Sstevel@tonic-gate #endif
14690Sstevel@tonic-gate iovp = iov;
14700Sstevel@tonic-gate } else {
14710Sstevel@tonic-gate #ifdef DEBUG
14720Sstevel@tonic-gate rfs3_write_misses++;
14730Sstevel@tonic-gate #endif
14740Sstevel@tonic-gate iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
14750Sstevel@tonic-gate }
14760Sstevel@tonic-gate mblk_to_iov(args->mblk, iovcnt, iovp);
14777387SRobert.Gordon@Sun.COM
14787387SRobert.Gordon@Sun.COM } else if (args->rlist != NULL) {
14797387SRobert.Gordon@Sun.COM iovcnt = 1;
14807387SRobert.Gordon@Sun.COM iovp = iov;
14817387SRobert.Gordon@Sun.COM iovp->iov_base = (char *)((args->rlist)->u.c_daddr3);
14827387SRobert.Gordon@Sun.COM iovp->iov_len = args->count;
14830Sstevel@tonic-gate } else {
14840Sstevel@tonic-gate iovcnt = 1;
14850Sstevel@tonic-gate iovp = iov;
14860Sstevel@tonic-gate iovp->iov_base = args->data.data_val;
14870Sstevel@tonic-gate iovp->iov_len = args->count;
14880Sstevel@tonic-gate }
14890Sstevel@tonic-gate
14900Sstevel@tonic-gate uio.uio_iov = iovp;
14910Sstevel@tonic-gate uio.uio_iovcnt = iovcnt;
14920Sstevel@tonic-gate
14930Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
14940Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_DEFAULT;
14950Sstevel@tonic-gate uio.uio_loffset = args->offset;
14960Sstevel@tonic-gate uio.uio_resid = args->count;
14970Sstevel@tonic-gate uio.uio_llimit = curproc->p_fsz_ctl;
14980Sstevel@tonic-gate rlimit = uio.uio_llimit - args->offset;
14990Sstevel@tonic-gate if (rlimit < (u_offset_t)uio.uio_resid)
15000Sstevel@tonic-gate uio.uio_resid = (int)rlimit;
15010Sstevel@tonic-gate
15020Sstevel@tonic-gate if (args->stable == UNSTABLE)
15030Sstevel@tonic-gate ioflag = 0;
15040Sstevel@tonic-gate else if (args->stable == FILE_SYNC)
15050Sstevel@tonic-gate ioflag = FSYNC;
15060Sstevel@tonic-gate else if (args->stable == DATA_SYNC)
15070Sstevel@tonic-gate ioflag = FDSYNC;
15080Sstevel@tonic-gate else {
15090Sstevel@tonic-gate if (iovp != iov)
15100Sstevel@tonic-gate kmem_free(iovp, sizeof (*iovp) * iovcnt);
15110Sstevel@tonic-gate resp->status = NFS3ERR_INVAL;
15125982Sahl goto err1;
15130Sstevel@tonic-gate }
15140Sstevel@tonic-gate
15150Sstevel@tonic-gate /*
15160Sstevel@tonic-gate * We're changing creds because VM may fault and we need
15170Sstevel@tonic-gate * the cred of the current thread to be used if quota
15180Sstevel@tonic-gate * checking is enabled.
15190Sstevel@tonic-gate */
15200Sstevel@tonic-gate savecred = curthread->t_cred;
15210Sstevel@tonic-gate curthread->t_cred = cr;
15225599Sjwahlig error = VOP_WRITE(vp, &uio, ioflag, cr, &ct);
15230Sstevel@tonic-gate curthread->t_cred = savecred;
15240Sstevel@tonic-gate
15250Sstevel@tonic-gate if (iovp != iov)
15260Sstevel@tonic-gate kmem_free(iovp, sizeof (*iovp) * iovcnt);
15270Sstevel@tonic-gate
15285599Sjwahlig /* check if a monitor detected a delegation conflict */
15295599Sjwahlig if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
15305599Sjwahlig resp->status = NFS3ERR_JUKEBOX;
15315982Sahl goto err1;
15325599Sjwahlig }
15335599Sjwahlig
15340Sstevel@tonic-gate ava.va_mask = AT_ALL;
15355599Sjwahlig avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
15360Sstevel@tonic-gate
15370Sstevel@tonic-gate #ifdef DEBUG
15380Sstevel@tonic-gate if (!rfs3_do_post_op_attr)
15390Sstevel@tonic-gate avap = NULL;
15400Sstevel@tonic-gate #endif
15410Sstevel@tonic-gate
15420Sstevel@tonic-gate if (error)
15435982Sahl goto err;
15440Sstevel@tonic-gate
15450Sstevel@tonic-gate /*
15460Sstevel@tonic-gate * If we were unable to get the V_WRITELOCK_TRUE, then we
15470Sstevel@tonic-gate * may not have accurate after attrs, so check if
15480Sstevel@tonic-gate * we have both attributes, they have a non-zero va_seq, and
15490Sstevel@tonic-gate * va_seq has changed by exactly one,
15500Sstevel@tonic-gate * if not, turn off the before attr.
15510Sstevel@tonic-gate */
15520Sstevel@tonic-gate if (rwlock_ret != V_WRITELOCK_TRUE) {
15530Sstevel@tonic-gate if (bvap == NULL || avap == NULL ||
15545599Sjwahlig bvap->va_seq == 0 || avap->va_seq == 0 ||
15555599Sjwahlig avap->va_seq != (bvap->va_seq + 1)) {
15560Sstevel@tonic-gate bvap = NULL;
15570Sstevel@tonic-gate }
15580Sstevel@tonic-gate }
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate resp->status = NFS3_OK;
15610Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
15620Sstevel@tonic-gate resp->resok.count = args->count - uio.uio_resid;
15630Sstevel@tonic-gate resp->resok.committed = args->stable;
15640Sstevel@tonic-gate resp->resok.verf = write3verf;
15655982Sahl goto out;
15665982Sahl
15675982Sahl err:
15680Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
15690Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
15700Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
15710Sstevel@tonic-gate } else
15720Sstevel@tonic-gate resp->status = puterrno3(error);
15735982Sahl err1:
15745982Sahl vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
15755982Sahl out:
15765982Sahl DTRACE_NFSV3_4(op__write__done, struct svc_req *, req,
15775982Sahl cred_t *, cr, vnode_t *, vp, WRITE3res *, resp);
15785982Sahl
15790Sstevel@tonic-gate if (vp != NULL) {
15800Sstevel@tonic-gate if (rwlock_ret != -1)
15815599Sjwahlig VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
15820Sstevel@tonic-gate if (in_crit)
15830Sstevel@tonic-gate nbl_end_crit(vp);
15840Sstevel@tonic-gate VN_RELE(vp);
15850Sstevel@tonic-gate }
15860Sstevel@tonic-gate }
15870Sstevel@tonic-gate
15881610Sthurlow void *
rfs3_write_getfh(WRITE3args * args)15890Sstevel@tonic-gate rfs3_write_getfh(WRITE3args *args)
15900Sstevel@tonic-gate {
15910Sstevel@tonic-gate
15921610Sthurlow return (&args->file);
15930Sstevel@tonic-gate }
15940Sstevel@tonic-gate
15950Sstevel@tonic-gate void
rfs3_create(CREATE3args * args,CREATE3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)15960Sstevel@tonic-gate rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
15970Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
15980Sstevel@tonic-gate {
15990Sstevel@tonic-gate int error;
16000Sstevel@tonic-gate int in_crit = 0;
16010Sstevel@tonic-gate vnode_t *vp;
16020Sstevel@tonic-gate vnode_t *tvp = NULL;
16030Sstevel@tonic-gate vnode_t *dvp;
16040Sstevel@tonic-gate struct vattr *vap;
16050Sstevel@tonic-gate struct vattr va;
16060Sstevel@tonic-gate struct vattr *dbvap;
16070Sstevel@tonic-gate struct vattr dbva;
16080Sstevel@tonic-gate struct vattr *davap;
16090Sstevel@tonic-gate struct vattr dava;
16100Sstevel@tonic-gate enum vcexcl excl;
16110Sstevel@tonic-gate nfstime3 *mtime;
16120Sstevel@tonic-gate len_t reqsize;
16130Sstevel@tonic-gate bool_t trunc;
16147961SNatalie.Li@Sun.COM struct sockaddr *ca;
16157961SNatalie.Li@Sun.COM char *name = NULL;
16160Sstevel@tonic-gate
16170Sstevel@tonic-gate dbvap = NULL;
16180Sstevel@tonic-gate davap = NULL;
16190Sstevel@tonic-gate
16201610Sthurlow dvp = nfs3_fhtovp(&args->where.dir, exi);
16215982Sahl
16225982Sahl DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
16235982Sahl cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
16245982Sahl
16250Sstevel@tonic-gate if (dvp == NULL) {
16260Sstevel@tonic-gate error = ESTALE;
16270Sstevel@tonic-gate goto out;
16280Sstevel@tonic-gate }
16290Sstevel@tonic-gate
16300Sstevel@tonic-gate #ifdef DEBUG
16310Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
16320Sstevel@tonic-gate dbva.va_mask = AT_ALL;
16335331Samw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
16340Sstevel@tonic-gate } else
16350Sstevel@tonic-gate dbvap = NULL;
16360Sstevel@tonic-gate #else
16370Sstevel@tonic-gate dbva.va_mask = AT_ALL;
16385331Samw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
16390Sstevel@tonic-gate #endif
16400Sstevel@tonic-gate davap = dbvap;
16410Sstevel@tonic-gate
16420Sstevel@tonic-gate if (args->where.name == nfs3nametoolong) {
16430Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG;
16440Sstevel@tonic-gate goto out1;
16450Sstevel@tonic-gate }
16460Sstevel@tonic-gate
16470Sstevel@tonic-gate if (args->where.name == NULL || *(args->where.name) == '\0') {
16480Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
16490Sstevel@tonic-gate goto out1;
16500Sstevel@tonic-gate }
16510Sstevel@tonic-gate
16520Sstevel@tonic-gate if (rdonly(exi, req)) {
16530Sstevel@tonic-gate resp->status = NFS3ERR_ROFS;
16540Sstevel@tonic-gate goto out1;
16550Sstevel@tonic-gate }
16560Sstevel@tonic-gate
16574971Sjarrett if (is_system_labeled()) {
16584971Sjarrett bslabel_t *clabel = req->rq_label;
16594971Sjarrett
16604971Sjarrett ASSERT(clabel != NULL);
16614971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
16624971Sjarrett "got client label from request(1)", struct svc_req *, req);
16634971Sjarrett
16644971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
16659871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
16669871SJarrett.Lu@Sun.COM exi)) {
16674971Sjarrett resp->status = NFS3ERR_ACCES;
16684971Sjarrett goto out1;
16694971Sjarrett }
16704971Sjarrett }
16714971Sjarrett }
16724971Sjarrett
16737961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
16747961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, args->where.name,
16757961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
16767961SNatalie.Li@Sun.COM
16777961SNatalie.Li@Sun.COM if (name == NULL) {
16787961SNatalie.Li@Sun.COM /* This is really a Solaris EILSEQ */
16797961SNatalie.Li@Sun.COM resp->status = NFS3ERR_INVAL;
16807961SNatalie.Li@Sun.COM goto out1;
16817961SNatalie.Li@Sun.COM }
16827961SNatalie.Li@Sun.COM
16830Sstevel@tonic-gate if (args->how.mode == EXCLUSIVE) {
16840Sstevel@tonic-gate va.va_mask = AT_TYPE | AT_MODE | AT_MTIME;
16850Sstevel@tonic-gate va.va_type = VREG;
16860Sstevel@tonic-gate va.va_mode = (mode_t)0;
16870Sstevel@tonic-gate /*
16880Sstevel@tonic-gate * Ensure no time overflows and that types match
16890Sstevel@tonic-gate */
16900Sstevel@tonic-gate mtime = (nfstime3 *)&args->how.createhow3_u.verf;
16910Sstevel@tonic-gate va.va_mtime.tv_sec = mtime->seconds % INT32_MAX;
16920Sstevel@tonic-gate va.va_mtime.tv_nsec = mtime->nseconds;
16930Sstevel@tonic-gate excl = EXCL;
16940Sstevel@tonic-gate } else {
16950Sstevel@tonic-gate error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes,
16960Sstevel@tonic-gate &va);
16970Sstevel@tonic-gate if (error)
16980Sstevel@tonic-gate goto out;
16990Sstevel@tonic-gate va.va_mask |= AT_TYPE;
17000Sstevel@tonic-gate va.va_type = VREG;
17010Sstevel@tonic-gate if (args->how.mode == GUARDED)
17020Sstevel@tonic-gate excl = EXCL;
17030Sstevel@tonic-gate else {
17040Sstevel@tonic-gate excl = NONEXCL;
17050Sstevel@tonic-gate
17060Sstevel@tonic-gate /*
17070Sstevel@tonic-gate * During creation of file in non-exclusive mode
17080Sstevel@tonic-gate * if size of file is being set then make sure
17090Sstevel@tonic-gate * that if the file already exists that no conflicting
17100Sstevel@tonic-gate * non-blocking mandatory locks exists in the region
17110Sstevel@tonic-gate * being modified. If there are conflicting locks fail
17120Sstevel@tonic-gate * the operation with EACCES.
17130Sstevel@tonic-gate */
17140Sstevel@tonic-gate if (va.va_mask & AT_SIZE) {
17150Sstevel@tonic-gate struct vattr tva;
17160Sstevel@tonic-gate
17170Sstevel@tonic-gate /*
17180Sstevel@tonic-gate * Does file already exist?
17190Sstevel@tonic-gate */
17207961SNatalie.Li@Sun.COM error = VOP_LOOKUP(dvp, name, &tvp,
17215599Sjwahlig NULL, 0, NULL, cr, NULL, NULL, NULL);
17220Sstevel@tonic-gate
17230Sstevel@tonic-gate /*
17240Sstevel@tonic-gate * Check to see if the file has been delegated
17250Sstevel@tonic-gate * to a v4 client. If so, then begin recall of
17260Sstevel@tonic-gate * the delegation and return JUKEBOX to allow
17270Sstevel@tonic-gate * the client to retrasmit its request.
17280Sstevel@tonic-gate */
17290Sstevel@tonic-gate
17300Sstevel@tonic-gate trunc = va.va_size == 0;
17310Sstevel@tonic-gate if (!error &&
17320Sstevel@tonic-gate rfs4_check_delegated(FWRITE, tvp, trunc)) {
17330Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
17340Sstevel@tonic-gate goto out1;
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate
17370Sstevel@tonic-gate /*
17380Sstevel@tonic-gate * Check for NBMAND lock conflicts
17390Sstevel@tonic-gate */
17400Sstevel@tonic-gate if (!error && nbl_need_check(tvp)) {
17410Sstevel@tonic-gate u_offset_t offset;
17420Sstevel@tonic-gate ssize_t len;
17430Sstevel@tonic-gate
17440Sstevel@tonic-gate nbl_start_crit(tvp, RW_READER);
17450Sstevel@tonic-gate in_crit = 1;
17460Sstevel@tonic-gate
17470Sstevel@tonic-gate tva.va_mask = AT_SIZE;
17485331Samw error = VOP_GETATTR(tvp, &tva, 0, cr,
17495599Sjwahlig NULL);
17500Sstevel@tonic-gate /*
17510Sstevel@tonic-gate * Can't check for conflicts, so return
17520Sstevel@tonic-gate * error.
17530Sstevel@tonic-gate */
17540Sstevel@tonic-gate if (error)
17550Sstevel@tonic-gate goto out;
17560Sstevel@tonic-gate
17570Sstevel@tonic-gate offset = tva.va_size < va.va_size ?
17585599Sjwahlig tva.va_size : va.va_size;
17590Sstevel@tonic-gate len = tva.va_size < va.va_size ?
17605599Sjwahlig va.va_size - tva.va_size :
17615599Sjwahlig tva.va_size - va.va_size;
17620Sstevel@tonic-gate if (nbl_conflict(tvp, NBL_WRITE,
17635599Sjwahlig offset, len, 0, NULL)) {
17640Sstevel@tonic-gate error = EACCES;
17650Sstevel@tonic-gate goto out;
17660Sstevel@tonic-gate }
17670Sstevel@tonic-gate } else if (tvp) {
17680Sstevel@tonic-gate VN_RELE(tvp);
17690Sstevel@tonic-gate tvp = NULL;
17700Sstevel@tonic-gate }
17710Sstevel@tonic-gate }
17720Sstevel@tonic-gate }
17730Sstevel@tonic-gate if (va.va_mask & AT_SIZE)
17740Sstevel@tonic-gate reqsize = va.va_size;
17750Sstevel@tonic-gate }
17760Sstevel@tonic-gate
17770Sstevel@tonic-gate /*
17780Sstevel@tonic-gate * Must specify the mode.
17790Sstevel@tonic-gate */
17800Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) {
17810Sstevel@tonic-gate resp->status = NFS3ERR_INVAL;
17820Sstevel@tonic-gate goto out1;
17830Sstevel@tonic-gate }
17840Sstevel@tonic-gate
17850Sstevel@tonic-gate /*
17860Sstevel@tonic-gate * If the filesystem is exported with nosuid, then mask off
17870Sstevel@tonic-gate * the setuid and setgid bits.
17880Sstevel@tonic-gate */
17890Sstevel@tonic-gate if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID))
17900Sstevel@tonic-gate va.va_mode &= ~(VSUID | VSGID);
17910Sstevel@tonic-gate
17920Sstevel@tonic-gate tryagain:
17930Sstevel@tonic-gate /*
17940Sstevel@tonic-gate * The file open mode used is VWRITE. If the client needs
17950Sstevel@tonic-gate * some other semantic, then it should do the access checking
17960Sstevel@tonic-gate * itself. It would have been nice to have the file open mode
17970Sstevel@tonic-gate * passed as part of the arguments.
17980Sstevel@tonic-gate */
17997961SNatalie.Li@Sun.COM error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
18005331Samw &vp, cr, 0, NULL, NULL);
18010Sstevel@tonic-gate
18020Sstevel@tonic-gate #ifdef DEBUG
18030Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
18040Sstevel@tonic-gate dava.va_mask = AT_ALL;
18055331Samw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
18060Sstevel@tonic-gate } else
18070Sstevel@tonic-gate davap = NULL;
18080Sstevel@tonic-gate #else
18090Sstevel@tonic-gate dava.va_mask = AT_ALL;
18105331Samw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
18110Sstevel@tonic-gate #endif
18120Sstevel@tonic-gate
18130Sstevel@tonic-gate if (error) {
18140Sstevel@tonic-gate /*
18150Sstevel@tonic-gate * If we got something other than file already exists
18160Sstevel@tonic-gate * then just return this error. Otherwise, we got
18170Sstevel@tonic-gate * EEXIST. If we were doing a GUARDED create, then
18180Sstevel@tonic-gate * just return this error. Otherwise, we need to
18190Sstevel@tonic-gate * make sure that this wasn't a duplicate of an
18200Sstevel@tonic-gate * exclusive create request.
18210Sstevel@tonic-gate *
18220Sstevel@tonic-gate * The assumption is made that a non-exclusive create
18230Sstevel@tonic-gate * request will never return EEXIST.
18240Sstevel@tonic-gate */
18250Sstevel@tonic-gate if (error != EEXIST || args->how.mode == GUARDED)
18260Sstevel@tonic-gate goto out;
18270Sstevel@tonic-gate /*
18280Sstevel@tonic-gate * Lookup the file so that we can get a vnode for it.
18290Sstevel@tonic-gate */
18307961SNatalie.Li@Sun.COM error = VOP_LOOKUP(dvp, name, &vp, NULL, 0,
18315331Samw NULL, cr, NULL, NULL, NULL);
18320Sstevel@tonic-gate if (error) {
18330Sstevel@tonic-gate /*
18340Sstevel@tonic-gate * We couldn't find the file that we thought that
18350Sstevel@tonic-gate * we just created. So, we'll just try creating
18360Sstevel@tonic-gate * it again.
18370Sstevel@tonic-gate */
18380Sstevel@tonic-gate if (error == ENOENT)
18390Sstevel@tonic-gate goto tryagain;
18400Sstevel@tonic-gate goto out;
18410Sstevel@tonic-gate }
18420Sstevel@tonic-gate
18430Sstevel@tonic-gate /*
18440Sstevel@tonic-gate * If the file is delegated to a v4 client, go ahead
18450Sstevel@tonic-gate * and initiate recall, this create is a hint that a
18460Sstevel@tonic-gate * conflicting v3 open has occurred.
18470Sstevel@tonic-gate */
18480Sstevel@tonic-gate
18490Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, vp, FALSE)) {
18500Sstevel@tonic-gate VN_RELE(vp);
18510Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
18520Sstevel@tonic-gate goto out1;
18530Sstevel@tonic-gate }
18540Sstevel@tonic-gate
18550Sstevel@tonic-gate va.va_mask = AT_ALL;
18565331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
18570Sstevel@tonic-gate
18580Sstevel@tonic-gate mtime = (nfstime3 *)&args->how.createhow3_u.verf;
18590Sstevel@tonic-gate /* % with INT32_MAX to prevent overflows */
18600Sstevel@tonic-gate if (args->how.mode == EXCLUSIVE && (vap == NULL ||
18610Sstevel@tonic-gate vap->va_mtime.tv_sec !=
18620Sstevel@tonic-gate (mtime->seconds % INT32_MAX) ||
18630Sstevel@tonic-gate vap->va_mtime.tv_nsec != mtime->nseconds)) {
18640Sstevel@tonic-gate VN_RELE(vp);
18650Sstevel@tonic-gate error = EEXIST;
18660Sstevel@tonic-gate goto out;
18670Sstevel@tonic-gate }
18680Sstevel@tonic-gate } else {
18690Sstevel@tonic-gate
18700Sstevel@tonic-gate if ((args->how.mode == UNCHECKED ||
18710Sstevel@tonic-gate args->how.mode == GUARDED) &&
18720Sstevel@tonic-gate args->how.createhow3_u.obj_attributes.size.set_it &&
18730Sstevel@tonic-gate va.va_size == 0)
18740Sstevel@tonic-gate trunc = TRUE;
18750Sstevel@tonic-gate else
18760Sstevel@tonic-gate trunc = FALSE;
18770Sstevel@tonic-gate
18780Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, vp, trunc)) {
18790Sstevel@tonic-gate VN_RELE(vp);
18800Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
18810Sstevel@tonic-gate goto out1;
18820Sstevel@tonic-gate }
18830Sstevel@tonic-gate
18840Sstevel@tonic-gate va.va_mask = AT_ALL;
18855331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
18860Sstevel@tonic-gate
18870Sstevel@tonic-gate /*
18880Sstevel@tonic-gate * We need to check to make sure that the file got
18890Sstevel@tonic-gate * created to the indicated size. If not, we do a
18900Sstevel@tonic-gate * setattr to try to change the size, but we don't
18910Sstevel@tonic-gate * try too hard. This shouldn't a problem as most
18920Sstevel@tonic-gate * clients will only specifiy a size of zero which
18930Sstevel@tonic-gate * local file systems handle. However, even if
18940Sstevel@tonic-gate * the client does specify a non-zero size, it can
18950Sstevel@tonic-gate * still recover by checking the size of the file
18960Sstevel@tonic-gate * after it has created it and then issue a setattr
18970Sstevel@tonic-gate * request of its own to set the size of the file.
18980Sstevel@tonic-gate */
18990Sstevel@tonic-gate if (vap != NULL &&
19000Sstevel@tonic-gate (args->how.mode == UNCHECKED ||
19010Sstevel@tonic-gate args->how.mode == GUARDED) &&
19020Sstevel@tonic-gate args->how.createhow3_u.obj_attributes.size.set_it &&
19030Sstevel@tonic-gate vap->va_size != reqsize) {
19040Sstevel@tonic-gate va.va_mask = AT_SIZE;
19050Sstevel@tonic-gate va.va_size = reqsize;
19060Sstevel@tonic-gate (void) VOP_SETATTR(vp, &va, 0, cr, NULL);
19070Sstevel@tonic-gate va.va_mask = AT_ALL;
19085331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
19090Sstevel@tonic-gate }
19100Sstevel@tonic-gate }
19110Sstevel@tonic-gate
19127961SNatalie.Li@Sun.COM if (name != args->where.name)
19137961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN + 1);
19147961SNatalie.Li@Sun.COM
19150Sstevel@tonic-gate #ifdef DEBUG
19160Sstevel@tonic-gate if (!rfs3_do_post_op_attr)
19170Sstevel@tonic-gate vap = NULL;
19180Sstevel@tonic-gate #endif
19190Sstevel@tonic-gate
19200Sstevel@tonic-gate #ifdef DEBUG
19210Sstevel@tonic-gate if (!rfs3_do_post_op_fh3)
19220Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE;
19230Sstevel@tonic-gate else {
19240Sstevel@tonic-gate #endif
19250Sstevel@tonic-gate error = makefh3(&resp->resok.obj.handle, vp, exi);
19260Sstevel@tonic-gate if (error)
19270Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE;
19280Sstevel@tonic-gate else
19290Sstevel@tonic-gate resp->resok.obj.handle_follows = TRUE;
19300Sstevel@tonic-gate #ifdef DEBUG
19310Sstevel@tonic-gate }
19320Sstevel@tonic-gate #endif
19330Sstevel@tonic-gate
19340Sstevel@tonic-gate /*
19350Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
19360Sstevel@tonic-gate */
19375331Samw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
19385331Samw (void) VOP_FSYNC(dvp, 0, cr, NULL);
19390Sstevel@tonic-gate
19400Sstevel@tonic-gate VN_RELE(vp);
19410Sstevel@tonic-gate if (tvp != NULL) {
19420Sstevel@tonic-gate if (in_crit)
19430Sstevel@tonic-gate nbl_end_crit(tvp);
19440Sstevel@tonic-gate VN_RELE(tvp);
19450Sstevel@tonic-gate }
19460Sstevel@tonic-gate
19470Sstevel@tonic-gate resp->status = NFS3_OK;
19480Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
19490Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
19505982Sahl
19515982Sahl DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
19525982Sahl cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
19535982Sahl
19545982Sahl VN_RELE(dvp);
19550Sstevel@tonic-gate return;
19560Sstevel@tonic-gate
19570Sstevel@tonic-gate out:
19580Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
19590Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
19600Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
19610Sstevel@tonic-gate } else
19620Sstevel@tonic-gate resp->status = puterrno3(error);
19630Sstevel@tonic-gate out1:
19645982Sahl DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
19655982Sahl cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
19665982Sahl
19677961SNatalie.Li@Sun.COM if (name != NULL && name != args->where.name)
19687961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN + 1);
19697961SNatalie.Li@Sun.COM
19700Sstevel@tonic-gate if (tvp != NULL) {
19710Sstevel@tonic-gate if (in_crit)
19720Sstevel@tonic-gate nbl_end_crit(tvp);
19730Sstevel@tonic-gate VN_RELE(tvp);
19740Sstevel@tonic-gate }
19750Sstevel@tonic-gate if (dvp != NULL)
19760Sstevel@tonic-gate VN_RELE(dvp);
19770Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
19780Sstevel@tonic-gate }
19790Sstevel@tonic-gate
19801610Sthurlow void *
rfs3_create_getfh(CREATE3args * args)19810Sstevel@tonic-gate rfs3_create_getfh(CREATE3args *args)
19820Sstevel@tonic-gate {
19830Sstevel@tonic-gate
19841610Sthurlow return (&args->where.dir);
19850Sstevel@tonic-gate }
19860Sstevel@tonic-gate
19870Sstevel@tonic-gate void
rfs3_mkdir(MKDIR3args * args,MKDIR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)19880Sstevel@tonic-gate rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
19890Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
19900Sstevel@tonic-gate {
19910Sstevel@tonic-gate int error;
19920Sstevel@tonic-gate vnode_t *vp = NULL;
19930Sstevel@tonic-gate vnode_t *dvp;
19940Sstevel@tonic-gate struct vattr *vap;
19950Sstevel@tonic-gate struct vattr va;
19960Sstevel@tonic-gate struct vattr *dbvap;
19970Sstevel@tonic-gate struct vattr dbva;
19980Sstevel@tonic-gate struct vattr *davap;
19990Sstevel@tonic-gate struct vattr dava;
20007961SNatalie.Li@Sun.COM struct sockaddr *ca;
20017961SNatalie.Li@Sun.COM char *name = NULL;
20020Sstevel@tonic-gate
20030Sstevel@tonic-gate dbvap = NULL;
20040Sstevel@tonic-gate davap = NULL;
20050Sstevel@tonic-gate
20061610Sthurlow dvp = nfs3_fhtovp(&args->where.dir, exi);
20075982Sahl
20085982Sahl DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
20095982Sahl cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
20105982Sahl
20110Sstevel@tonic-gate if (dvp == NULL) {
20120Sstevel@tonic-gate error = ESTALE;
20130Sstevel@tonic-gate goto out;
20140Sstevel@tonic-gate }
20150Sstevel@tonic-gate
20160Sstevel@tonic-gate #ifdef DEBUG
20170Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
20180Sstevel@tonic-gate dbva.va_mask = AT_ALL;
20195331Samw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
20200Sstevel@tonic-gate } else
20210Sstevel@tonic-gate dbvap = NULL;
20220Sstevel@tonic-gate #else
20230Sstevel@tonic-gate dbva.va_mask = AT_ALL;
20245331Samw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
20250Sstevel@tonic-gate #endif
20260Sstevel@tonic-gate davap = dbvap;
20270Sstevel@tonic-gate
20280Sstevel@tonic-gate if (args->where.name == nfs3nametoolong) {
20290Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG;
20300Sstevel@tonic-gate goto out1;
20310Sstevel@tonic-gate }
20320Sstevel@tonic-gate
20330Sstevel@tonic-gate if (args->where.name == NULL || *(args->where.name) == '\0') {
20340Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
20350Sstevel@tonic-gate goto out1;
20360Sstevel@tonic-gate }
20370Sstevel@tonic-gate
20380Sstevel@tonic-gate if (rdonly(exi, req)) {
20390Sstevel@tonic-gate resp->status = NFS3ERR_ROFS;
20400Sstevel@tonic-gate goto out1;
20410Sstevel@tonic-gate }
20420Sstevel@tonic-gate
20434971Sjarrett if (is_system_labeled()) {
20444971Sjarrett bslabel_t *clabel = req->rq_label;
20454971Sjarrett
20464971Sjarrett ASSERT(clabel != NULL);
20474971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
20484971Sjarrett "got client label from request(1)", struct svc_req *, req);
20494971Sjarrett
20504971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
20519871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
20529871SJarrett.Lu@Sun.COM exi)) {
20534971Sjarrett resp->status = NFS3ERR_ACCES;
20544971Sjarrett goto out1;
20554971Sjarrett }
20564971Sjarrett }
20574971Sjarrett }
20584971Sjarrett
20590Sstevel@tonic-gate error = sattr3_to_vattr(&args->attributes, &va);
20600Sstevel@tonic-gate if (error)
20610Sstevel@tonic-gate goto out;
20620Sstevel@tonic-gate
20630Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) {
20640Sstevel@tonic-gate resp->status = NFS3ERR_INVAL;
20650Sstevel@tonic-gate goto out1;
20660Sstevel@tonic-gate }
20670Sstevel@tonic-gate
20687961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
20697961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, args->where.name,
20707961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
20717961SNatalie.Li@Sun.COM
20727961SNatalie.Li@Sun.COM if (name == NULL) {
20737961SNatalie.Li@Sun.COM resp->status = NFS3ERR_INVAL;
20747961SNatalie.Li@Sun.COM goto out1;
20757961SNatalie.Li@Sun.COM }
20767961SNatalie.Li@Sun.COM
20770Sstevel@tonic-gate va.va_mask |= AT_TYPE;
20780Sstevel@tonic-gate va.va_type = VDIR;
20790Sstevel@tonic-gate
20807961SNatalie.Li@Sun.COM error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL);
20817961SNatalie.Li@Sun.COM
20827961SNatalie.Li@Sun.COM if (name != args->where.name)
20837961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN + 1);
20840Sstevel@tonic-gate
20850Sstevel@tonic-gate #ifdef DEBUG
20860Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
20870Sstevel@tonic-gate dava.va_mask = AT_ALL;
20885331Samw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
20890Sstevel@tonic-gate } else
20900Sstevel@tonic-gate davap = NULL;
20910Sstevel@tonic-gate #else
20920Sstevel@tonic-gate dava.va_mask = AT_ALL;
20935331Samw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
20940Sstevel@tonic-gate #endif
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate /*
20970Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
20980Sstevel@tonic-gate */
20995331Samw (void) VOP_FSYNC(dvp, 0, cr, NULL);
21000Sstevel@tonic-gate
21010Sstevel@tonic-gate if (error)
21020Sstevel@tonic-gate goto out;
21030Sstevel@tonic-gate
21040Sstevel@tonic-gate #ifdef DEBUG
21050Sstevel@tonic-gate if (!rfs3_do_post_op_fh3)
21060Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE;
21070Sstevel@tonic-gate else {
21080Sstevel@tonic-gate #endif
21090Sstevel@tonic-gate error = makefh3(&resp->resok.obj.handle, vp, exi);
21100Sstevel@tonic-gate if (error)
21110Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE;
21120Sstevel@tonic-gate else
21130Sstevel@tonic-gate resp->resok.obj.handle_follows = TRUE;
21140Sstevel@tonic-gate #ifdef DEBUG
21150Sstevel@tonic-gate }
21160Sstevel@tonic-gate #endif
21170Sstevel@tonic-gate
21180Sstevel@tonic-gate #ifdef DEBUG
21190Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
21200Sstevel@tonic-gate va.va_mask = AT_ALL;
21215331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
21220Sstevel@tonic-gate } else
21230Sstevel@tonic-gate vap = NULL;
21240Sstevel@tonic-gate #else
21250Sstevel@tonic-gate va.va_mask = AT_ALL;
21265331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
21270Sstevel@tonic-gate #endif
21280Sstevel@tonic-gate
21290Sstevel@tonic-gate /*
21300Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
21310Sstevel@tonic-gate */
21325331Samw (void) VOP_FSYNC(vp, 0, cr, NULL);
21330Sstevel@tonic-gate
21340Sstevel@tonic-gate VN_RELE(vp);
21350Sstevel@tonic-gate
21360Sstevel@tonic-gate resp->status = NFS3_OK;
21370Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
21380Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
21395982Sahl
21405982Sahl DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
21415982Sahl cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
21425982Sahl VN_RELE(dvp);
21435982Sahl
21440Sstevel@tonic-gate return;
21450Sstevel@tonic-gate
21460Sstevel@tonic-gate out:
21470Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
21480Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
21490Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
21500Sstevel@tonic-gate } else
21510Sstevel@tonic-gate resp->status = puterrno3(error);
21520Sstevel@tonic-gate out1:
21535982Sahl DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
21545982Sahl cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
21550Sstevel@tonic-gate if (dvp != NULL)
21560Sstevel@tonic-gate VN_RELE(dvp);
21570Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
21580Sstevel@tonic-gate }
21590Sstevel@tonic-gate
21601610Sthurlow void *
rfs3_mkdir_getfh(MKDIR3args * args)21610Sstevel@tonic-gate rfs3_mkdir_getfh(MKDIR3args *args)
21620Sstevel@tonic-gate {
21630Sstevel@tonic-gate
21641610Sthurlow return (&args->where.dir);
21650Sstevel@tonic-gate }
21660Sstevel@tonic-gate
21670Sstevel@tonic-gate void
rfs3_symlink(SYMLINK3args * args,SYMLINK3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)21680Sstevel@tonic-gate rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
21690Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
21700Sstevel@tonic-gate {
21710Sstevel@tonic-gate int error;
21720Sstevel@tonic-gate vnode_t *vp;
21730Sstevel@tonic-gate vnode_t *dvp;
21740Sstevel@tonic-gate struct vattr *vap;
21750Sstevel@tonic-gate struct vattr va;
21760Sstevel@tonic-gate struct vattr *dbvap;
21770Sstevel@tonic-gate struct vattr dbva;
21780Sstevel@tonic-gate struct vattr *davap;
21790Sstevel@tonic-gate struct vattr dava;
21807961SNatalie.Li@Sun.COM struct sockaddr *ca;
21817961SNatalie.Li@Sun.COM char *name = NULL;
21827961SNatalie.Li@Sun.COM char *symdata = NULL;
21830Sstevel@tonic-gate
21840Sstevel@tonic-gate dbvap = NULL;
21850Sstevel@tonic-gate davap = NULL;
21860Sstevel@tonic-gate
21871610Sthurlow dvp = nfs3_fhtovp(&args->where.dir, exi);
21885982Sahl
21895982Sahl DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
21905982Sahl cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
21915982Sahl
21920Sstevel@tonic-gate if (dvp == NULL) {
21930Sstevel@tonic-gate error = ESTALE;
21945982Sahl goto err;
21950Sstevel@tonic-gate }
21960Sstevel@tonic-gate
21970Sstevel@tonic-gate #ifdef DEBUG
21980Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
21990Sstevel@tonic-gate dbva.va_mask = AT_ALL;
22005331Samw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
22010Sstevel@tonic-gate } else
22020Sstevel@tonic-gate dbvap = NULL;
22030Sstevel@tonic-gate #else
22040Sstevel@tonic-gate dbva.va_mask = AT_ALL;
22055331Samw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
22060Sstevel@tonic-gate #endif
22070Sstevel@tonic-gate davap = dbvap;
22080Sstevel@tonic-gate
22090Sstevel@tonic-gate if (args->where.name == nfs3nametoolong) {
22100Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG;
22115982Sahl goto err1;
22120Sstevel@tonic-gate }
22130Sstevel@tonic-gate
22140Sstevel@tonic-gate if (args->where.name == NULL || *(args->where.name) == '\0') {
22150Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
22165982Sahl goto err1;
22170Sstevel@tonic-gate }
22180Sstevel@tonic-gate
22190Sstevel@tonic-gate if (rdonly(exi, req)) {
22200Sstevel@tonic-gate resp->status = NFS3ERR_ROFS;
22215982Sahl goto err1;
22220Sstevel@tonic-gate }
22230Sstevel@tonic-gate
22244971Sjarrett if (is_system_labeled()) {
22254971Sjarrett bslabel_t *clabel = req->rq_label;
22264971Sjarrett
22274971Sjarrett ASSERT(clabel != NULL);
22284971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
22294971Sjarrett "got client label from request(1)", struct svc_req *, req);
22304971Sjarrett
22314971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
22329871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
22339871SJarrett.Lu@Sun.COM exi)) {
22344971Sjarrett resp->status = NFS3ERR_ACCES;
22355982Sahl goto err1;
22364971Sjarrett }
22374971Sjarrett }
22384971Sjarrett }
22394971Sjarrett
22400Sstevel@tonic-gate error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
22410Sstevel@tonic-gate if (error)
22425982Sahl goto err;
22430Sstevel@tonic-gate
22440Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) {
22450Sstevel@tonic-gate resp->status = NFS3ERR_INVAL;
22465982Sahl goto err1;
22470Sstevel@tonic-gate }
22480Sstevel@tonic-gate
22490Sstevel@tonic-gate if (args->symlink.symlink_data == nfs3nametoolong) {
22500Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG;
22515982Sahl goto err1;
22520Sstevel@tonic-gate }
22530Sstevel@tonic-gate
22547961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
22557961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, args->where.name,
22567961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
22577961SNatalie.Li@Sun.COM
22587961SNatalie.Li@Sun.COM if (name == NULL) {
22597961SNatalie.Li@Sun.COM /* This is really a Solaris EILSEQ */
22607961SNatalie.Li@Sun.COM resp->status = NFS3ERR_INVAL;
22617961SNatalie.Li@Sun.COM goto err1;
22627961SNatalie.Li@Sun.COM }
22637961SNatalie.Li@Sun.COM
22647961SNatalie.Li@Sun.COM symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data,
22657961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
22667961SNatalie.Li@Sun.COM if (symdata == NULL) {
22677961SNatalie.Li@Sun.COM /* This is really a Solaris EILSEQ */
22687961SNatalie.Li@Sun.COM resp->status = NFS3ERR_INVAL;
22697961SNatalie.Li@Sun.COM goto err1;
22707961SNatalie.Li@Sun.COM }
22717961SNatalie.Li@Sun.COM
22727961SNatalie.Li@Sun.COM
22730Sstevel@tonic-gate va.va_mask |= AT_TYPE;
22740Sstevel@tonic-gate va.va_type = VLNK;
22750Sstevel@tonic-gate
22767961SNatalie.Li@Sun.COM error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
22770Sstevel@tonic-gate
22780Sstevel@tonic-gate #ifdef DEBUG
22790Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
22800Sstevel@tonic-gate dava.va_mask = AT_ALL;
22815331Samw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
22820Sstevel@tonic-gate } else
22830Sstevel@tonic-gate davap = NULL;
22840Sstevel@tonic-gate #else
22850Sstevel@tonic-gate dava.va_mask = AT_ALL;
22865331Samw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
22870Sstevel@tonic-gate #endif
22880Sstevel@tonic-gate
22890Sstevel@tonic-gate if (error)
22905982Sahl goto err;
22910Sstevel@tonic-gate
22927961SNatalie.Li@Sun.COM error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
22935599Sjwahlig NULL, NULL, NULL);
22940Sstevel@tonic-gate
22950Sstevel@tonic-gate /*
22960Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
22970Sstevel@tonic-gate */
22985331Samw (void) VOP_FSYNC(dvp, 0, cr, NULL);
22990Sstevel@tonic-gate
23000Sstevel@tonic-gate
23010Sstevel@tonic-gate resp->status = NFS3_OK;
23020Sstevel@tonic-gate if (error) {
23030Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE;
23040Sstevel@tonic-gate vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes);
23050Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
23065982Sahl goto out;
23070Sstevel@tonic-gate }
23080Sstevel@tonic-gate
23090Sstevel@tonic-gate #ifdef DEBUG
23100Sstevel@tonic-gate if (!rfs3_do_post_op_fh3)
23110Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE;
23120Sstevel@tonic-gate else {
23130Sstevel@tonic-gate #endif
23140Sstevel@tonic-gate error = makefh3(&resp->resok.obj.handle, vp, exi);
23150Sstevel@tonic-gate if (error)
23160Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE;
23170Sstevel@tonic-gate else
23180Sstevel@tonic-gate resp->resok.obj.handle_follows = TRUE;
23190Sstevel@tonic-gate #ifdef DEBUG
23200Sstevel@tonic-gate }
23210Sstevel@tonic-gate #endif
23220Sstevel@tonic-gate
23230Sstevel@tonic-gate #ifdef DEBUG
23240Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
23250Sstevel@tonic-gate va.va_mask = AT_ALL;
23265331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
23270Sstevel@tonic-gate } else
23280Sstevel@tonic-gate vap = NULL;
23290Sstevel@tonic-gate #else
23300Sstevel@tonic-gate va.va_mask = AT_ALL;
23315331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
23320Sstevel@tonic-gate #endif
23330Sstevel@tonic-gate
23340Sstevel@tonic-gate /*
23350Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
23360Sstevel@tonic-gate */
23375331Samw (void) VOP_FSYNC(vp, 0, cr, NULL);
23380Sstevel@tonic-gate
23390Sstevel@tonic-gate VN_RELE(vp);
23400Sstevel@tonic-gate
23410Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
23420Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
23435982Sahl goto out;
23445982Sahl
23455982Sahl err:
23460Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
23470Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
23480Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
23490Sstevel@tonic-gate } else
23500Sstevel@tonic-gate resp->status = puterrno3(error);
23515982Sahl err1:
23525982Sahl vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
23535982Sahl out:
23547961SNatalie.Li@Sun.COM if (name != NULL && name != args->where.name)
23557961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN + 1);
23567961SNatalie.Li@Sun.COM if (symdata != NULL && symdata != args->symlink.symlink_data)
23577961SNatalie.Li@Sun.COM kmem_free(symdata, MAXPATHLEN + 1);
23587961SNatalie.Li@Sun.COM
23595982Sahl DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
23605982Sahl cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
23615982Sahl
23620Sstevel@tonic-gate if (dvp != NULL)
23630Sstevel@tonic-gate VN_RELE(dvp);
23640Sstevel@tonic-gate }
23650Sstevel@tonic-gate
23661610Sthurlow void *
rfs3_symlink_getfh(SYMLINK3args * args)23670Sstevel@tonic-gate rfs3_symlink_getfh(SYMLINK3args *args)
23680Sstevel@tonic-gate {
23690Sstevel@tonic-gate
23701610Sthurlow return (&args->where.dir);
23710Sstevel@tonic-gate }
23720Sstevel@tonic-gate
23730Sstevel@tonic-gate void
rfs3_mknod(MKNOD3args * args,MKNOD3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)23740Sstevel@tonic-gate rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
23750Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
23760Sstevel@tonic-gate {
23770Sstevel@tonic-gate int error;
23780Sstevel@tonic-gate vnode_t *vp;
23796402Sgt29601 vnode_t *realvp;
23800Sstevel@tonic-gate vnode_t *dvp;
23810Sstevel@tonic-gate struct vattr *vap;
23820Sstevel@tonic-gate struct vattr va;
23830Sstevel@tonic-gate struct vattr *dbvap;
23840Sstevel@tonic-gate struct vattr dbva;
23850Sstevel@tonic-gate struct vattr *davap;
23860Sstevel@tonic-gate struct vattr dava;
23870Sstevel@tonic-gate int mode;
23880Sstevel@tonic-gate enum vcexcl excl;
23897961SNatalie.Li@Sun.COM struct sockaddr *ca;
23907961SNatalie.Li@Sun.COM char *name = NULL;
23910Sstevel@tonic-gate
23920Sstevel@tonic-gate dbvap = NULL;
23930Sstevel@tonic-gate davap = NULL;
23940Sstevel@tonic-gate
23951610Sthurlow dvp = nfs3_fhtovp(&args->where.dir, exi);
23965982Sahl
23975982Sahl DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
23985982Sahl cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
23995982Sahl
24000Sstevel@tonic-gate if (dvp == NULL) {
24010Sstevel@tonic-gate error = ESTALE;
24020Sstevel@tonic-gate goto out;
24030Sstevel@tonic-gate }
24040Sstevel@tonic-gate
24050Sstevel@tonic-gate #ifdef DEBUG
24060Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
24070Sstevel@tonic-gate dbva.va_mask = AT_ALL;
24085331Samw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
24090Sstevel@tonic-gate } else
24100Sstevel@tonic-gate dbvap = NULL;
24110Sstevel@tonic-gate #else
24120Sstevel@tonic-gate dbva.va_mask = AT_ALL;
24135331Samw dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
24140Sstevel@tonic-gate #endif
24150Sstevel@tonic-gate davap = dbvap;
24160Sstevel@tonic-gate
24170Sstevel@tonic-gate if (args->where.name == nfs3nametoolong) {
24180Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG;
24190Sstevel@tonic-gate goto out1;
24200Sstevel@tonic-gate }
24210Sstevel@tonic-gate
24220Sstevel@tonic-gate if (args->where.name == NULL || *(args->where.name) == '\0') {
24230Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
24240Sstevel@tonic-gate goto out1;
24250Sstevel@tonic-gate }
24260Sstevel@tonic-gate
24270Sstevel@tonic-gate if (rdonly(exi, req)) {
24280Sstevel@tonic-gate resp->status = NFS3ERR_ROFS;
24290Sstevel@tonic-gate goto out1;
24300Sstevel@tonic-gate }
24310Sstevel@tonic-gate
24324971Sjarrett if (is_system_labeled()) {
24334971Sjarrett bslabel_t *clabel = req->rq_label;
24344971Sjarrett
24354971Sjarrett ASSERT(clabel != NULL);
24364971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
24374971Sjarrett "got client label from request(1)", struct svc_req *, req);
24384971Sjarrett
24394971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
24409871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
24419871SJarrett.Lu@Sun.COM exi)) {
24424971Sjarrett resp->status = NFS3ERR_ACCES;
24434971Sjarrett goto out1;
24444971Sjarrett }
24454971Sjarrett }
24464971Sjarrett }
24474971Sjarrett
24480Sstevel@tonic-gate switch (args->what.type) {
24490Sstevel@tonic-gate case NF3CHR:
24500Sstevel@tonic-gate case NF3BLK:
24510Sstevel@tonic-gate error = sattr3_to_vattr(
24520Sstevel@tonic-gate &args->what.mknoddata3_u.device.dev_attributes, &va);
24530Sstevel@tonic-gate if (error)
24540Sstevel@tonic-gate goto out;
24550Sstevel@tonic-gate if (secpolicy_sys_devices(cr) != 0) {
24560Sstevel@tonic-gate resp->status = NFS3ERR_PERM;
24570Sstevel@tonic-gate goto out1;
24580Sstevel@tonic-gate }
24590Sstevel@tonic-gate if (args->what.type == NF3CHR)
24600Sstevel@tonic-gate va.va_type = VCHR;
24610Sstevel@tonic-gate else
24620Sstevel@tonic-gate va.va_type = VBLK;
24630Sstevel@tonic-gate va.va_rdev = makedevice(
24640Sstevel@tonic-gate args->what.mknoddata3_u.device.spec.specdata1,
24650Sstevel@tonic-gate args->what.mknoddata3_u.device.spec.specdata2);
24660Sstevel@tonic-gate va.va_mask |= AT_TYPE | AT_RDEV;
24670Sstevel@tonic-gate break;
24680Sstevel@tonic-gate case NF3SOCK:
24690Sstevel@tonic-gate error = sattr3_to_vattr(
24700Sstevel@tonic-gate &args->what.mknoddata3_u.pipe_attributes, &va);
24710Sstevel@tonic-gate if (error)
24720Sstevel@tonic-gate goto out;
24730Sstevel@tonic-gate va.va_type = VSOCK;
24740Sstevel@tonic-gate va.va_mask |= AT_TYPE;
24750Sstevel@tonic-gate break;
24760Sstevel@tonic-gate case NF3FIFO:
24770Sstevel@tonic-gate error = sattr3_to_vattr(
24780Sstevel@tonic-gate &args->what.mknoddata3_u.pipe_attributes, &va);
24790Sstevel@tonic-gate if (error)
24800Sstevel@tonic-gate goto out;
24810Sstevel@tonic-gate va.va_type = VFIFO;
24820Sstevel@tonic-gate va.va_mask |= AT_TYPE;
24830Sstevel@tonic-gate break;
24840Sstevel@tonic-gate default:
24850Sstevel@tonic-gate resp->status = NFS3ERR_BADTYPE;
24860Sstevel@tonic-gate goto out1;
24870Sstevel@tonic-gate }
24880Sstevel@tonic-gate
24890Sstevel@tonic-gate /*
24900Sstevel@tonic-gate * Must specify the mode.
24910Sstevel@tonic-gate */
24920Sstevel@tonic-gate if (!(va.va_mask & AT_MODE)) {
24930Sstevel@tonic-gate resp->status = NFS3ERR_INVAL;
24940Sstevel@tonic-gate goto out1;
24950Sstevel@tonic-gate }
24960Sstevel@tonic-gate
24977961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
24987961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, args->where.name,
24997961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
25007961SNatalie.Li@Sun.COM
25017961SNatalie.Li@Sun.COM if (name == NULL) {
25027961SNatalie.Li@Sun.COM resp->status = NFS3ERR_INVAL;
25037961SNatalie.Li@Sun.COM goto out1;
25047961SNatalie.Li@Sun.COM }
25057961SNatalie.Li@Sun.COM
25060Sstevel@tonic-gate excl = EXCL;
25070Sstevel@tonic-gate
25080Sstevel@tonic-gate mode = 0;
25090Sstevel@tonic-gate
25107961SNatalie.Li@Sun.COM error = VOP_CREATE(dvp, name, &va, excl, mode,
25115331Samw &vp, cr, 0, NULL, NULL);
25120Sstevel@tonic-gate
25137961SNatalie.Li@Sun.COM if (name != args->where.name)
25147961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN + 1);
25157961SNatalie.Li@Sun.COM
25160Sstevel@tonic-gate #ifdef DEBUG
25170Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
25180Sstevel@tonic-gate dava.va_mask = AT_ALL;
25195331Samw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
25200Sstevel@tonic-gate } else
25210Sstevel@tonic-gate davap = NULL;
25220Sstevel@tonic-gate #else
25230Sstevel@tonic-gate dava.va_mask = AT_ALL;
25245331Samw davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
25250Sstevel@tonic-gate #endif
25260Sstevel@tonic-gate
25270Sstevel@tonic-gate /*
25280Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
25290Sstevel@tonic-gate */
25305331Samw (void) VOP_FSYNC(dvp, 0, cr, NULL);
25310Sstevel@tonic-gate
25320Sstevel@tonic-gate if (error)
25330Sstevel@tonic-gate goto out;
25340Sstevel@tonic-gate
25350Sstevel@tonic-gate resp->status = NFS3_OK;
25360Sstevel@tonic-gate
25370Sstevel@tonic-gate #ifdef DEBUG
25380Sstevel@tonic-gate if (!rfs3_do_post_op_fh3)
25390Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE;
25400Sstevel@tonic-gate else {
25410Sstevel@tonic-gate #endif
25420Sstevel@tonic-gate error = makefh3(&resp->resok.obj.handle, vp, exi);
25430Sstevel@tonic-gate if (error)
25440Sstevel@tonic-gate resp->resok.obj.handle_follows = FALSE;
25450Sstevel@tonic-gate else
25460Sstevel@tonic-gate resp->resok.obj.handle_follows = TRUE;
25470Sstevel@tonic-gate #ifdef DEBUG
25480Sstevel@tonic-gate }
25490Sstevel@tonic-gate #endif
25500Sstevel@tonic-gate
25510Sstevel@tonic-gate #ifdef DEBUG
25520Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
25530Sstevel@tonic-gate va.va_mask = AT_ALL;
25545331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
25550Sstevel@tonic-gate } else
25560Sstevel@tonic-gate vap = NULL;
25570Sstevel@tonic-gate #else
25580Sstevel@tonic-gate va.va_mask = AT_ALL;
25595331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
25600Sstevel@tonic-gate #endif
25610Sstevel@tonic-gate
25620Sstevel@tonic-gate /*
25630Sstevel@tonic-gate * Force modified metadata out to stable storage.
25646402Sgt29601 *
25656402Sgt29601 * if a underlying vp exists, pass it to VOP_FSYNC
25660Sstevel@tonic-gate */
25676402Sgt29601 if (VOP_REALVP(vp, &realvp, NULL) == 0)
25686402Sgt29601 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
25696402Sgt29601 else
25706402Sgt29601 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
25710Sstevel@tonic-gate
25720Sstevel@tonic-gate VN_RELE(vp);
25730Sstevel@tonic-gate
25740Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
25750Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
25765982Sahl DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
25775982Sahl cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
25785982Sahl VN_RELE(dvp);
25790Sstevel@tonic-gate return;
25800Sstevel@tonic-gate
25810Sstevel@tonic-gate out:
25820Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
25830Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
25840Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
25850Sstevel@tonic-gate } else
25860Sstevel@tonic-gate resp->status = puterrno3(error);
25870Sstevel@tonic-gate out1:
25885982Sahl DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
25895982Sahl cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
25900Sstevel@tonic-gate if (dvp != NULL)
25910Sstevel@tonic-gate VN_RELE(dvp);
25920Sstevel@tonic-gate vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
25930Sstevel@tonic-gate }
25940Sstevel@tonic-gate
25951610Sthurlow void *
rfs3_mknod_getfh(MKNOD3args * args)25960Sstevel@tonic-gate rfs3_mknod_getfh(MKNOD3args *args)
25970Sstevel@tonic-gate {
25980Sstevel@tonic-gate
25991610Sthurlow return (&args->where.dir);
26000Sstevel@tonic-gate }
26010Sstevel@tonic-gate
26020Sstevel@tonic-gate void
rfs3_remove(REMOVE3args * args,REMOVE3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)26030Sstevel@tonic-gate rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
26040Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
26050Sstevel@tonic-gate {
26060Sstevel@tonic-gate int error = 0;
26070Sstevel@tonic-gate vnode_t *vp;
26080Sstevel@tonic-gate struct vattr *bvap;
26090Sstevel@tonic-gate struct vattr bva;
26100Sstevel@tonic-gate struct vattr *avap;
26110Sstevel@tonic-gate struct vattr ava;
26120Sstevel@tonic-gate vnode_t *targvp = NULL;
26137961SNatalie.Li@Sun.COM struct sockaddr *ca;
26147961SNatalie.Li@Sun.COM char *name = NULL;
26150Sstevel@tonic-gate
26160Sstevel@tonic-gate bvap = NULL;
26170Sstevel@tonic-gate avap = NULL;
26180Sstevel@tonic-gate
26191610Sthurlow vp = nfs3_fhtovp(&args->object.dir, exi);
26205982Sahl
26215982Sahl DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
26225982Sahl cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
26235982Sahl
26240Sstevel@tonic-gate if (vp == NULL) {
26250Sstevel@tonic-gate error = ESTALE;
26265982Sahl goto err;
26270Sstevel@tonic-gate }
26280Sstevel@tonic-gate
26290Sstevel@tonic-gate #ifdef DEBUG
26300Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
26310Sstevel@tonic-gate bva.va_mask = AT_ALL;
26325331Samw bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
26330Sstevel@tonic-gate } else
26340Sstevel@tonic-gate bvap = NULL;
26350Sstevel@tonic-gate #else
26360Sstevel@tonic-gate bva.va_mask = AT_ALL;
26375331Samw bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
26380Sstevel@tonic-gate #endif
26390Sstevel@tonic-gate avap = bvap;
26400Sstevel@tonic-gate
26410Sstevel@tonic-gate if (vp->v_type != VDIR) {
26420Sstevel@tonic-gate resp->status = NFS3ERR_NOTDIR;
26435982Sahl goto err1;
26440Sstevel@tonic-gate }
26450Sstevel@tonic-gate
26460Sstevel@tonic-gate if (args->object.name == nfs3nametoolong) {
26470Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG;
26485982Sahl goto err1;
26490Sstevel@tonic-gate }
26500Sstevel@tonic-gate
26510Sstevel@tonic-gate if (args->object.name == NULL || *(args->object.name) == '\0') {
26520Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
26535982Sahl goto err1;
26540Sstevel@tonic-gate }
26550Sstevel@tonic-gate
26560Sstevel@tonic-gate if (rdonly(exi, req)) {
26570Sstevel@tonic-gate resp->status = NFS3ERR_ROFS;
26585982Sahl goto err1;
26590Sstevel@tonic-gate }
26600Sstevel@tonic-gate
26614971Sjarrett if (is_system_labeled()) {
26624971Sjarrett bslabel_t *clabel = req->rq_label;
26634971Sjarrett
26644971Sjarrett ASSERT(clabel != NULL);
26654971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *,
26664971Sjarrett "got client label from request(1)", struct svc_req *, req);
26674971Sjarrett
26684971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
26699871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
26709871SJarrett.Lu@Sun.COM exi)) {
26714971Sjarrett resp->status = NFS3ERR_ACCES;
26725982Sahl goto err1;
26734971Sjarrett }
26744971Sjarrett }
26754971Sjarrett }
26764971Sjarrett
26777961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
26787961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, args->object.name,
26797961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
26807961SNatalie.Li@Sun.COM
26817961SNatalie.Li@Sun.COM if (name == NULL) {
26827961SNatalie.Li@Sun.COM resp->status = NFS3ERR_INVAL;
26837961SNatalie.Li@Sun.COM goto err1;
26847961SNatalie.Li@Sun.COM }
26857961SNatalie.Li@Sun.COM
26860Sstevel@tonic-gate /*
26870Sstevel@tonic-gate * Check for a conflict with a non-blocking mandatory share
26880Sstevel@tonic-gate * reservation and V4 delegations
26890Sstevel@tonic-gate */
26907961SNatalie.Li@Sun.COM error = VOP_LOOKUP(vp, name, &targvp, NULL, 0,
26915599Sjwahlig NULL, cr, NULL, NULL, NULL);
26920Sstevel@tonic-gate if (error != 0)
26935982Sahl goto err;
26940Sstevel@tonic-gate
26950Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
26960Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
26975982Sahl goto err1;
26980Sstevel@tonic-gate }
26990Sstevel@tonic-gate
27000Sstevel@tonic-gate if (!nbl_need_check(targvp)) {
27017961SNatalie.Li@Sun.COM error = VOP_REMOVE(vp, name, cr, NULL, 0);
27020Sstevel@tonic-gate } else {
27030Sstevel@tonic-gate nbl_start_crit(targvp, RW_READER);
27045331Samw if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
27050Sstevel@tonic-gate error = EACCES;
27060Sstevel@tonic-gate } else {
27077961SNatalie.Li@Sun.COM error = VOP_REMOVE(vp, name, cr, NULL, 0);
27080Sstevel@tonic-gate }
27090Sstevel@tonic-gate nbl_end_crit(targvp);
27100Sstevel@tonic-gate }
27110Sstevel@tonic-gate VN_RELE(targvp);
27120Sstevel@tonic-gate targvp = NULL;
27130Sstevel@tonic-gate
27140Sstevel@tonic-gate #ifdef DEBUG
27150Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
27160Sstevel@tonic-gate ava.va_mask = AT_ALL;
27175331Samw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
27180Sstevel@tonic-gate } else
27190Sstevel@tonic-gate avap = NULL;
27200Sstevel@tonic-gate #else
27210Sstevel@tonic-gate ava.va_mask = AT_ALL;
27225331Samw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
27230Sstevel@tonic-gate #endif
27240Sstevel@tonic-gate
27250Sstevel@tonic-gate /*
27260Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
27270Sstevel@tonic-gate */
27285331Samw (void) VOP_FSYNC(vp, 0, cr, NULL);
27290Sstevel@tonic-gate
27300Sstevel@tonic-gate if (error)
27315982Sahl goto err;
27320Sstevel@tonic-gate
27330Sstevel@tonic-gate resp->status = NFS3_OK;
27340Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
27355982Sahl goto out;
27365982Sahl
27375982Sahl err:
27380Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
27390Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
27400Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
27410Sstevel@tonic-gate } else
27420Sstevel@tonic-gate resp->status = puterrno3(error);
27435982Sahl err1:
27445982Sahl vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
27455982Sahl out:
27465982Sahl DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
27475982Sahl cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
27487961SNatalie.Li@Sun.COM
27497961SNatalie.Li@Sun.COM if (name != NULL && name != args->object.name)
27507961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN + 1);
27517961SNatalie.Li@Sun.COM
27520Sstevel@tonic-gate if (vp != NULL)
27530Sstevel@tonic-gate VN_RELE(vp);
27540Sstevel@tonic-gate }
27550Sstevel@tonic-gate
27561610Sthurlow void *
rfs3_remove_getfh(REMOVE3args * args)27570Sstevel@tonic-gate rfs3_remove_getfh(REMOVE3args *args)
27580Sstevel@tonic-gate {
27590Sstevel@tonic-gate
27601610Sthurlow return (&args->object.dir);
27610Sstevel@tonic-gate }
27620Sstevel@tonic-gate
27630Sstevel@tonic-gate void
rfs3_rmdir(RMDIR3args * args,RMDIR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)27640Sstevel@tonic-gate rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
27650Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
27660Sstevel@tonic-gate {
27670Sstevel@tonic-gate int error;
27680Sstevel@tonic-gate vnode_t *vp;
27690Sstevel@tonic-gate struct vattr *bvap;
27700Sstevel@tonic-gate struct vattr bva;
27710Sstevel@tonic-gate struct vattr *avap;
27720Sstevel@tonic-gate struct vattr ava;
27737961SNatalie.Li@Sun.COM struct sockaddr *ca;
27747961SNatalie.Li@Sun.COM char *name = NULL;
27750Sstevel@tonic-gate
27760Sstevel@tonic-gate bvap = NULL;
27770Sstevel@tonic-gate avap = NULL;
27780Sstevel@tonic-gate
27791610Sthurlow vp = nfs3_fhtovp(&args->object.dir, exi);
27805982Sahl
27815982Sahl DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
27825982Sahl cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
27835982Sahl
27840Sstevel@tonic-gate if (vp == NULL) {
27850Sstevel@tonic-gate error = ESTALE;
27865982Sahl goto err;
27870Sstevel@tonic-gate }
27880Sstevel@tonic-gate
27890Sstevel@tonic-gate #ifdef DEBUG
27900Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
27910Sstevel@tonic-gate bva.va_mask = AT_ALL;
27925331Samw bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
27930Sstevel@tonic-gate } else
27940Sstevel@tonic-gate bvap = NULL;
27950Sstevel@tonic-gate #else
27960Sstevel@tonic-gate bva.va_mask = AT_ALL;
27975331Samw bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
27980Sstevel@tonic-gate #endif
27990Sstevel@tonic-gate avap = bvap;
28000Sstevel@tonic-gate
28010Sstevel@tonic-gate if (vp->v_type != VDIR) {
28020Sstevel@tonic-gate resp->status = NFS3ERR_NOTDIR;
28035982Sahl goto err1;
28040Sstevel@tonic-gate }
28050Sstevel@tonic-gate
28060Sstevel@tonic-gate if (args->object.name == nfs3nametoolong) {
28070Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG;
28085982Sahl goto err1;
28090Sstevel@tonic-gate }
28100Sstevel@tonic-gate
28110Sstevel@tonic-gate if (args->object.name == NULL || *(args->object.name) == '\0') {
28120Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
28135982Sahl goto err1;
28140Sstevel@tonic-gate }
28150Sstevel@tonic-gate
28160Sstevel@tonic-gate if (rdonly(exi, req)) {
28170Sstevel@tonic-gate resp->status = NFS3ERR_ROFS;
28185982Sahl goto err1;
28190Sstevel@tonic-gate }
28200Sstevel@tonic-gate
28214971Sjarrett if (is_system_labeled()) {
28224971Sjarrett bslabel_t *clabel = req->rq_label;
28234971Sjarrett
28244971Sjarrett ASSERT(clabel != NULL);
28254971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *,
28264971Sjarrett "got client label from request(1)", struct svc_req *, req);
28274971Sjarrett
28284971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
28299871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
28309871SJarrett.Lu@Sun.COM exi)) {
28314971Sjarrett resp->status = NFS3ERR_ACCES;
28325982Sahl goto err1;
28334971Sjarrett }
28344971Sjarrett }
28354971Sjarrett }
28364971Sjarrett
28377961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
28387961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, args->object.name,
28397961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
28407961SNatalie.Li@Sun.COM
28417961SNatalie.Li@Sun.COM if (name == NULL) {
28427961SNatalie.Li@Sun.COM resp->status = NFS3ERR_INVAL;
28437961SNatalie.Li@Sun.COM goto err1;
28447961SNatalie.Li@Sun.COM }
28457961SNatalie.Li@Sun.COM
28467961SNatalie.Li@Sun.COM error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
28477961SNatalie.Li@Sun.COM
28487961SNatalie.Li@Sun.COM if (name != args->object.name)
28497961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN + 1);
28500Sstevel@tonic-gate
28510Sstevel@tonic-gate #ifdef DEBUG
28520Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
28530Sstevel@tonic-gate ava.va_mask = AT_ALL;
28545331Samw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
28550Sstevel@tonic-gate } else
28560Sstevel@tonic-gate avap = NULL;
28570Sstevel@tonic-gate #else
28580Sstevel@tonic-gate ava.va_mask = AT_ALL;
28595331Samw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
28600Sstevel@tonic-gate #endif
28610Sstevel@tonic-gate
28620Sstevel@tonic-gate /*
28630Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
28640Sstevel@tonic-gate */
28655331Samw (void) VOP_FSYNC(vp, 0, cr, NULL);
28660Sstevel@tonic-gate
28670Sstevel@tonic-gate if (error) {
28680Sstevel@tonic-gate /*
28690Sstevel@tonic-gate * System V defines rmdir to return EEXIST, not ENOTEMPTY,
28700Sstevel@tonic-gate * if the directory is not empty. A System V NFS server
28710Sstevel@tonic-gate * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
28720Sstevel@tonic-gate * over the wire.
28730Sstevel@tonic-gate */
28740Sstevel@tonic-gate if (error == EEXIST)
28750Sstevel@tonic-gate error = ENOTEMPTY;
28765982Sahl goto err;
28770Sstevel@tonic-gate }
28780Sstevel@tonic-gate
28790Sstevel@tonic-gate resp->status = NFS3_OK;
28800Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
28815982Sahl goto out;
28825982Sahl
28835982Sahl err:
28840Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
28850Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
28860Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
28870Sstevel@tonic-gate } else
28880Sstevel@tonic-gate resp->status = puterrno3(error);
28895982Sahl err1:
28905982Sahl vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
28915982Sahl out:
28925982Sahl DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req,
28935982Sahl cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp);
28940Sstevel@tonic-gate if (vp != NULL)
28950Sstevel@tonic-gate VN_RELE(vp);
28965982Sahl
28970Sstevel@tonic-gate }
28980Sstevel@tonic-gate
28991610Sthurlow void *
rfs3_rmdir_getfh(RMDIR3args * args)29000Sstevel@tonic-gate rfs3_rmdir_getfh(RMDIR3args *args)
29010Sstevel@tonic-gate {
29020Sstevel@tonic-gate
29031610Sthurlow return (&args->object.dir);
29040Sstevel@tonic-gate }
29050Sstevel@tonic-gate
29060Sstevel@tonic-gate void
rfs3_rename(RENAME3args * args,RENAME3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)29070Sstevel@tonic-gate rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
29080Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
29090Sstevel@tonic-gate {
29100Sstevel@tonic-gate int error = 0;
29110Sstevel@tonic-gate vnode_t *fvp;
29120Sstevel@tonic-gate vnode_t *tvp;
29130Sstevel@tonic-gate vnode_t *targvp;
29140Sstevel@tonic-gate struct vattr *fbvap;
29150Sstevel@tonic-gate struct vattr fbva;
29160Sstevel@tonic-gate struct vattr *favap;
29170Sstevel@tonic-gate struct vattr fava;
29180Sstevel@tonic-gate struct vattr *tbvap;
29190Sstevel@tonic-gate struct vattr tbva;
29200Sstevel@tonic-gate struct vattr *tavap;
29210Sstevel@tonic-gate struct vattr tava;
29221610Sthurlow nfs_fh3 *fh3;
29230Sstevel@tonic-gate struct exportinfo *to_exi;
29240Sstevel@tonic-gate vnode_t *srcvp = NULL;
29254971Sjarrett bslabel_t *clabel;
29267961SNatalie.Li@Sun.COM struct sockaddr *ca;
29277961SNatalie.Li@Sun.COM char *name = NULL;
29287961SNatalie.Li@Sun.COM char *toname = NULL;
29290Sstevel@tonic-gate
29300Sstevel@tonic-gate fbvap = NULL;
29310Sstevel@tonic-gate favap = NULL;
29320Sstevel@tonic-gate tbvap = NULL;
29330Sstevel@tonic-gate tavap = NULL;
29340Sstevel@tonic-gate tvp = NULL;
29350Sstevel@tonic-gate
29361610Sthurlow fvp = nfs3_fhtovp(&args->from.dir, exi);
29375982Sahl
29385982Sahl DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req,
29395982Sahl cred_t *, cr, vnode_t *, fvp, RENAME3args *, args);
29405982Sahl
29410Sstevel@tonic-gate if (fvp == NULL) {
29420Sstevel@tonic-gate error = ESTALE;
29435982Sahl goto err;
29440Sstevel@tonic-gate }
29450Sstevel@tonic-gate
29464971Sjarrett if (is_system_labeled()) {
29474971Sjarrett clabel = req->rq_label;
29484971Sjarrett ASSERT(clabel != NULL);
29494971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
29504971Sjarrett "got client label from request(1)", struct svc_req *, req);
29514971Sjarrett
29524971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
29539871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
29549871SJarrett.Lu@Sun.COM exi)) {
29554971Sjarrett resp->status = NFS3ERR_ACCES;
29565982Sahl goto err1;
29574971Sjarrett }
29584971Sjarrett }
29594971Sjarrett }
29604971Sjarrett
29610Sstevel@tonic-gate #ifdef DEBUG
29620Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
29630Sstevel@tonic-gate fbva.va_mask = AT_ALL;
29645331Samw fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
29650Sstevel@tonic-gate } else
29660Sstevel@tonic-gate fbvap = NULL;
29670Sstevel@tonic-gate #else
29680Sstevel@tonic-gate fbva.va_mask = AT_ALL;
29695331Samw fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
29700Sstevel@tonic-gate #endif
29710Sstevel@tonic-gate favap = fbvap;
29720Sstevel@tonic-gate
29731610Sthurlow fh3 = &args->to.dir;
29741610Sthurlow to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
29750Sstevel@tonic-gate if (to_exi == NULL) {
29760Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
29775982Sahl goto err1;
29780Sstevel@tonic-gate }
29790Sstevel@tonic-gate exi_rele(to_exi);
29800Sstevel@tonic-gate
29810Sstevel@tonic-gate if (to_exi != exi) {
29820Sstevel@tonic-gate resp->status = NFS3ERR_XDEV;
29835982Sahl goto err1;
29840Sstevel@tonic-gate }
29850Sstevel@tonic-gate
29861610Sthurlow tvp = nfs3_fhtovp(&args->to.dir, exi);
29870Sstevel@tonic-gate if (tvp == NULL) {
29880Sstevel@tonic-gate error = ESTALE;
29895982Sahl goto err;
29900Sstevel@tonic-gate }
29910Sstevel@tonic-gate
29920Sstevel@tonic-gate #ifdef DEBUG
29930Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
29940Sstevel@tonic-gate tbva.va_mask = AT_ALL;
29955331Samw tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
29960Sstevel@tonic-gate } else
29970Sstevel@tonic-gate tbvap = NULL;
29980Sstevel@tonic-gate #else
29990Sstevel@tonic-gate tbva.va_mask = AT_ALL;
30005331Samw tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
30010Sstevel@tonic-gate #endif
30020Sstevel@tonic-gate tavap = tbvap;
30030Sstevel@tonic-gate
30040Sstevel@tonic-gate if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
30050Sstevel@tonic-gate resp->status = NFS3ERR_NOTDIR;
30065982Sahl goto err1;
30070Sstevel@tonic-gate }
30080Sstevel@tonic-gate
30090Sstevel@tonic-gate if (args->from.name == nfs3nametoolong ||
30100Sstevel@tonic-gate args->to.name == nfs3nametoolong) {
30110Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG;
30125982Sahl goto err1;
30130Sstevel@tonic-gate }
30140Sstevel@tonic-gate if (args->from.name == NULL || *(args->from.name) == '\0' ||
30150Sstevel@tonic-gate args->to.name == NULL || *(args->to.name) == '\0') {
30160Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
30175982Sahl goto err1;
30180Sstevel@tonic-gate }
30190Sstevel@tonic-gate
30200Sstevel@tonic-gate if (rdonly(exi, req)) {
30210Sstevel@tonic-gate resp->status = NFS3ERR_ROFS;
30225982Sahl goto err1;
30230Sstevel@tonic-gate }
30240Sstevel@tonic-gate
30254971Sjarrett if (is_system_labeled()) {
30264971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
30279871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
30289871SJarrett.Lu@Sun.COM exi)) {
30294971Sjarrett resp->status = NFS3ERR_ACCES;
30305982Sahl goto err1;
30314971Sjarrett }
30324971Sjarrett }
30334971Sjarrett }
30344971Sjarrett
30357961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
30367961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, args->from.name,
30377961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
30387961SNatalie.Li@Sun.COM
30397961SNatalie.Li@Sun.COM if (name == NULL) {
30407961SNatalie.Li@Sun.COM resp->status = NFS3ERR_INVAL;
30417961SNatalie.Li@Sun.COM goto err1;
30427961SNatalie.Li@Sun.COM }
30437961SNatalie.Li@Sun.COM
30447961SNatalie.Li@Sun.COM toname = nfscmd_convname(ca, exi, args->to.name,
30457961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
30467961SNatalie.Li@Sun.COM
30477961SNatalie.Li@Sun.COM if (toname == NULL) {
30487961SNatalie.Li@Sun.COM resp->status = NFS3ERR_INVAL;
30497961SNatalie.Li@Sun.COM goto err1;
30507961SNatalie.Li@Sun.COM }
30517961SNatalie.Li@Sun.COM
30520Sstevel@tonic-gate /*
30530Sstevel@tonic-gate * Check for a conflict with a non-blocking mandatory share
30540Sstevel@tonic-gate * reservation or V4 delegations.
30550Sstevel@tonic-gate */
30567961SNatalie.Li@Sun.COM error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
30575599Sjwahlig NULL, cr, NULL, NULL, NULL);
30580Sstevel@tonic-gate if (error != 0)
30595982Sahl goto err;
30600Sstevel@tonic-gate
30610Sstevel@tonic-gate /*
30620Sstevel@tonic-gate * If we rename a delegated file we should recall the
30630Sstevel@tonic-gate * delegation, since future opens should fail or would
30640Sstevel@tonic-gate * refer to a new file.
30650Sstevel@tonic-gate */
30660Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
30670Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
30685982Sahl goto err1;
30690Sstevel@tonic-gate }
30700Sstevel@tonic-gate
30710Sstevel@tonic-gate /*
30720Sstevel@tonic-gate * Check for renaming over a delegated file. Check rfs4_deleg_policy
30730Sstevel@tonic-gate * first to avoid VOP_LOOKUP if possible.
30740Sstevel@tonic-gate */
30750Sstevel@tonic-gate if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
30767961SNatalie.Li@Sun.COM VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
30775331Samw NULL, NULL, NULL) == 0) {
30780Sstevel@tonic-gate
30790Sstevel@tonic-gate if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
30800Sstevel@tonic-gate VN_RELE(targvp);
30810Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
30825982Sahl goto err1;
30830Sstevel@tonic-gate }
30840Sstevel@tonic-gate VN_RELE(targvp);
30850Sstevel@tonic-gate }
30860Sstevel@tonic-gate
30870Sstevel@tonic-gate if (!nbl_need_check(srcvp)) {
30887961SNatalie.Li@Sun.COM error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
30890Sstevel@tonic-gate } else {
30900Sstevel@tonic-gate nbl_start_crit(srcvp, RW_READER);
30917961SNatalie.Li@Sun.COM if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
30920Sstevel@tonic-gate error = EACCES;
30937961SNatalie.Li@Sun.COM else
30947961SNatalie.Li@Sun.COM error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
30950Sstevel@tonic-gate nbl_end_crit(srcvp);
30960Sstevel@tonic-gate }
30976976Seschrock if (error == 0)
30986976Seschrock vn_renamepath(tvp, srcvp, args->to.name,
30995599Sjwahlig strlen(args->to.name));
31000Sstevel@tonic-gate VN_RELE(srcvp);
31010Sstevel@tonic-gate srcvp = NULL;
31020Sstevel@tonic-gate
31030Sstevel@tonic-gate #ifdef DEBUG
31040Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
31050Sstevel@tonic-gate fava.va_mask = AT_ALL;
31065331Samw favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
31070Sstevel@tonic-gate tava.va_mask = AT_ALL;
31085331Samw tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
31090Sstevel@tonic-gate } else {
31100Sstevel@tonic-gate favap = NULL;
31110Sstevel@tonic-gate tavap = NULL;
31120Sstevel@tonic-gate }
31130Sstevel@tonic-gate #else
31140Sstevel@tonic-gate fava.va_mask = AT_ALL;
31155331Samw favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
31160Sstevel@tonic-gate tava.va_mask = AT_ALL;
31175331Samw tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
31180Sstevel@tonic-gate #endif
31190Sstevel@tonic-gate
31200Sstevel@tonic-gate /*
31210Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
31220Sstevel@tonic-gate */
31235331Samw (void) VOP_FSYNC(fvp, 0, cr, NULL);
31245331Samw (void) VOP_FSYNC(tvp, 0, cr, NULL);
31250Sstevel@tonic-gate
31260Sstevel@tonic-gate if (error)
31275982Sahl goto err;
31280Sstevel@tonic-gate
31290Sstevel@tonic-gate resp->status = NFS3_OK;
31300Sstevel@tonic-gate vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc);
31310Sstevel@tonic-gate vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
31325982Sahl goto out;
31335982Sahl
31345982Sahl err:
31350Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
31360Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
31370Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
31387961SNatalie.Li@Sun.COM } else {
31390Sstevel@tonic-gate resp->status = puterrno3(error);
31407961SNatalie.Li@Sun.COM }
31415982Sahl err1:
31425982Sahl vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
31435982Sahl vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
31447961SNatalie.Li@Sun.COM
31455982Sahl out:
31467961SNatalie.Li@Sun.COM if (name != NULL && name != args->from.name)
31477961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN + 1);
31487961SNatalie.Li@Sun.COM if (toname != NULL && toname != args->to.name)
31497961SNatalie.Li@Sun.COM kmem_free(toname, MAXPATHLEN + 1);
31507961SNatalie.Li@Sun.COM
31515982Sahl DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
31525982Sahl cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
31530Sstevel@tonic-gate if (fvp != NULL)
31540Sstevel@tonic-gate VN_RELE(fvp);
31550Sstevel@tonic-gate if (tvp != NULL)
31560Sstevel@tonic-gate VN_RELE(tvp);
31570Sstevel@tonic-gate }
31580Sstevel@tonic-gate
31591610Sthurlow void *
rfs3_rename_getfh(RENAME3args * args)31600Sstevel@tonic-gate rfs3_rename_getfh(RENAME3args *args)
31610Sstevel@tonic-gate {
31620Sstevel@tonic-gate
31631610Sthurlow return (&args->from.dir);
31640Sstevel@tonic-gate }
31650Sstevel@tonic-gate
31660Sstevel@tonic-gate void
rfs3_link(LINK3args * args,LINK3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)31670Sstevel@tonic-gate rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
31680Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
31690Sstevel@tonic-gate {
31700Sstevel@tonic-gate int error;
31710Sstevel@tonic-gate vnode_t *vp;
31720Sstevel@tonic-gate vnode_t *dvp;
31730Sstevel@tonic-gate struct vattr *vap;
31740Sstevel@tonic-gate struct vattr va;
31750Sstevel@tonic-gate struct vattr *bvap;
31760Sstevel@tonic-gate struct vattr bva;
31770Sstevel@tonic-gate struct vattr *avap;
31780Sstevel@tonic-gate struct vattr ava;
31790Sstevel@tonic-gate nfs_fh3 *fh3;
31800Sstevel@tonic-gate struct exportinfo *to_exi;
31814971Sjarrett bslabel_t *clabel;
31827961SNatalie.Li@Sun.COM struct sockaddr *ca;
31837961SNatalie.Li@Sun.COM char *name = NULL;
31840Sstevel@tonic-gate
31850Sstevel@tonic-gate vap = NULL;
31860Sstevel@tonic-gate bvap = NULL;
31870Sstevel@tonic-gate avap = NULL;
31880Sstevel@tonic-gate dvp = NULL;
31890Sstevel@tonic-gate
31900Sstevel@tonic-gate vp = nfs3_fhtovp(&args->file, exi);
31915982Sahl
31925982Sahl DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
31935982Sahl cred_t *, cr, vnode_t *, vp, LINK3args *, args);
31945982Sahl
31950Sstevel@tonic-gate if (vp == NULL) {
31960Sstevel@tonic-gate error = ESTALE;
31970Sstevel@tonic-gate goto out;
31980Sstevel@tonic-gate }
31990Sstevel@tonic-gate
32000Sstevel@tonic-gate #ifdef DEBUG
32010Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
32020Sstevel@tonic-gate va.va_mask = AT_ALL;
32035331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
32040Sstevel@tonic-gate } else
32050Sstevel@tonic-gate vap = NULL;
32060Sstevel@tonic-gate #else
32070Sstevel@tonic-gate va.va_mask = AT_ALL;
32085331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
32090Sstevel@tonic-gate #endif
32100Sstevel@tonic-gate
32111610Sthurlow fh3 = &args->link.dir;
32121610Sthurlow to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
32130Sstevel@tonic-gate if (to_exi == NULL) {
32140Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
32150Sstevel@tonic-gate goto out1;
32160Sstevel@tonic-gate }
32170Sstevel@tonic-gate exi_rele(to_exi);
32180Sstevel@tonic-gate
32190Sstevel@tonic-gate if (to_exi != exi) {
32200Sstevel@tonic-gate resp->status = NFS3ERR_XDEV;
32210Sstevel@tonic-gate goto out1;
32220Sstevel@tonic-gate }
32230Sstevel@tonic-gate
32244971Sjarrett if (is_system_labeled()) {
32254971Sjarrett clabel = req->rq_label;
32264971Sjarrett
32274971Sjarrett ASSERT(clabel != NULL);
32284971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
32294971Sjarrett "got client label from request(1)", struct svc_req *, req);
32304971Sjarrett
32314971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
32329871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
32339871SJarrett.Lu@Sun.COM exi)) {
32344971Sjarrett resp->status = NFS3ERR_ACCES;
32354971Sjarrett goto out1;
32364971Sjarrett }
32374971Sjarrett }
32384971Sjarrett }
32394971Sjarrett
32401610Sthurlow dvp = nfs3_fhtovp(&args->link.dir, exi);
32410Sstevel@tonic-gate if (dvp == NULL) {
32420Sstevel@tonic-gate error = ESTALE;
32430Sstevel@tonic-gate goto out;
32440Sstevel@tonic-gate }
32450Sstevel@tonic-gate
32460Sstevel@tonic-gate #ifdef DEBUG
32470Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
32480Sstevel@tonic-gate bva.va_mask = AT_ALL;
32495331Samw bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
32500Sstevel@tonic-gate } else
32510Sstevel@tonic-gate bvap = NULL;
32520Sstevel@tonic-gate #else
32530Sstevel@tonic-gate bva.va_mask = AT_ALL;
32545331Samw bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
32550Sstevel@tonic-gate #endif
32560Sstevel@tonic-gate
32570Sstevel@tonic-gate if (dvp->v_type != VDIR) {
32580Sstevel@tonic-gate resp->status = NFS3ERR_NOTDIR;
32590Sstevel@tonic-gate goto out1;
32600Sstevel@tonic-gate }
32610Sstevel@tonic-gate
32620Sstevel@tonic-gate if (args->link.name == nfs3nametoolong) {
32630Sstevel@tonic-gate resp->status = NFS3ERR_NAMETOOLONG;
32640Sstevel@tonic-gate goto out1;
32650Sstevel@tonic-gate }
32660Sstevel@tonic-gate
32670Sstevel@tonic-gate if (args->link.name == NULL || *(args->link.name) == '\0') {
32680Sstevel@tonic-gate resp->status = NFS3ERR_ACCES;
32690Sstevel@tonic-gate goto out1;
32700Sstevel@tonic-gate }
32710Sstevel@tonic-gate
32720Sstevel@tonic-gate if (rdonly(exi, req)) {
32730Sstevel@tonic-gate resp->status = NFS3ERR_ROFS;
32740Sstevel@tonic-gate goto out1;
32750Sstevel@tonic-gate }
32760Sstevel@tonic-gate
32774971Sjarrett if (is_system_labeled()) {
32784971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
32794971Sjarrett "got client label from request(1)", struct svc_req *, req);
32804971Sjarrett
32814971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
32829871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
32839871SJarrett.Lu@Sun.COM exi)) {
32844971Sjarrett resp->status = NFS3ERR_ACCES;
32854971Sjarrett goto out1;
32864971Sjarrett }
32874971Sjarrett }
32884971Sjarrett }
32894971Sjarrett
32907961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
32917961SNatalie.Li@Sun.COM name = nfscmd_convname(ca, exi, args->link.name,
32927961SNatalie.Li@Sun.COM NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
32937961SNatalie.Li@Sun.COM
32947961SNatalie.Li@Sun.COM if (name == NULL) {
32957961SNatalie.Li@Sun.COM resp->status = NFS3ERR_SERVERFAULT;
32967961SNatalie.Li@Sun.COM goto out1;
32977961SNatalie.Li@Sun.COM }
32987961SNatalie.Li@Sun.COM
32997961SNatalie.Li@Sun.COM error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
33000Sstevel@tonic-gate
33010Sstevel@tonic-gate #ifdef DEBUG
33020Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
33030Sstevel@tonic-gate va.va_mask = AT_ALL;
33045331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
33050Sstevel@tonic-gate ava.va_mask = AT_ALL;
33065331Samw avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
33070Sstevel@tonic-gate } else {
33080Sstevel@tonic-gate vap = NULL;
33090Sstevel@tonic-gate avap = NULL;
33100Sstevel@tonic-gate }
33110Sstevel@tonic-gate #else
33120Sstevel@tonic-gate va.va_mask = AT_ALL;
33135331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
33140Sstevel@tonic-gate ava.va_mask = AT_ALL;
33155331Samw avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
33160Sstevel@tonic-gate #endif
33170Sstevel@tonic-gate
33180Sstevel@tonic-gate /*
33190Sstevel@tonic-gate * Force modified data and metadata out to stable storage.
33200Sstevel@tonic-gate */
33215331Samw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
33225331Samw (void) VOP_FSYNC(dvp, 0, cr, NULL);
33230Sstevel@tonic-gate
33240Sstevel@tonic-gate if (error)
33250Sstevel@tonic-gate goto out;
33260Sstevel@tonic-gate
33270Sstevel@tonic-gate VN_RELE(dvp);
33280Sstevel@tonic-gate
33290Sstevel@tonic-gate resp->status = NFS3_OK;
33300Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
33310Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
33325982Sahl
33335982Sahl DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
33345982Sahl cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
33355982Sahl
33365982Sahl VN_RELE(vp);
33375982Sahl
33380Sstevel@tonic-gate return;
33390Sstevel@tonic-gate
33400Sstevel@tonic-gate out:
33410Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
33420Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
33430Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
33440Sstevel@tonic-gate } else
33450Sstevel@tonic-gate resp->status = puterrno3(error);
33460Sstevel@tonic-gate out1:
33477961SNatalie.Li@Sun.COM if (name != NULL && name != args->link.name)
33487961SNatalie.Li@Sun.COM kmem_free(name, MAXPATHLEN + 1);
33497961SNatalie.Li@Sun.COM
33505982Sahl DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
33515982Sahl cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
33525982Sahl
33530Sstevel@tonic-gate if (vp != NULL)
33540Sstevel@tonic-gate VN_RELE(vp);
33550Sstevel@tonic-gate if (dvp != NULL)
33560Sstevel@tonic-gate VN_RELE(dvp);
33570Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
33580Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
33590Sstevel@tonic-gate }
33600Sstevel@tonic-gate
33611610Sthurlow void *
rfs3_link_getfh(LINK3args * args)33620Sstevel@tonic-gate rfs3_link_getfh(LINK3args *args)
33630Sstevel@tonic-gate {
33640Sstevel@tonic-gate
33651610Sthurlow return (&args->file);
33660Sstevel@tonic-gate }
33670Sstevel@tonic-gate
33680Sstevel@tonic-gate /*
33690Sstevel@tonic-gate * This macro defines the size of a response which contains attribute
33700Sstevel@tonic-gate * information and one directory entry (whose length is specified by
33710Sstevel@tonic-gate * the macro parameter). If the incoming request is larger than this,
33720Sstevel@tonic-gate * then we are guaranteed to be able to return at one directory entry
33730Sstevel@tonic-gate * if one exists. Therefore, we do not need to check for
33740Sstevel@tonic-gate * NFS3ERR_TOOSMALL if the requested size is larger then this. If it
33750Sstevel@tonic-gate * is not, then we need to check to make sure that this error does not
33760Sstevel@tonic-gate * need to be returned.
33770Sstevel@tonic-gate *
33780Sstevel@tonic-gate * NFS3_READDIR_MIN_COUNT is comprised of following :
33790Sstevel@tonic-gate *
33800Sstevel@tonic-gate * status - 1 * BYTES_PER_XDR_UNIT
33810Sstevel@tonic-gate * attr. flag - 1 * BYTES_PER_XDR_UNIT
33820Sstevel@tonic-gate * cookie verifier - 2 * BYTES_PER_XDR_UNIT
33830Sstevel@tonic-gate * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
33840Sstevel@tonic-gate * boolean - 1 * BYTES_PER_XDR_UNIT
33850Sstevel@tonic-gate * file id - 2 * BYTES_PER_XDR_UNIT
33865331Samw * directory name length - 1 * BYTES_PER_XDR_UNIT
33870Sstevel@tonic-gate * cookie - 2 * BYTES_PER_XDR_UNIT
33880Sstevel@tonic-gate * end of list - 1 * BYTES_PER_XDR_UNIT
33890Sstevel@tonic-gate * end of file - 1 * BYTES_PER_XDR_UNIT
33900Sstevel@tonic-gate * Name length of directory to the nearest byte
33910Sstevel@tonic-gate */
33920Sstevel@tonic-gate
33930Sstevel@tonic-gate #define NFS3_READDIR_MIN_COUNT(length) \
33940Sstevel@tonic-gate ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
33950Sstevel@tonic-gate BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
33960Sstevel@tonic-gate
33970Sstevel@tonic-gate /* ARGSUSED */
33980Sstevel@tonic-gate void
rfs3_readdir(READDIR3args * args,READDIR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)33990Sstevel@tonic-gate rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
34000Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
34010Sstevel@tonic-gate {
34020Sstevel@tonic-gate int error;
34030Sstevel@tonic-gate vnode_t *vp;
34040Sstevel@tonic-gate struct vattr *vap;
34050Sstevel@tonic-gate struct vattr va;
34060Sstevel@tonic-gate struct iovec iov;
34070Sstevel@tonic-gate struct uio uio;
34080Sstevel@tonic-gate char *data;
34090Sstevel@tonic-gate int iseof;
34100Sstevel@tonic-gate int bufsize;
34110Sstevel@tonic-gate int namlen;
34120Sstevel@tonic-gate uint_t count;
34137961SNatalie.Li@Sun.COM struct sockaddr *ca;
34140Sstevel@tonic-gate
34150Sstevel@tonic-gate vap = NULL;
34160Sstevel@tonic-gate
34170Sstevel@tonic-gate vp = nfs3_fhtovp(&args->dir, exi);
34185982Sahl
34195982Sahl DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req,
34205982Sahl cred_t *, cr, vnode_t *, vp, READDIR3args *, args);
34215982Sahl
34220Sstevel@tonic-gate if (vp == NULL) {
34230Sstevel@tonic-gate error = ESTALE;
34240Sstevel@tonic-gate goto out;
34250Sstevel@tonic-gate }
34260Sstevel@tonic-gate
34274971Sjarrett if (is_system_labeled()) {
34284971Sjarrett bslabel_t *clabel = req->rq_label;
34294971Sjarrett
34304971Sjarrett ASSERT(clabel != NULL);
34314971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
34324971Sjarrett "got client label from request(1)", struct svc_req *, req);
34334971Sjarrett
34344971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
34359871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
34369871SJarrett.Lu@Sun.COM exi)) {
34374971Sjarrett resp->status = NFS3ERR_ACCES;
34384971Sjarrett goto out1;
34394971Sjarrett }
34404971Sjarrett }
34414971Sjarrett }
34424971Sjarrett
34430Sstevel@tonic-gate (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
34440Sstevel@tonic-gate
34450Sstevel@tonic-gate #ifdef DEBUG
34460Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
34470Sstevel@tonic-gate va.va_mask = AT_ALL;
34485331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
34490Sstevel@tonic-gate } else
34500Sstevel@tonic-gate vap = NULL;
34510Sstevel@tonic-gate #else
34520Sstevel@tonic-gate va.va_mask = AT_ALL;
34535331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
34540Sstevel@tonic-gate #endif
34550Sstevel@tonic-gate
34560Sstevel@tonic-gate if (vp->v_type != VDIR) {
34570Sstevel@tonic-gate resp->status = NFS3ERR_NOTDIR;
34580Sstevel@tonic-gate goto out1;
34590Sstevel@tonic-gate }
34600Sstevel@tonic-gate
34615331Samw error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
34620Sstevel@tonic-gate if (error)
34630Sstevel@tonic-gate goto out;
34640Sstevel@tonic-gate
34650Sstevel@tonic-gate /*
34660Sstevel@tonic-gate * Now don't allow arbitrary count to alloc;
34670Sstevel@tonic-gate * allow the maximum not to exceed rfs3_tsize()
34680Sstevel@tonic-gate */
34690Sstevel@tonic-gate if (args->count > rfs3_tsize(req))
34700Sstevel@tonic-gate args->count = rfs3_tsize(req);
34710Sstevel@tonic-gate
34720Sstevel@tonic-gate /*
34730Sstevel@tonic-gate * Make sure that there is room to read at least one entry
34740Sstevel@tonic-gate * if any are available.
34750Sstevel@tonic-gate */
34760Sstevel@tonic-gate if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
34770Sstevel@tonic-gate count = DIRENT64_RECLEN(MAXNAMELEN);
34780Sstevel@tonic-gate else
34790Sstevel@tonic-gate count = args->count;
34800Sstevel@tonic-gate
34810Sstevel@tonic-gate data = kmem_alloc(count, KM_SLEEP);
34820Sstevel@tonic-gate
34830Sstevel@tonic-gate iov.iov_base = data;
34840Sstevel@tonic-gate iov.iov_len = count;
34850Sstevel@tonic-gate uio.uio_iov = &iov;
34860Sstevel@tonic-gate uio.uio_iovcnt = 1;
34870Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
34880Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED;
34890Sstevel@tonic-gate uio.uio_loffset = (offset_t)args->cookie;
34900Sstevel@tonic-gate uio.uio_resid = count;
34910Sstevel@tonic-gate
34925331Samw error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
34930Sstevel@tonic-gate
34940Sstevel@tonic-gate #ifdef DEBUG
34950Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
34960Sstevel@tonic-gate va.va_mask = AT_ALL;
34975331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
34980Sstevel@tonic-gate } else
34990Sstevel@tonic-gate vap = NULL;
35000Sstevel@tonic-gate #else
35010Sstevel@tonic-gate va.va_mask = AT_ALL;
35025331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
35030Sstevel@tonic-gate #endif
35040Sstevel@tonic-gate
35050Sstevel@tonic-gate if (error) {
35060Sstevel@tonic-gate kmem_free(data, count);
35070Sstevel@tonic-gate goto out;
35080Sstevel@tonic-gate }
35090Sstevel@tonic-gate
35100Sstevel@tonic-gate /*
35110Sstevel@tonic-gate * If the count was not large enough to be able to guarantee
35120Sstevel@tonic-gate * to be able to return at least one entry, then need to
35130Sstevel@tonic-gate * check to see if NFS3ERR_TOOSMALL should be returned.
35140Sstevel@tonic-gate */
35150Sstevel@tonic-gate if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
35160Sstevel@tonic-gate /*
35170Sstevel@tonic-gate * bufsize is used to keep track of the size of the response.
35180Sstevel@tonic-gate * It is primed with:
35190Sstevel@tonic-gate * 1 for the status +
35200Sstevel@tonic-gate * 1 for the dir_attributes.attributes boolean +
35210Sstevel@tonic-gate * 2 for the cookie verifier
35220Sstevel@tonic-gate * all times BYTES_PER_XDR_UNIT to convert from XDR units
35230Sstevel@tonic-gate * to bytes. If there are directory attributes to be
35240Sstevel@tonic-gate * returned, then:
35250Sstevel@tonic-gate * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
35260Sstevel@tonic-gate * time BYTES_PER_XDR_UNIT is added to account for them.
35270Sstevel@tonic-gate */
35280Sstevel@tonic-gate bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
35290Sstevel@tonic-gate if (vap != NULL)
35300Sstevel@tonic-gate bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
35310Sstevel@tonic-gate /*
35320Sstevel@tonic-gate * An entry is composed of:
35330Sstevel@tonic-gate * 1 for the true/false list indicator +
35340Sstevel@tonic-gate * 2 for the fileid +
35350Sstevel@tonic-gate * 1 for the length of the name +
35360Sstevel@tonic-gate * 2 for the cookie +
35370Sstevel@tonic-gate * all times BYTES_PER_XDR_UNIT to convert from
35380Sstevel@tonic-gate * XDR units to bytes, plus the length of the name
35390Sstevel@tonic-gate * rounded up to the nearest BYTES_PER_XDR_UNIT.
35400Sstevel@tonic-gate */
35410Sstevel@tonic-gate if (count != uio.uio_resid) {
35420Sstevel@tonic-gate namlen = strlen(((struct dirent64 *)data)->d_name);
35430Sstevel@tonic-gate bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
35445599Sjwahlig roundup(namlen, BYTES_PER_XDR_UNIT);
35450Sstevel@tonic-gate }
35460Sstevel@tonic-gate /*
35470Sstevel@tonic-gate * We need to check to see if the number of bytes left
35480Sstevel@tonic-gate * to go into the buffer will actually fit into the
35490Sstevel@tonic-gate * buffer. This is calculated as the size of this
35500Sstevel@tonic-gate * entry plus:
35510Sstevel@tonic-gate * 1 for the true/false list indicator +
35520Sstevel@tonic-gate * 1 for the eof indicator
35530Sstevel@tonic-gate * times BYTES_PER_XDR_UNIT to convert from from
35540Sstevel@tonic-gate * XDR units to bytes.
35550Sstevel@tonic-gate */
35560Sstevel@tonic-gate bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
35570Sstevel@tonic-gate if (bufsize > args->count) {
35580Sstevel@tonic-gate kmem_free(data, count);
35590Sstevel@tonic-gate resp->status = NFS3ERR_TOOSMALL;
35600Sstevel@tonic-gate goto out1;
35610Sstevel@tonic-gate }
35620Sstevel@tonic-gate }
35630Sstevel@tonic-gate
35647961SNatalie.Li@Sun.COM /*
35657961SNatalie.Li@Sun.COM * Have a valid readir buffer for the native character
35667961SNatalie.Li@Sun.COM * set. Need to check if a conversion is necessary and
35677961SNatalie.Li@Sun.COM * potentially rewrite the whole buffer. Note that if the
35687961SNatalie.Li@Sun.COM * conversion expands names enough, the structure may not
35697961SNatalie.Li@Sun.COM * fit. In this case, we need to drop entries until if fits
35707961SNatalie.Li@Sun.COM * and patch the counts in order that the next readdir will
35717961SNatalie.Li@Sun.COM * get the correct entries.
35727961SNatalie.Li@Sun.COM */
35737961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
35747961SNatalie.Li@Sun.COM data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
35757961SNatalie.Li@Sun.COM
35767961SNatalie.Li@Sun.COM
35770Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
35780Sstevel@tonic-gate
35790Sstevel@tonic-gate #if 0 /* notyet */
35800Sstevel@tonic-gate /*
35810Sstevel@tonic-gate * Don't do this. It causes local disk writes when just
35820Sstevel@tonic-gate * reading the file and the overhead is deemed larger
35830Sstevel@tonic-gate * than the benefit.
35840Sstevel@tonic-gate */
35850Sstevel@tonic-gate /*
35860Sstevel@tonic-gate * Force modified metadata out to stable storage.
35870Sstevel@tonic-gate */
35885331Samw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
35890Sstevel@tonic-gate #endif
35900Sstevel@tonic-gate
35910Sstevel@tonic-gate resp->status = NFS3_OK;
35920Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
35930Sstevel@tonic-gate resp->resok.cookieverf = 0;
35940Sstevel@tonic-gate resp->resok.reply.entries = (entry3 *)data;
35950Sstevel@tonic-gate resp->resok.reply.eof = iseof;
35960Sstevel@tonic-gate resp->resok.size = count - uio.uio_resid;
35970Sstevel@tonic-gate resp->resok.count = args->count;
35980Sstevel@tonic-gate resp->resok.freecount = count;
35995982Sahl
36005982Sahl DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
36015982Sahl cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
36025982Sahl
36035982Sahl VN_RELE(vp);
36045982Sahl
36050Sstevel@tonic-gate return;
36060Sstevel@tonic-gate
36070Sstevel@tonic-gate out:
36080Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
36090Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
36100Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
36110Sstevel@tonic-gate } else
36120Sstevel@tonic-gate resp->status = puterrno3(error);
36130Sstevel@tonic-gate out1:
36145982Sahl DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
36155982Sahl cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
36165982Sahl
36170Sstevel@tonic-gate if (vp != NULL) {
36180Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
36190Sstevel@tonic-gate VN_RELE(vp);
36200Sstevel@tonic-gate }
36210Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
36220Sstevel@tonic-gate }
36230Sstevel@tonic-gate
36241610Sthurlow void *
rfs3_readdir_getfh(READDIR3args * args)36250Sstevel@tonic-gate rfs3_readdir_getfh(READDIR3args *args)
36260Sstevel@tonic-gate {
36270Sstevel@tonic-gate
36281610Sthurlow return (&args->dir);
36290Sstevel@tonic-gate }
36300Sstevel@tonic-gate
36310Sstevel@tonic-gate void
rfs3_readdir_free(READDIR3res * resp)36320Sstevel@tonic-gate rfs3_readdir_free(READDIR3res *resp)
36330Sstevel@tonic-gate {
36340Sstevel@tonic-gate
36350Sstevel@tonic-gate if (resp->status == NFS3_OK)
36360Sstevel@tonic-gate kmem_free(resp->resok.reply.entries, resp->resok.freecount);
36370Sstevel@tonic-gate }
36380Sstevel@tonic-gate
36390Sstevel@tonic-gate #ifdef nextdp
36400Sstevel@tonic-gate #undef nextdp
36410Sstevel@tonic-gate #endif
36420Sstevel@tonic-gate #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
36430Sstevel@tonic-gate
36440Sstevel@tonic-gate /*
36450Sstevel@tonic-gate * This macro computes the size of a response which contains
36460Sstevel@tonic-gate * one directory entry including the attributes as well as file handle.
36470Sstevel@tonic-gate * If the incoming request is larger than this, then we are guaranteed to be
36480Sstevel@tonic-gate * able to return at least one more directory entry if one exists.
36490Sstevel@tonic-gate *
36500Sstevel@tonic-gate * NFS3_READDIRPLUS_ENTRY is made up of the following:
36510Sstevel@tonic-gate *
36520Sstevel@tonic-gate * boolean - 1 * BYTES_PER_XDR_UNIT
36530Sstevel@tonic-gate * file id - 2 * BYTES_PER_XDR_UNIT
36540Sstevel@tonic-gate * directory name length - 1 * BYTES_PER_XDR_UNIT
36550Sstevel@tonic-gate * cookie - 2 * BYTES_PER_XDR_UNIT
36560Sstevel@tonic-gate * attribute flag - 1 * BYTES_PER_XDR_UNIT
36570Sstevel@tonic-gate * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
36580Sstevel@tonic-gate * status byte for file handle - 1 * BYTES_PER_XDR_UNIT
36590Sstevel@tonic-gate * length of a file handle - 1 * BYTES_PER_XDR_UNIT
36605331Samw * Maximum length of a file handle (NFS3_MAXFHSIZE)
36610Sstevel@tonic-gate * name length of the entry to the nearest bytes
36620Sstevel@tonic-gate */
36630Sstevel@tonic-gate #define NFS3_READDIRPLUS_ENTRY(namelen) \
36640Sstevel@tonic-gate ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
36650Sstevel@tonic-gate BYTES_PER_XDR_UNIT + \
36661610Sthurlow NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
36670Sstevel@tonic-gate
36680Sstevel@tonic-gate static int rfs3_readdir_unit = MAXBSIZE;
36690Sstevel@tonic-gate
36700Sstevel@tonic-gate /* ARGSUSED */
36710Sstevel@tonic-gate void
rfs3_readdirplus(READDIRPLUS3args * args,READDIRPLUS3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)36720Sstevel@tonic-gate rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
36730Sstevel@tonic-gate struct exportinfo *exi, struct svc_req *req, cred_t *cr)
36740Sstevel@tonic-gate {
36750Sstevel@tonic-gate int error;
36760Sstevel@tonic-gate vnode_t *vp;
36770Sstevel@tonic-gate struct vattr *vap;
36780Sstevel@tonic-gate struct vattr va;
36790Sstevel@tonic-gate struct iovec iov;
36800Sstevel@tonic-gate struct uio uio;
36810Sstevel@tonic-gate char *data;
36820Sstevel@tonic-gate int iseof;
36830Sstevel@tonic-gate struct dirent64 *dp;
36840Sstevel@tonic-gate vnode_t *nvp;
36850Sstevel@tonic-gate struct vattr *nvap;
36860Sstevel@tonic-gate struct vattr nva;
36870Sstevel@tonic-gate entryplus3_info *infop = NULL;
36880Sstevel@tonic-gate int size = 0;
36890Sstevel@tonic-gate int nents = 0;
36900Sstevel@tonic-gate int bufsize = 0;
36910Sstevel@tonic-gate int entrysize = 0;
36920Sstevel@tonic-gate int tofit = 0;
36930Sstevel@tonic-gate int rd_unit = rfs3_readdir_unit;
36940Sstevel@tonic-gate int prev_len;
36950Sstevel@tonic-gate int space_left;
36960Sstevel@tonic-gate int i;
36970Sstevel@tonic-gate uint_t *namlen = NULL;
36987961SNatalie.Li@Sun.COM char *ndata = NULL;
36997961SNatalie.Li@Sun.COM struct sockaddr *ca;
37007961SNatalie.Li@Sun.COM size_t ret;
37010Sstevel@tonic-gate
37020Sstevel@tonic-gate vap = NULL;
37030Sstevel@tonic-gate
37040Sstevel@tonic-gate vp = nfs3_fhtovp(&args->dir, exi);
37055982Sahl
37065982Sahl DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req,
37075982Sahl cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args);
37085982Sahl
37090Sstevel@tonic-gate if (vp == NULL) {
37100Sstevel@tonic-gate error = ESTALE;
37110Sstevel@tonic-gate goto out;
37120Sstevel@tonic-gate }
37130Sstevel@tonic-gate
37144971Sjarrett if (is_system_labeled()) {
37154971Sjarrett bslabel_t *clabel = req->rq_label;
37164971Sjarrett
37174971Sjarrett ASSERT(clabel != NULL);
37184971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
37194971Sjarrett char *, "got client label from request(1)",
37204971Sjarrett struct svc_req *, req);
37214971Sjarrett
37224971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
37239871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
37249871SJarrett.Lu@Sun.COM exi)) {
37254971Sjarrett resp->status = NFS3ERR_ACCES;
37264971Sjarrett goto out1;
37274971Sjarrett }
37284971Sjarrett }
37294971Sjarrett }
37304971Sjarrett
37310Sstevel@tonic-gate (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
37320Sstevel@tonic-gate
37330Sstevel@tonic-gate #ifdef DEBUG
37340Sstevel@tonic-gate if (rfs3_do_pre_op_attr) {
37350Sstevel@tonic-gate va.va_mask = AT_ALL;
37365331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
37370Sstevel@tonic-gate } else
37380Sstevel@tonic-gate vap = NULL;
37390Sstevel@tonic-gate #else
37400Sstevel@tonic-gate va.va_mask = AT_ALL;
37415331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
37420Sstevel@tonic-gate #endif
37430Sstevel@tonic-gate
37440Sstevel@tonic-gate if (vp->v_type != VDIR) {
37450Sstevel@tonic-gate error = ENOTDIR;
37460Sstevel@tonic-gate goto out;
37470Sstevel@tonic-gate }
37480Sstevel@tonic-gate
37495331Samw error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
37500Sstevel@tonic-gate if (error)
37510Sstevel@tonic-gate goto out;
37520Sstevel@tonic-gate
37530Sstevel@tonic-gate /*
37540Sstevel@tonic-gate * Don't allow arbitrary counts for allocation
37550Sstevel@tonic-gate */
37560Sstevel@tonic-gate if (args->maxcount > rfs3_tsize(req))
37570Sstevel@tonic-gate args->maxcount = rfs3_tsize(req);
37580Sstevel@tonic-gate
37590Sstevel@tonic-gate /*
37600Sstevel@tonic-gate * Make sure that there is room to read at least one entry
37610Sstevel@tonic-gate * if any are available
37620Sstevel@tonic-gate */
37630Sstevel@tonic-gate args->dircount = MIN(args->dircount, args->maxcount);
37640Sstevel@tonic-gate
37650Sstevel@tonic-gate if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
37660Sstevel@tonic-gate args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
37670Sstevel@tonic-gate
37680Sstevel@tonic-gate /*
37690Sstevel@tonic-gate * This allocation relies on a minimum directory entry
37700Sstevel@tonic-gate * being roughly 24 bytes. Therefore, the namlen array
37710Sstevel@tonic-gate * will have enough space based on the maximum number of
37720Sstevel@tonic-gate * entries to read.
37730Sstevel@tonic-gate */
37740Sstevel@tonic-gate namlen = kmem_alloc(args->dircount, KM_SLEEP);
37750Sstevel@tonic-gate
37760Sstevel@tonic-gate space_left = args->dircount;
37770Sstevel@tonic-gate data = kmem_alloc(args->dircount, KM_SLEEP);
37780Sstevel@tonic-gate dp = (struct dirent64 *)data;
37790Sstevel@tonic-gate uio.uio_iov = &iov;
37800Sstevel@tonic-gate uio.uio_iovcnt = 1;
37810Sstevel@tonic-gate uio.uio_segflg = UIO_SYSSPACE;
37820Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_CACHED;
37830Sstevel@tonic-gate uio.uio_loffset = (offset_t)args->cookie;
37840Sstevel@tonic-gate
37850Sstevel@tonic-gate /*
37860Sstevel@tonic-gate * bufsize is used to keep track of the size of the response as we
37870Sstevel@tonic-gate * get post op attributes and filehandles for each entry. This is
37880Sstevel@tonic-gate * an optimization as the server may have read more entries than will
37890Sstevel@tonic-gate * fit in the buffer specified by maxcount. We stop calculating
37900Sstevel@tonic-gate * post op attributes and filehandles once we have exceeded maxcount.
37910Sstevel@tonic-gate * This will minimize the effect of truncation.
37920Sstevel@tonic-gate *
37930Sstevel@tonic-gate * It is primed with:
37940Sstevel@tonic-gate * 1 for the status +
37950Sstevel@tonic-gate * 1 for the dir_attributes.attributes boolean +
37960Sstevel@tonic-gate * 2 for the cookie verifier
37970Sstevel@tonic-gate * all times BYTES_PER_XDR_UNIT to convert from XDR units
37980Sstevel@tonic-gate * to bytes. If there are directory attributes to be
37990Sstevel@tonic-gate * returned, then:
38000Sstevel@tonic-gate * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
38010Sstevel@tonic-gate * time BYTES_PER_XDR_UNIT is added to account for them.
38020Sstevel@tonic-gate */
38030Sstevel@tonic-gate bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
38040Sstevel@tonic-gate if (vap != NULL)
38050Sstevel@tonic-gate bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
38060Sstevel@tonic-gate
38070Sstevel@tonic-gate getmoredents:
38080Sstevel@tonic-gate /*
38090Sstevel@tonic-gate * Here we make a check so that our read unit is not larger than
38100Sstevel@tonic-gate * the space left in the buffer.
38110Sstevel@tonic-gate */
38120Sstevel@tonic-gate rd_unit = MIN(rd_unit, space_left);
38130Sstevel@tonic-gate iov.iov_base = (char *)dp;
38140Sstevel@tonic-gate iov.iov_len = rd_unit;
38150Sstevel@tonic-gate uio.uio_resid = rd_unit;
38160Sstevel@tonic-gate prev_len = rd_unit;
38170Sstevel@tonic-gate
38185331Samw error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
38190Sstevel@tonic-gate
38200Sstevel@tonic-gate if (error) {
38210Sstevel@tonic-gate kmem_free(data, args->dircount);
38220Sstevel@tonic-gate goto out;
38230Sstevel@tonic-gate }
38240Sstevel@tonic-gate
38250Sstevel@tonic-gate if (uio.uio_resid == prev_len && !iseof) {
38260Sstevel@tonic-gate if (nents == 0) {
38270Sstevel@tonic-gate kmem_free(data, args->dircount);
38280Sstevel@tonic-gate resp->status = NFS3ERR_TOOSMALL;
38290Sstevel@tonic-gate goto out1;
38300Sstevel@tonic-gate }
38310Sstevel@tonic-gate
38320Sstevel@tonic-gate /*
38330Sstevel@tonic-gate * We could not get any more entries, so get the attributes
38340Sstevel@tonic-gate * and filehandle for the entries already obtained.
38350Sstevel@tonic-gate */
38360Sstevel@tonic-gate goto good;
38370Sstevel@tonic-gate }
38380Sstevel@tonic-gate
38390Sstevel@tonic-gate /*
38400Sstevel@tonic-gate * We estimate the size of the response by assuming the
38410Sstevel@tonic-gate * entry exists and attributes and filehandle are also valid
38420Sstevel@tonic-gate */
38430Sstevel@tonic-gate for (size = prev_len - uio.uio_resid;
38445599Sjwahlig size > 0;
38455599Sjwahlig size -= dp->d_reclen, dp = nextdp(dp)) {
38460Sstevel@tonic-gate
38470Sstevel@tonic-gate if (dp->d_ino == 0) {
38480Sstevel@tonic-gate nents++;
38490Sstevel@tonic-gate continue;
38500Sstevel@tonic-gate }
38510Sstevel@tonic-gate
38520Sstevel@tonic-gate namlen[nents] = strlen(dp->d_name);
38530Sstevel@tonic-gate entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
38540Sstevel@tonic-gate
38550Sstevel@tonic-gate /*
38560Sstevel@tonic-gate * We need to check to see if the number of bytes left
38570Sstevel@tonic-gate * to go into the buffer will actually fit into the
38580Sstevel@tonic-gate * buffer. This is calculated as the size of this
38590Sstevel@tonic-gate * entry plus:
38600Sstevel@tonic-gate * 1 for the true/false list indicator +
38610Sstevel@tonic-gate * 1 for the eof indicator
38620Sstevel@tonic-gate * times BYTES_PER_XDR_UNIT to convert from XDR units
38630Sstevel@tonic-gate * to bytes.
38640Sstevel@tonic-gate *
38650Sstevel@tonic-gate * Also check the dircount limit against the first entry read
38660Sstevel@tonic-gate *
38670Sstevel@tonic-gate */
38680Sstevel@tonic-gate tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
38690Sstevel@tonic-gate if (bufsize + tofit > args->maxcount) {
38700Sstevel@tonic-gate /*
38710Sstevel@tonic-gate * We make a check here to see if this was the
38720Sstevel@tonic-gate * first entry being measured. If so, then maxcount
38730Sstevel@tonic-gate * was too small to begin with and so we need to
38740Sstevel@tonic-gate * return with NFS3ERR_TOOSMALL.
38750Sstevel@tonic-gate */
38760Sstevel@tonic-gate if (nents == 0) {
38770Sstevel@tonic-gate kmem_free(data, args->dircount);
38780Sstevel@tonic-gate resp->status = NFS3ERR_TOOSMALL;
38790Sstevel@tonic-gate goto out1;
38800Sstevel@tonic-gate }
38810Sstevel@tonic-gate iseof = FALSE;
38820Sstevel@tonic-gate goto good;
38830Sstevel@tonic-gate }
38840Sstevel@tonic-gate bufsize += entrysize;
38850Sstevel@tonic-gate nents++;
38860Sstevel@tonic-gate }
38870Sstevel@tonic-gate
38880Sstevel@tonic-gate /*
38890Sstevel@tonic-gate * If there is enough room to fit at least 1 more entry including
38900Sstevel@tonic-gate * post op attributes and filehandle in the buffer AND that we haven't
38910Sstevel@tonic-gate * exceeded dircount then go back and get some more.
38920Sstevel@tonic-gate */
38930Sstevel@tonic-gate if (!iseof &&
38940Sstevel@tonic-gate (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
38950Sstevel@tonic-gate space_left -= (prev_len - uio.uio_resid);
38960Sstevel@tonic-gate if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
38970Sstevel@tonic-gate goto getmoredents;
38980Sstevel@tonic-gate
38990Sstevel@tonic-gate /* else, fall through */
39000Sstevel@tonic-gate }
39010Sstevel@tonic-gate
39020Sstevel@tonic-gate good:
39030Sstevel@tonic-gate
39040Sstevel@tonic-gate #ifdef DEBUG
39050Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
39060Sstevel@tonic-gate va.va_mask = AT_ALL;
39075331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
39080Sstevel@tonic-gate } else
39090Sstevel@tonic-gate vap = NULL;
39100Sstevel@tonic-gate #else
39110Sstevel@tonic-gate va.va_mask = AT_ALL;
39125331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
39130Sstevel@tonic-gate #endif
39140Sstevel@tonic-gate
39150Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
39160Sstevel@tonic-gate
39170Sstevel@tonic-gate infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
39180Sstevel@tonic-gate resp->resok.infop = infop;
39190Sstevel@tonic-gate
39200Sstevel@tonic-gate dp = (struct dirent64 *)data;
39210Sstevel@tonic-gate for (i = 0; i < nents; i++) {
39220Sstevel@tonic-gate
39230Sstevel@tonic-gate if (dp->d_ino == 0) {
39240Sstevel@tonic-gate infop[i].attr.attributes = FALSE;
39250Sstevel@tonic-gate infop[i].fh.handle_follows = FALSE;
39260Sstevel@tonic-gate dp = nextdp(dp);
39270Sstevel@tonic-gate continue;
39280Sstevel@tonic-gate }
39290Sstevel@tonic-gate
39300Sstevel@tonic-gate infop[i].namelen = namlen[i];
39310Sstevel@tonic-gate
39325331Samw error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
39335599Sjwahlig NULL, NULL, NULL);
39340Sstevel@tonic-gate if (error) {
39350Sstevel@tonic-gate infop[i].attr.attributes = FALSE;
39360Sstevel@tonic-gate infop[i].fh.handle_follows = FALSE;
39370Sstevel@tonic-gate dp = nextdp(dp);
39380Sstevel@tonic-gate continue;
39390Sstevel@tonic-gate }
39400Sstevel@tonic-gate
39410Sstevel@tonic-gate #ifdef DEBUG
39420Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
39430Sstevel@tonic-gate nva.va_mask = AT_ALL;
39440Sstevel@tonic-gate nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ?
39455599Sjwahlig NULL : &nva;
39460Sstevel@tonic-gate } else
39470Sstevel@tonic-gate nvap = NULL;
39480Sstevel@tonic-gate #else
39490Sstevel@tonic-gate nva.va_mask = AT_ALL;
39500Sstevel@tonic-gate nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
39510Sstevel@tonic-gate #endif
395211291SRobert.Thurlow@Sun.COM /* Lie about the object type for a referral */
395311291SRobert.Thurlow@Sun.COM if (vn_is_nfs_reparse(nvp, cr))
395411291SRobert.Thurlow@Sun.COM nvap->va_type = VLNK;
395511291SRobert.Thurlow@Sun.COM
39560Sstevel@tonic-gate vattr_to_post_op_attr(nvap, &infop[i].attr);
39570Sstevel@tonic-gate
39580Sstevel@tonic-gate #ifdef DEBUG
39590Sstevel@tonic-gate if (!rfs3_do_post_op_fh3)
39600Sstevel@tonic-gate infop[i].fh.handle_follows = FALSE;
39610Sstevel@tonic-gate else {
39620Sstevel@tonic-gate #endif
39630Sstevel@tonic-gate error = makefh3(&infop[i].fh.handle, nvp, exi);
39640Sstevel@tonic-gate if (!error)
39650Sstevel@tonic-gate infop[i].fh.handle_follows = TRUE;
39660Sstevel@tonic-gate else
39670Sstevel@tonic-gate infop[i].fh.handle_follows = FALSE;
39680Sstevel@tonic-gate #ifdef DEBUG
39690Sstevel@tonic-gate }
39700Sstevel@tonic-gate #endif
39710Sstevel@tonic-gate
39720Sstevel@tonic-gate VN_RELE(nvp);
39730Sstevel@tonic-gate dp = nextdp(dp);
39740Sstevel@tonic-gate }
39750Sstevel@tonic-gate
39767961SNatalie.Li@Sun.COM ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
39777961SNatalie.Li@Sun.COM ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
39787961SNatalie.Li@Sun.COM if (ndata == NULL)
39797961SNatalie.Li@Sun.COM ndata = data;
39807961SNatalie.Li@Sun.COM
39817961SNatalie.Li@Sun.COM if (ret > 0) {
39827961SNatalie.Li@Sun.COM /*
39837961SNatalie.Li@Sun.COM * We had to drop one or more entries in order to fit
39847961SNatalie.Li@Sun.COM * during the character conversion. We need to patch
39857961SNatalie.Li@Sun.COM * up the size and eof info.
39867961SNatalie.Li@Sun.COM */
39877961SNatalie.Li@Sun.COM if (iseof)
39887961SNatalie.Li@Sun.COM iseof = FALSE;
39897961SNatalie.Li@Sun.COM
39907961SNatalie.Li@Sun.COM ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
39917961SNatalie.Li@Sun.COM nents, ret);
39927961SNatalie.Li@Sun.COM }
39937961SNatalie.Li@Sun.COM
39947961SNatalie.Li@Sun.COM
39950Sstevel@tonic-gate #if 0 /* notyet */
39960Sstevel@tonic-gate /*
39970Sstevel@tonic-gate * Don't do this. It causes local disk writes when just
39980Sstevel@tonic-gate * reading the file and the overhead is deemed larger
39990Sstevel@tonic-gate * than the benefit.
40000Sstevel@tonic-gate */
40010Sstevel@tonic-gate /*
40020Sstevel@tonic-gate * Force modified metadata out to stable storage.
40030Sstevel@tonic-gate */
40045331Samw (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
40050Sstevel@tonic-gate #endif
40060Sstevel@tonic-gate
40070Sstevel@tonic-gate kmem_free(namlen, args->dircount);
40080Sstevel@tonic-gate
40090Sstevel@tonic-gate resp->status = NFS3_OK;
40100Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
40110Sstevel@tonic-gate resp->resok.cookieverf = 0;
40127961SNatalie.Li@Sun.COM resp->resok.reply.entries = (entryplus3 *)ndata;
40130Sstevel@tonic-gate resp->resok.reply.eof = iseof;
40140Sstevel@tonic-gate resp->resok.size = nents;
40157961SNatalie.Li@Sun.COM resp->resok.count = args->dircount - ret;
40160Sstevel@tonic-gate resp->resok.maxcount = args->maxcount;
40175982Sahl
40185982Sahl DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
40195982Sahl cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
40207961SNatalie.Li@Sun.COM if (ndata != data)
40217961SNatalie.Li@Sun.COM kmem_free(data, args->dircount);
40227961SNatalie.Li@Sun.COM
40235982Sahl
40245982Sahl VN_RELE(vp);
40255982Sahl
40260Sstevel@tonic-gate return;
40270Sstevel@tonic-gate
40280Sstevel@tonic-gate out:
40290Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
40300Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
40310Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
40327961SNatalie.Li@Sun.COM } else {
40330Sstevel@tonic-gate resp->status = puterrno3(error);
40347961SNatalie.Li@Sun.COM }
40350Sstevel@tonic-gate out1:
40365982Sahl DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
40375982Sahl cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
40385982Sahl
40390Sstevel@tonic-gate if (vp != NULL) {
40400Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
40410Sstevel@tonic-gate VN_RELE(vp);
40420Sstevel@tonic-gate }
40430Sstevel@tonic-gate
40440Sstevel@tonic-gate if (namlen != NULL)
40450Sstevel@tonic-gate kmem_free(namlen, args->dircount);
40460Sstevel@tonic-gate
40470Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
40480Sstevel@tonic-gate }
40490Sstevel@tonic-gate
40501610Sthurlow void *
rfs3_readdirplus_getfh(READDIRPLUS3args * args)40510Sstevel@tonic-gate rfs3_readdirplus_getfh(READDIRPLUS3args *args)
40520Sstevel@tonic-gate {
40530Sstevel@tonic-gate
40541610Sthurlow return (&args->dir);
40550Sstevel@tonic-gate }
40560Sstevel@tonic-gate
40570Sstevel@tonic-gate void
rfs3_readdirplus_free(READDIRPLUS3res * resp)40580Sstevel@tonic-gate rfs3_readdirplus_free(READDIRPLUS3res *resp)
40590Sstevel@tonic-gate {
40600Sstevel@tonic-gate
40610Sstevel@tonic-gate if (resp->status == NFS3_OK) {
40620Sstevel@tonic-gate kmem_free(resp->resok.reply.entries, resp->resok.count);
40630Sstevel@tonic-gate kmem_free(resp->resok.infop,
40645599Sjwahlig resp->resok.size * sizeof (struct entryplus3_info));
40650Sstevel@tonic-gate }
40660Sstevel@tonic-gate }
40670Sstevel@tonic-gate
40680Sstevel@tonic-gate /* ARGSUSED */
40690Sstevel@tonic-gate void
rfs3_fsstat(FSSTAT3args * args,FSSTAT3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)40700Sstevel@tonic-gate rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
40710Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
40720Sstevel@tonic-gate {
40730Sstevel@tonic-gate int error;
40740Sstevel@tonic-gate vnode_t *vp;
40750Sstevel@tonic-gate struct vattr *vap;
40760Sstevel@tonic-gate struct vattr va;
40770Sstevel@tonic-gate struct statvfs64 sb;
40780Sstevel@tonic-gate
40790Sstevel@tonic-gate vap = NULL;
40800Sstevel@tonic-gate
40810Sstevel@tonic-gate vp = nfs3_fhtovp(&args->fsroot, exi);
40825982Sahl
40835982Sahl DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req,
40845982Sahl cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args);
40855982Sahl
40860Sstevel@tonic-gate if (vp == NULL) {
40870Sstevel@tonic-gate error = ESTALE;
40880Sstevel@tonic-gate goto out;
40890Sstevel@tonic-gate }
40900Sstevel@tonic-gate
40914971Sjarrett if (is_system_labeled()) {
40924971Sjarrett bslabel_t *clabel = req->rq_label;
40934971Sjarrett
40944971Sjarrett ASSERT(clabel != NULL);
40954971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
40964971Sjarrett "got client label from request(1)", struct svc_req *, req);
40974971Sjarrett
40984971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
40999871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
41009871SJarrett.Lu@Sun.COM exi)) {
41014971Sjarrett resp->status = NFS3ERR_ACCES;
41024971Sjarrett goto out1;
41034971Sjarrett }
41044971Sjarrett }
41054971Sjarrett }
41064971Sjarrett
41070Sstevel@tonic-gate error = VFS_STATVFS(vp->v_vfsp, &sb);
41080Sstevel@tonic-gate
41090Sstevel@tonic-gate #ifdef DEBUG
41100Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
41110Sstevel@tonic-gate va.va_mask = AT_ALL;
41125331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
41130Sstevel@tonic-gate } else
41140Sstevel@tonic-gate vap = NULL;
41150Sstevel@tonic-gate #else
41160Sstevel@tonic-gate va.va_mask = AT_ALL;
41175331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
41180Sstevel@tonic-gate #endif
41190Sstevel@tonic-gate
41200Sstevel@tonic-gate if (error)
41210Sstevel@tonic-gate goto out;
41220Sstevel@tonic-gate
41230Sstevel@tonic-gate resp->status = NFS3_OK;
41240Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
41250Sstevel@tonic-gate if (sb.f_blocks != (fsblkcnt64_t)-1)
41260Sstevel@tonic-gate resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
41270Sstevel@tonic-gate else
41280Sstevel@tonic-gate resp->resok.tbytes = (size3)sb.f_blocks;
41290Sstevel@tonic-gate if (sb.f_bfree != (fsblkcnt64_t)-1)
41300Sstevel@tonic-gate resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
41310Sstevel@tonic-gate else
41320Sstevel@tonic-gate resp->resok.fbytes = (size3)sb.f_bfree;
41330Sstevel@tonic-gate if (sb.f_bavail != (fsblkcnt64_t)-1)
41340Sstevel@tonic-gate resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
41350Sstevel@tonic-gate else
41360Sstevel@tonic-gate resp->resok.abytes = (size3)sb.f_bavail;
41370Sstevel@tonic-gate resp->resok.tfiles = (size3)sb.f_files;
41380Sstevel@tonic-gate resp->resok.ffiles = (size3)sb.f_ffree;
41390Sstevel@tonic-gate resp->resok.afiles = (size3)sb.f_favail;
41400Sstevel@tonic-gate resp->resok.invarsec = 0;
41415982Sahl
41425982Sahl DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
41435982Sahl cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
41445982Sahl VN_RELE(vp);
41455982Sahl
41460Sstevel@tonic-gate return;
41470Sstevel@tonic-gate
41480Sstevel@tonic-gate out:
41490Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
41500Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
41510Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
41520Sstevel@tonic-gate } else
41530Sstevel@tonic-gate resp->status = puterrno3(error);
41544971Sjarrett out1:
41555982Sahl DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
41565982Sahl cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
41575982Sahl
41584971Sjarrett if (vp != NULL)
41594971Sjarrett VN_RELE(vp);
41600Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
41610Sstevel@tonic-gate }
41620Sstevel@tonic-gate
41631610Sthurlow void *
rfs3_fsstat_getfh(FSSTAT3args * args)41640Sstevel@tonic-gate rfs3_fsstat_getfh(FSSTAT3args *args)
41650Sstevel@tonic-gate {
41660Sstevel@tonic-gate
41671610Sthurlow return (&args->fsroot);
41680Sstevel@tonic-gate }
41690Sstevel@tonic-gate
41700Sstevel@tonic-gate void
rfs3_fsinfo(FSINFO3args * args,FSINFO3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)41710Sstevel@tonic-gate rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
41720Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
41730Sstevel@tonic-gate {
41740Sstevel@tonic-gate vnode_t *vp;
41750Sstevel@tonic-gate struct vattr *vap;
41760Sstevel@tonic-gate struct vattr va;
41770Sstevel@tonic-gate uint32_t xfer_size;
41780Sstevel@tonic-gate ulong_t l = 0;
41790Sstevel@tonic-gate int error;
41800Sstevel@tonic-gate
41810Sstevel@tonic-gate vp = nfs3_fhtovp(&args->fsroot, exi);
41825982Sahl
41835982Sahl DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req,
41845982Sahl cred_t *, cr, vnode_t *, vp, FSINFO3args *, args);
41855982Sahl
41860Sstevel@tonic-gate if (vp == NULL) {
41870Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
41880Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
41890Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
41900Sstevel@tonic-gate } else
41910Sstevel@tonic-gate resp->status = NFS3ERR_STALE;
41920Sstevel@tonic-gate vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
41935982Sahl goto out;
41940Sstevel@tonic-gate }
41950Sstevel@tonic-gate
41964971Sjarrett if (is_system_labeled()) {
41974971Sjarrett bslabel_t *clabel = req->rq_label;
41984971Sjarrett
41994971Sjarrett ASSERT(clabel != NULL);
42004971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
42014971Sjarrett "got client label from request(1)", struct svc_req *, req);
42024971Sjarrett
42034971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
42049871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
42059871SJarrett.Lu@Sun.COM exi)) {
42064971Sjarrett resp->status = NFS3ERR_STALE;
42074971Sjarrett vattr_to_post_op_attr(NULL,
42084971Sjarrett &resp->resfail.obj_attributes);
42095982Sahl goto out;
42104971Sjarrett }
42114971Sjarrett }
42124971Sjarrett }
42134971Sjarrett
42140Sstevel@tonic-gate #ifdef DEBUG
42150Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
42160Sstevel@tonic-gate va.va_mask = AT_ALL;
42175331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
42180Sstevel@tonic-gate } else
42190Sstevel@tonic-gate vap = NULL;
42200Sstevel@tonic-gate #else
42210Sstevel@tonic-gate va.va_mask = AT_ALL;
42225331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
42230Sstevel@tonic-gate #endif
42240Sstevel@tonic-gate
42250Sstevel@tonic-gate resp->status = NFS3_OK;
42260Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
42270Sstevel@tonic-gate xfer_size = rfs3_tsize(req);
42280Sstevel@tonic-gate resp->resok.rtmax = xfer_size;
42290Sstevel@tonic-gate resp->resok.rtpref = xfer_size;
42300Sstevel@tonic-gate resp->resok.rtmult = DEV_BSIZE;
42310Sstevel@tonic-gate resp->resok.wtmax = xfer_size;
42320Sstevel@tonic-gate resp->resok.wtpref = xfer_size;
42330Sstevel@tonic-gate resp->resok.wtmult = DEV_BSIZE;
42340Sstevel@tonic-gate resp->resok.dtpref = MAXBSIZE;
42350Sstevel@tonic-gate
42360Sstevel@tonic-gate /*
42370Sstevel@tonic-gate * Large file spec: want maxfilesize based on limit of
42380Sstevel@tonic-gate * underlying filesystem. We can guess 2^31-1 if need be.
42390Sstevel@tonic-gate */
42405331Samw error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
424110035SPiyush.Shivam@Sun.COM if (error) {
424210035SPiyush.Shivam@Sun.COM resp->status = puterrno3(error);
424310035SPiyush.Shivam@Sun.COM goto out;
424410035SPiyush.Shivam@Sun.COM }
424510035SPiyush.Shivam@Sun.COM
424610035SPiyush.Shivam@Sun.COM /*
424710035SPiyush.Shivam@Sun.COM * If the underlying file system does not support _PC_FILESIZEBITS,
424810035SPiyush.Shivam@Sun.COM * return a reasonable default. Note that error code on VOP_PATHCONF
424910035SPiyush.Shivam@Sun.COM * will be 0, even if the underlying file system does not support
425010035SPiyush.Shivam@Sun.COM * _PC_FILESIZEBITS.
425110035SPiyush.Shivam@Sun.COM */
425210035SPiyush.Shivam@Sun.COM if (l == (ulong_t)-1) {
42530Sstevel@tonic-gate resp->resok.maxfilesize = MAXOFF32_T;
425410035SPiyush.Shivam@Sun.COM } else {
425510035SPiyush.Shivam@Sun.COM if (l >= (sizeof (uint64_t) * 8))
425610035SPiyush.Shivam@Sun.COM resp->resok.maxfilesize = INT64_MAX;
425710035SPiyush.Shivam@Sun.COM else
425810035SPiyush.Shivam@Sun.COM resp->resok.maxfilesize = (1LL << (l-1)) - 1;
425910035SPiyush.Shivam@Sun.COM }
42600Sstevel@tonic-gate
42610Sstevel@tonic-gate resp->resok.time_delta.seconds = 0;
42620Sstevel@tonic-gate resp->resok.time_delta.nseconds = 1000;
42630Sstevel@tonic-gate resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
42640Sstevel@tonic-gate FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
42655982Sahl
42665982Sahl DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
42675982Sahl cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp);
42685982Sahl
42695982Sahl VN_RELE(vp);
42705982Sahl
42715982Sahl return;
42725982Sahl
42735982Sahl out:
42745982Sahl DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
42755982Sahl cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp);
42765982Sahl if (vp != NULL)
42775982Sahl VN_RELE(vp);
42780Sstevel@tonic-gate }
42790Sstevel@tonic-gate
42801610Sthurlow void *
rfs3_fsinfo_getfh(FSINFO3args * args)42810Sstevel@tonic-gate rfs3_fsinfo_getfh(FSINFO3args *args)
42820Sstevel@tonic-gate {
42830Sstevel@tonic-gate
42841610Sthurlow return (&args->fsroot);
42850Sstevel@tonic-gate }
42860Sstevel@tonic-gate
42870Sstevel@tonic-gate /* ARGSUSED */
42880Sstevel@tonic-gate void
rfs3_pathconf(PATHCONF3args * args,PATHCONF3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)42890Sstevel@tonic-gate rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
42900Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
42910Sstevel@tonic-gate {
42920Sstevel@tonic-gate int error;
42930Sstevel@tonic-gate vnode_t *vp;
42940Sstevel@tonic-gate struct vattr *vap;
42950Sstevel@tonic-gate struct vattr va;
42960Sstevel@tonic-gate ulong_t val;
42970Sstevel@tonic-gate
42980Sstevel@tonic-gate vap = NULL;
42990Sstevel@tonic-gate
43000Sstevel@tonic-gate vp = nfs3_fhtovp(&args->object, exi);
43015982Sahl
43025982Sahl DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req,
43035982Sahl cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args);
43045982Sahl
43050Sstevel@tonic-gate if (vp == NULL) {
43060Sstevel@tonic-gate error = ESTALE;
43070Sstevel@tonic-gate goto out;
43080Sstevel@tonic-gate }
43090Sstevel@tonic-gate
43104971Sjarrett if (is_system_labeled()) {
43114971Sjarrett bslabel_t *clabel = req->rq_label;
43124971Sjarrett
43134971Sjarrett ASSERT(clabel != NULL);
43144971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
43154971Sjarrett "got client label from request(1)", struct svc_req *, req);
43164971Sjarrett
43174971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
43189871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
43199871SJarrett.Lu@Sun.COM exi)) {
43204971Sjarrett resp->status = NFS3ERR_ACCES;
43214971Sjarrett goto out1;
43224971Sjarrett }
43234971Sjarrett }
43244971Sjarrett }
43254971Sjarrett
43260Sstevel@tonic-gate #ifdef DEBUG
43270Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
43280Sstevel@tonic-gate va.va_mask = AT_ALL;
43295331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
43300Sstevel@tonic-gate } else
43310Sstevel@tonic-gate vap = NULL;
43320Sstevel@tonic-gate #else
43330Sstevel@tonic-gate va.va_mask = AT_ALL;
43345331Samw vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
43350Sstevel@tonic-gate #endif
43360Sstevel@tonic-gate
43375331Samw error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
43380Sstevel@tonic-gate if (error)
43390Sstevel@tonic-gate goto out;
43400Sstevel@tonic-gate resp->resok.info.link_max = (uint32)val;
43410Sstevel@tonic-gate
43425331Samw error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
43430Sstevel@tonic-gate if (error)
43440Sstevel@tonic-gate goto out;
43450Sstevel@tonic-gate resp->resok.info.name_max = (uint32)val;
43460Sstevel@tonic-gate
43475331Samw error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
43480Sstevel@tonic-gate if (error)
43490Sstevel@tonic-gate goto out;
43500Sstevel@tonic-gate if (val == 1)
43510Sstevel@tonic-gate resp->resok.info.no_trunc = TRUE;
43520Sstevel@tonic-gate else
43530Sstevel@tonic-gate resp->resok.info.no_trunc = FALSE;
43540Sstevel@tonic-gate
43555331Samw error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
43560Sstevel@tonic-gate if (error)
43570Sstevel@tonic-gate goto out;
43580Sstevel@tonic-gate if (val == 1)
43590Sstevel@tonic-gate resp->resok.info.chown_restricted = TRUE;
43600Sstevel@tonic-gate else
43610Sstevel@tonic-gate resp->resok.info.chown_restricted = FALSE;
43620Sstevel@tonic-gate
43630Sstevel@tonic-gate resp->status = NFS3_OK;
43640Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
43650Sstevel@tonic-gate resp->resok.info.case_insensitive = FALSE;
43660Sstevel@tonic-gate resp->resok.info.case_preserving = TRUE;
43675982Sahl DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
43685982Sahl cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
43695982Sahl VN_RELE(vp);
43700Sstevel@tonic-gate return;
43710Sstevel@tonic-gate
43720Sstevel@tonic-gate out:
43730Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
43740Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
43750Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
43760Sstevel@tonic-gate } else
43770Sstevel@tonic-gate resp->status = puterrno3(error);
43784971Sjarrett out1:
43795982Sahl DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
43805982Sahl cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
43810Sstevel@tonic-gate if (vp != NULL)
43820Sstevel@tonic-gate VN_RELE(vp);
43830Sstevel@tonic-gate vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
43840Sstevel@tonic-gate }
43850Sstevel@tonic-gate
43861610Sthurlow void *
rfs3_pathconf_getfh(PATHCONF3args * args)43870Sstevel@tonic-gate rfs3_pathconf_getfh(PATHCONF3args *args)
43880Sstevel@tonic-gate {
43890Sstevel@tonic-gate
43901610Sthurlow return (&args->object);
43910Sstevel@tonic-gate }
43920Sstevel@tonic-gate
43930Sstevel@tonic-gate void
rfs3_commit(COMMIT3args * args,COMMIT3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)43940Sstevel@tonic-gate rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
43950Sstevel@tonic-gate struct svc_req *req, cred_t *cr)
43960Sstevel@tonic-gate {
43970Sstevel@tonic-gate int error;
43980Sstevel@tonic-gate vnode_t *vp;
43990Sstevel@tonic-gate struct vattr *bvap;
44000Sstevel@tonic-gate struct vattr bva;
44010Sstevel@tonic-gate struct vattr *avap;
44020Sstevel@tonic-gate struct vattr ava;
44030Sstevel@tonic-gate
44040Sstevel@tonic-gate bvap = NULL;
44050Sstevel@tonic-gate avap = NULL;
44060Sstevel@tonic-gate
44070Sstevel@tonic-gate vp = nfs3_fhtovp(&args->file, exi);
44085982Sahl
44095982Sahl DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
44105982Sahl cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
44115982Sahl
44120Sstevel@tonic-gate if (vp == NULL) {
44130Sstevel@tonic-gate error = ESTALE;
44140Sstevel@tonic-gate goto out;
44150Sstevel@tonic-gate }
44160Sstevel@tonic-gate
44170Sstevel@tonic-gate bva.va_mask = AT_ALL;
44185331Samw error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
44190Sstevel@tonic-gate
44200Sstevel@tonic-gate /*
44210Sstevel@tonic-gate * If we can't get the attributes, then we can't do the
44220Sstevel@tonic-gate * right access checking. So, we'll fail the request.
44230Sstevel@tonic-gate */
44240Sstevel@tonic-gate if (error)
44250Sstevel@tonic-gate goto out;
44260Sstevel@tonic-gate
44270Sstevel@tonic-gate #ifdef DEBUG
44280Sstevel@tonic-gate if (rfs3_do_pre_op_attr)
44290Sstevel@tonic-gate bvap = &bva;
44300Sstevel@tonic-gate else
44310Sstevel@tonic-gate bvap = NULL;
44320Sstevel@tonic-gate #else
44330Sstevel@tonic-gate bvap = &bva;
44340Sstevel@tonic-gate #endif
44350Sstevel@tonic-gate
44360Sstevel@tonic-gate if (rdonly(exi, req)) {
44370Sstevel@tonic-gate resp->status = NFS3ERR_ROFS;
44380Sstevel@tonic-gate goto out1;
44390Sstevel@tonic-gate }
44400Sstevel@tonic-gate
44410Sstevel@tonic-gate if (vp->v_type != VREG) {
44420Sstevel@tonic-gate resp->status = NFS3ERR_INVAL;
44430Sstevel@tonic-gate goto out1;
44440Sstevel@tonic-gate }
44450Sstevel@tonic-gate
44464971Sjarrett if (is_system_labeled()) {
44474971Sjarrett bslabel_t *clabel = req->rq_label;
44484971Sjarrett
44494971Sjarrett ASSERT(clabel != NULL);
44504971Sjarrett DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *,
44514971Sjarrett "got client label from request(1)", struct svc_req *, req);
44524971Sjarrett
44534971Sjarrett if (!blequal(&l_admin_low->tsl_label, clabel)) {
44549871SJarrett.Lu@Sun.COM if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
44559871SJarrett.Lu@Sun.COM exi)) {
44564971Sjarrett resp->status = NFS3ERR_ACCES;
44574971Sjarrett goto out1;
44584971Sjarrett }
44594971Sjarrett }
44604971Sjarrett }
44614971Sjarrett
44620Sstevel@tonic-gate if (crgetuid(cr) != bva.va_uid &&
44635331Samw (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
44640Sstevel@tonic-gate goto out;
44650Sstevel@tonic-gate
446611894SJeff.A.Smith@Sun.Com error = VOP_FSYNC(vp, FSYNC, cr, NULL);
44670Sstevel@tonic-gate
44680Sstevel@tonic-gate #ifdef DEBUG
44690Sstevel@tonic-gate if (rfs3_do_post_op_attr) {
44700Sstevel@tonic-gate ava.va_mask = AT_ALL;
44715331Samw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
44720Sstevel@tonic-gate } else
44730Sstevel@tonic-gate avap = NULL;
44740Sstevel@tonic-gate #else
44750Sstevel@tonic-gate ava.va_mask = AT_ALL;
44765331Samw avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
44770Sstevel@tonic-gate #endif
44780Sstevel@tonic-gate
44790Sstevel@tonic-gate if (error)
44800Sstevel@tonic-gate goto out;
44810Sstevel@tonic-gate
44820Sstevel@tonic-gate resp->status = NFS3_OK;
44830Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
44840Sstevel@tonic-gate resp->resok.verf = write3verf;
44855982Sahl
44865982Sahl DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
44875982Sahl cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
44885982Sahl
44895982Sahl VN_RELE(vp);
44905982Sahl
44910Sstevel@tonic-gate return;
44920Sstevel@tonic-gate
44930Sstevel@tonic-gate out:
44940Sstevel@tonic-gate if (curthread->t_flag & T_WOULDBLOCK) {
44950Sstevel@tonic-gate curthread->t_flag &= ~T_WOULDBLOCK;
44960Sstevel@tonic-gate resp->status = NFS3ERR_JUKEBOX;
44970Sstevel@tonic-gate } else
44980Sstevel@tonic-gate resp->status = puterrno3(error);
44990Sstevel@tonic-gate out1:
45005982Sahl DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
45015982Sahl cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
45025982Sahl
45030Sstevel@tonic-gate if (vp != NULL)
45040Sstevel@tonic-gate VN_RELE(vp);
45050Sstevel@tonic-gate vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
45060Sstevel@tonic-gate }
45070Sstevel@tonic-gate
45081610Sthurlow void *
rfs3_commit_getfh(COMMIT3args * args)45090Sstevel@tonic-gate rfs3_commit_getfh(COMMIT3args *args)
45100Sstevel@tonic-gate {
45110Sstevel@tonic-gate
45121610Sthurlow return (&args->file);
45130Sstevel@tonic-gate }
45140Sstevel@tonic-gate
45150Sstevel@tonic-gate static int
sattr3_to_vattr(sattr3 * sap,struct vattr * vap)45160Sstevel@tonic-gate sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
45170Sstevel@tonic-gate {
45180Sstevel@tonic-gate
45190Sstevel@tonic-gate vap->va_mask = 0;
45200Sstevel@tonic-gate
45210Sstevel@tonic-gate if (sap->mode.set_it) {
45220Sstevel@tonic-gate vap->va_mode = (mode_t)sap->mode.mode;
45230Sstevel@tonic-gate vap->va_mask |= AT_MODE;
45240Sstevel@tonic-gate }
45250Sstevel@tonic-gate if (sap->uid.set_it) {
45260Sstevel@tonic-gate vap->va_uid = (uid_t)sap->uid.uid;
45270Sstevel@tonic-gate vap->va_mask |= AT_UID;
45280Sstevel@tonic-gate }
45290Sstevel@tonic-gate if (sap->gid.set_it) {
45300Sstevel@tonic-gate vap->va_gid = (gid_t)sap->gid.gid;
45310Sstevel@tonic-gate vap->va_mask |= AT_GID;
45320Sstevel@tonic-gate }
45330Sstevel@tonic-gate if (sap->size.set_it) {
45340Sstevel@tonic-gate if (sap->size.size > (size3)((u_longlong_t)-1))
45350Sstevel@tonic-gate return (EINVAL);
45360Sstevel@tonic-gate vap->va_size = sap->size.size;
45370Sstevel@tonic-gate vap->va_mask |= AT_SIZE;
45380Sstevel@tonic-gate }
45390Sstevel@tonic-gate if (sap->atime.set_it == SET_TO_CLIENT_TIME) {
45400Sstevel@tonic-gate #ifndef _LP64
45410Sstevel@tonic-gate /* check time validity */
45420Sstevel@tonic-gate if (!NFS3_TIME_OK(sap->atime.atime.seconds))
45430Sstevel@tonic-gate return (EOVERFLOW);
45440Sstevel@tonic-gate #endif
45450Sstevel@tonic-gate /*
45460Sstevel@tonic-gate * nfs protocol defines times as unsigned so don't extend sign,
45470Sstevel@tonic-gate * unless sysadmin set nfs_allow_preepoch_time.
45480Sstevel@tonic-gate */
45490Sstevel@tonic-gate NFS_TIME_T_CONVERT(vap->va_atime.tv_sec,
45505599Sjwahlig sap->atime.atime.seconds);
45510Sstevel@tonic-gate vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds;
45520Sstevel@tonic-gate vap->va_mask |= AT_ATIME;
45530Sstevel@tonic-gate } else if (sap->atime.set_it == SET_TO_SERVER_TIME) {
45540Sstevel@tonic-gate gethrestime(&vap->va_atime);
45550Sstevel@tonic-gate vap->va_mask |= AT_ATIME;
45560Sstevel@tonic-gate }
45570Sstevel@tonic-gate if (sap->mtime.set_it == SET_TO_CLIENT_TIME) {
45580Sstevel@tonic-gate #ifndef _LP64
45590Sstevel@tonic-gate /* check time validity */
45600Sstevel@tonic-gate if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
45610Sstevel@tonic-gate return (EOVERFLOW);
45620Sstevel@tonic-gate #endif
45630Sstevel@tonic-gate /*
45640Sstevel@tonic-gate * nfs protocol defines times as unsigned so don't extend sign,
45650Sstevel@tonic-gate * unless sysadmin set nfs_allow_preepoch_time.
45660Sstevel@tonic-gate */
45670Sstevel@tonic-gate NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
45685599Sjwahlig sap->mtime.mtime.seconds);
45690Sstevel@tonic-gate vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
45700Sstevel@tonic-gate vap->va_mask |= AT_MTIME;
45710Sstevel@tonic-gate } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
45720Sstevel@tonic-gate gethrestime(&vap->va_mtime);
45730Sstevel@tonic-gate vap->va_mask |= AT_MTIME;
45740Sstevel@tonic-gate }
45750Sstevel@tonic-gate
45760Sstevel@tonic-gate return (0);
45770Sstevel@tonic-gate }
45780Sstevel@tonic-gate
45790Sstevel@tonic-gate static ftype3 vt_to_nf3[] = {
45800Sstevel@tonic-gate 0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
45810Sstevel@tonic-gate };
45820Sstevel@tonic-gate
45830Sstevel@tonic-gate static int
vattr_to_fattr3(struct vattr * vap,fattr3 * fap)45840Sstevel@tonic-gate vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
45850Sstevel@tonic-gate {
45860Sstevel@tonic-gate
45870Sstevel@tonic-gate ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
45880Sstevel@tonic-gate /* Return error if time or size overflow */
45890Sstevel@tonic-gate if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
45900Sstevel@tonic-gate return (EOVERFLOW);
45910Sstevel@tonic-gate }
45920Sstevel@tonic-gate fap->type = vt_to_nf3[vap->va_type];
45930Sstevel@tonic-gate fap->mode = (mode3)(vap->va_mode & MODEMASK);
45940Sstevel@tonic-gate fap->nlink = (uint32)vap->va_nlink;
45950Sstevel@tonic-gate if (vap->va_uid == UID_NOBODY)
45960Sstevel@tonic-gate fap->uid = (uid3)NFS_UID_NOBODY;
45970Sstevel@tonic-gate else
45980Sstevel@tonic-gate fap->uid = (uid3)vap->va_uid;
45990Sstevel@tonic-gate if (vap->va_gid == GID_NOBODY)
46000Sstevel@tonic-gate fap->gid = (gid3)NFS_GID_NOBODY;
46010Sstevel@tonic-gate else
46020Sstevel@tonic-gate fap->gid = (gid3)vap->va_gid;
46030Sstevel@tonic-gate fap->size = (size3)vap->va_size;
46040Sstevel@tonic-gate fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks;
46050Sstevel@tonic-gate fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev);
46060Sstevel@tonic-gate fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev);
46070Sstevel@tonic-gate fap->fsid = (uint64)vap->va_fsid;
46080Sstevel@tonic-gate fap->fileid = (fileid3)vap->va_nodeid;
46090Sstevel@tonic-gate fap->atime.seconds = vap->va_atime.tv_sec;
46100Sstevel@tonic-gate fap->atime.nseconds = vap->va_atime.tv_nsec;
46110Sstevel@tonic-gate fap->mtime.seconds = vap->va_mtime.tv_sec;
46120Sstevel@tonic-gate fap->mtime.nseconds = vap->va_mtime.tv_nsec;
46130Sstevel@tonic-gate fap->ctime.seconds = vap->va_ctime.tv_sec;
46140Sstevel@tonic-gate fap->ctime.nseconds = vap->va_ctime.tv_nsec;
46150Sstevel@tonic-gate return (0);
46160Sstevel@tonic-gate }
46170Sstevel@tonic-gate
46180Sstevel@tonic-gate static int
vattr_to_wcc_attr(struct vattr * vap,wcc_attr * wccap)46190Sstevel@tonic-gate vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap)
46200Sstevel@tonic-gate {
46210Sstevel@tonic-gate
46220Sstevel@tonic-gate /* Return error if time or size overflow */
46237387SRobert.Gordon@Sun.COM if (!(NFS_TIME_T_OK(vap->va_mtime.tv_sec) &&
46245599Sjwahlig NFS_TIME_T_OK(vap->va_ctime.tv_sec) &&
46255599Sjwahlig NFS3_SIZE_OK(vap->va_size))) {
46260Sstevel@tonic-gate return (EOVERFLOW);
46270Sstevel@tonic-gate }
46280Sstevel@tonic-gate wccap->size = (size3)vap->va_size;
46290Sstevel@tonic-gate wccap->mtime.seconds = vap->va_mtime.tv_sec;
46300Sstevel@tonic-gate wccap->mtime.nseconds = vap->va_mtime.tv_nsec;
46310Sstevel@tonic-gate wccap->ctime.seconds = vap->va_ctime.tv_sec;
46320Sstevel@tonic-gate wccap->ctime.nseconds = vap->va_ctime.tv_nsec;
46330Sstevel@tonic-gate return (0);
46340Sstevel@tonic-gate }
46350Sstevel@tonic-gate
46360Sstevel@tonic-gate static void
vattr_to_pre_op_attr(struct vattr * vap,pre_op_attr * poap)46370Sstevel@tonic-gate vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap)
46380Sstevel@tonic-gate {
46390Sstevel@tonic-gate
46400Sstevel@tonic-gate /* don't return attrs if time overflow */
46410Sstevel@tonic-gate if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
46420Sstevel@tonic-gate poap->attributes = TRUE;
46430Sstevel@tonic-gate } else
46440Sstevel@tonic-gate poap->attributes = FALSE;
46450Sstevel@tonic-gate }
46460Sstevel@tonic-gate
46470Sstevel@tonic-gate void
vattr_to_post_op_attr(struct vattr * vap,post_op_attr * poap)46480Sstevel@tonic-gate vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
46490Sstevel@tonic-gate {
46500Sstevel@tonic-gate
46510Sstevel@tonic-gate /* don't return attrs if time overflow */
46520Sstevel@tonic-gate if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
46530Sstevel@tonic-gate poap->attributes = TRUE;
46540Sstevel@tonic-gate } else
46550Sstevel@tonic-gate poap->attributes = FALSE;
46560Sstevel@tonic-gate }
46570Sstevel@tonic-gate
46580Sstevel@tonic-gate static void
vattr_to_wcc_data(struct vattr * bvap,struct vattr * avap,wcc_data * wccp)46590Sstevel@tonic-gate vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
46600Sstevel@tonic-gate {
46610Sstevel@tonic-gate
46620Sstevel@tonic-gate vattr_to_pre_op_attr(bvap, &wccp->before);
46630Sstevel@tonic-gate vattr_to_post_op_attr(avap, &wccp->after);
46640Sstevel@tonic-gate }
46650Sstevel@tonic-gate
46660Sstevel@tonic-gate void
rfs3_srvrinit(void)46670Sstevel@tonic-gate rfs3_srvrinit(void)
46680Sstevel@tonic-gate {
46690Sstevel@tonic-gate struct rfs3_verf_overlay {
46700Sstevel@tonic-gate uint_t id; /* a "unique" identifier */
46710Sstevel@tonic-gate int ts; /* a unique timestamp */
46720Sstevel@tonic-gate } *verfp;
46730Sstevel@tonic-gate timestruc_t now;
46740Sstevel@tonic-gate
46750Sstevel@tonic-gate /*
46760Sstevel@tonic-gate * The following algorithm attempts to find a unique verifier
46770Sstevel@tonic-gate * to be used as the write verifier returned from the server
46780Sstevel@tonic-gate * to the client. It is important that this verifier change
46790Sstevel@tonic-gate * whenever the server reboots. Of secondary importance, it
46800Sstevel@tonic-gate * is important for the verifier to be unique between two
46810Sstevel@tonic-gate * different servers.
46820Sstevel@tonic-gate *
46830Sstevel@tonic-gate * Thus, an attempt is made to use the system hostid and the
46840Sstevel@tonic-gate * current time in seconds when the nfssrv kernel module is
46850Sstevel@tonic-gate * loaded. It is assumed that an NFS server will not be able
46860Sstevel@tonic-gate * to boot and then to reboot in less than a second. If the
46870Sstevel@tonic-gate * hostid has not been set, then the current high resolution
46880Sstevel@tonic-gate * time is used. This will ensure different verifiers each
46890Sstevel@tonic-gate * time the server reboots and minimize the chances that two
46900Sstevel@tonic-gate * different servers will have the same verifier.
46910Sstevel@tonic-gate */
46920Sstevel@tonic-gate
46930Sstevel@tonic-gate #ifndef lint
46940Sstevel@tonic-gate /*
46950Sstevel@tonic-gate * We ASSERT that this constant logic expression is
46960Sstevel@tonic-gate * always true because in the past, it wasn't.
46970Sstevel@tonic-gate */
46980Sstevel@tonic-gate ASSERT(sizeof (*verfp) <= sizeof (write3verf));
46990Sstevel@tonic-gate #endif
47000Sstevel@tonic-gate
47010Sstevel@tonic-gate gethrestime(&now);
47020Sstevel@tonic-gate verfp = (struct rfs3_verf_overlay *)&write3verf;
47030Sstevel@tonic-gate verfp->ts = (int)now.tv_sec;
47048662SJordan.Vaughan@Sun.com verfp->id = zone_get_hostid(NULL);
47050Sstevel@tonic-gate
47060Sstevel@tonic-gate if (verfp->id == 0)
47070Sstevel@tonic-gate verfp->id = (uint_t)now.tv_nsec;
47080Sstevel@tonic-gate
47095599Sjwahlig nfs3_srv_caller_id = fs_new_caller_id();
47105599Sjwahlig
47110Sstevel@tonic-gate }
47120Sstevel@tonic-gate
47137387SRobert.Gordon@Sun.COM static int
rdma_setup_read_data3(READ3args * args,READ3resok * rok)47147387SRobert.Gordon@Sun.COM rdma_setup_read_data3(READ3args *args, READ3resok *rok)
47157387SRobert.Gordon@Sun.COM {
47167387SRobert.Gordon@Sun.COM struct clist *wcl;
47179348SSiddheshwar.Mahesh@Sun.COM int wlist_len;
47187387SRobert.Gordon@Sun.COM count3 count = rok->count;
47197387SRobert.Gordon@Sun.COM
47207387SRobert.Gordon@Sun.COM wcl = args->wlist;
47219348SSiddheshwar.Mahesh@Sun.COM if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
47227387SRobert.Gordon@Sun.COM return (FALSE);
47237387SRobert.Gordon@Sun.COM }
47247387SRobert.Gordon@Sun.COM
47257387SRobert.Gordon@Sun.COM wcl = args->wlist;
47269348SSiddheshwar.Mahesh@Sun.COM rok->wlist_len = wlist_len;
47277387SRobert.Gordon@Sun.COM rok->wlist = wcl;
47287387SRobert.Gordon@Sun.COM return (TRUE);
47297387SRobert.Gordon@Sun.COM }
47307387SRobert.Gordon@Sun.COM
47310Sstevel@tonic-gate void
rfs3_srvrfini(void)47320Sstevel@tonic-gate rfs3_srvrfini(void)
47330Sstevel@tonic-gate {
47340Sstevel@tonic-gate /* Nothing to do */
47350Sstevel@tonic-gate }
4736