1*8329232eSGordon Ross /*
2*8329232eSGordon Ross * CDDL HEADER START
3*8329232eSGordon Ross *
4*8329232eSGordon Ross * The contents of this file are subject to the terms of the
5*8329232eSGordon Ross * Common Development and Distribution License (the "License").
6*8329232eSGordon Ross * You may not use this file except in compliance with the License.
7*8329232eSGordon Ross *
8*8329232eSGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8329232eSGordon Ross * or http://www.opensolaris.org/os/licensing.
10*8329232eSGordon Ross * See the License for the specific language governing permissions
11*8329232eSGordon Ross * and limitations under the License.
12*8329232eSGordon Ross *
13*8329232eSGordon Ross * When distributing Covered Code, include this CDDL HEADER in each
14*8329232eSGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8329232eSGordon Ross * If applicable, add the following below this CDDL HEADER, with the
16*8329232eSGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
17*8329232eSGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
18*8329232eSGordon Ross *
19*8329232eSGordon Ross * CDDL HEADER END
20*8329232eSGordon Ross */
21*8329232eSGordon Ross /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22*8329232eSGordon Ross /* All Rights Reserved */
23*8329232eSGordon Ross
24*8329232eSGordon Ross
25*8329232eSGordon Ross /*
26*8329232eSGordon Ross * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
27*8329232eSGordon Ross * Copyright 2017 Joyent, Inc.
28*8329232eSGordon Ross * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
29*8329232eSGordon Ross */
30*8329232eSGordon Ross
31*8329232eSGordon Ross /*
32*8329232eSGordon Ross * Generic vnode operations.
33*8329232eSGordon Ross */
34*8329232eSGordon Ross #include <sys/types.h>
35*8329232eSGordon Ross #include <sys/param.h>
36*8329232eSGordon Ross #include <sys/systm.h>
37*8329232eSGordon Ross #include <sys/errno.h>
38*8329232eSGordon Ross #include <sys/fcntl.h>
39*8329232eSGordon Ross #include <sys/flock.h>
40*8329232eSGordon Ross #include <sys/statvfs.h>
41*8329232eSGordon Ross #include <sys/vfs.h>
42*8329232eSGordon Ross #include <sys/vnode.h>
43*8329232eSGordon Ross #include <sys/cred.h>
44*8329232eSGordon Ross #include <sys/poll.h>
45*8329232eSGordon Ross #include <sys/debug.h>
46*8329232eSGordon Ross #include <sys/cmn_err.h>
47*8329232eSGordon Ross #include <sys/share.h>
48*8329232eSGordon Ross #include <sys/file.h>
49*8329232eSGordon Ross #include <sys/kmem.h>
50*8329232eSGordon Ross #include <sys/nbmlock.h>
51*8329232eSGordon Ross #include <sys/acl.h>
52*8329232eSGordon Ross
53*8329232eSGordon Ross #include <acl/acl_common.h>
54*8329232eSGordon Ross #include <fs/fs_subr.h>
55*8329232eSGordon Ross
56*8329232eSGordon Ross /*
57*8329232eSGordon Ross * Tunable to limit the number of retry to recover from STALE error.
58*8329232eSGordon Ross */
59*8329232eSGordon Ross int fs_estale_retry = 5;
60*8329232eSGordon Ross
61*8329232eSGordon Ross /*
62*8329232eSGordon Ross * The associated operation is not supported by the file system.
63*8329232eSGordon Ross */
64*8329232eSGordon Ross int
fs_nosys()65*8329232eSGordon Ross fs_nosys()
66*8329232eSGordon Ross {
67*8329232eSGordon Ross return (ENOSYS);
68*8329232eSGordon Ross }
69*8329232eSGordon Ross
70*8329232eSGordon Ross /*
71*8329232eSGordon Ross * The associated operation is invalid (on this vnode).
72*8329232eSGordon Ross */
73*8329232eSGordon Ross int
fs_inval()74*8329232eSGordon Ross fs_inval()
75*8329232eSGordon Ross {
76*8329232eSGordon Ross return (EINVAL);
77*8329232eSGordon Ross }
78*8329232eSGordon Ross
79*8329232eSGordon Ross /*
80*8329232eSGordon Ross * The associated operation is valid only for directories.
81*8329232eSGordon Ross */
82*8329232eSGordon Ross int
fs_notdir()83*8329232eSGordon Ross fs_notdir()
84*8329232eSGordon Ross {
85*8329232eSGordon Ross return (ENOTDIR);
86*8329232eSGordon Ross }
87*8329232eSGordon Ross
88*8329232eSGordon Ross /*
89*8329232eSGordon Ross * Free the file system specific resources. For the file systems that
90*8329232eSGordon Ross * do not support the forced unmount, it will be a nop function.
91*8329232eSGordon Ross */
92*8329232eSGordon Ross
93*8329232eSGordon Ross /*ARGSUSED*/
94*8329232eSGordon Ross void
fs_freevfs(vfs_t * vfsp)95*8329232eSGordon Ross fs_freevfs(vfs_t *vfsp)
96*8329232eSGordon Ross {
97*8329232eSGordon Ross }
98*8329232eSGordon Ross
99*8329232eSGordon Ross /* ARGSUSED */
100*8329232eSGordon Ross int
fs_nosys_map(struct vnode * vp,offset_t off,struct as * as,caddr_t * addrp,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)101*8329232eSGordon Ross fs_nosys_map(struct vnode *vp, offset_t off, struct as *as, caddr_t *addrp,
102*8329232eSGordon Ross size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
103*8329232eSGordon Ross caller_context_t *ct)
104*8329232eSGordon Ross {
105*8329232eSGordon Ross return (ENOSYS);
106*8329232eSGordon Ross }
107*8329232eSGordon Ross
108*8329232eSGordon Ross /* ARGSUSED */
109*8329232eSGordon Ross int
fs_nosys_addmap(struct vnode * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)110*8329232eSGordon Ross fs_nosys_addmap(struct vnode *vp, offset_t off, struct as *as, caddr_t addr,
111*8329232eSGordon Ross size_t len, uchar_t prot, uchar_t maxprot, uint_t flags, struct cred *cr,
112*8329232eSGordon Ross caller_context_t *ct)
113*8329232eSGordon Ross {
114*8329232eSGordon Ross return (ENOSYS);
115*8329232eSGordon Ross }
116*8329232eSGordon Ross
117*8329232eSGordon Ross /* ARGSUSED */
118*8329232eSGordon Ross int
fs_nosys_poll(vnode_t * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)119*8329232eSGordon Ross fs_nosys_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
120*8329232eSGordon Ross struct pollhead **phpp, caller_context_t *ct)
121*8329232eSGordon Ross {
122*8329232eSGordon Ross return (ENOSYS);
123*8329232eSGordon Ross }
124*8329232eSGordon Ross
125*8329232eSGordon Ross
126*8329232eSGordon Ross /*
127*8329232eSGordon Ross * The file system has nothing to sync to disk. However, the
128*8329232eSGordon Ross * VFS_SYNC operation must not fail.
129*8329232eSGordon Ross */
130*8329232eSGordon Ross /* ARGSUSED */
131*8329232eSGordon Ross int
fs_sync(struct vfs * vfspp,short flag,cred_t * cr)132*8329232eSGordon Ross fs_sync(struct vfs *vfspp, short flag, cred_t *cr)
133*8329232eSGordon Ross {
134*8329232eSGordon Ross return (0);
135*8329232eSGordon Ross }
136*8329232eSGordon Ross
137*8329232eSGordon Ross /*
138*8329232eSGordon Ross * Does nothing but VOP_FSYNC must not fail.
139*8329232eSGordon Ross */
140*8329232eSGordon Ross /* ARGSUSED */
141*8329232eSGordon Ross int
fs_fsync(vnode_t * vp,int syncflag,cred_t * cr,caller_context_t * ct)142*8329232eSGordon Ross fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
143*8329232eSGordon Ross {
144*8329232eSGordon Ross return (0);
145*8329232eSGordon Ross }
146*8329232eSGordon Ross
147*8329232eSGordon Ross /*
148*8329232eSGordon Ross * Does nothing but VOP_PUTPAGE must not fail.
149*8329232eSGordon Ross */
150*8329232eSGordon Ross /* ARGSUSED */
151*8329232eSGordon Ross int
fs_putpage(vnode_t * vp,offset_t off,size_t len,int flags,cred_t * cr,caller_context_t * ctp)152*8329232eSGordon Ross fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
153*8329232eSGordon Ross caller_context_t *ctp)
154*8329232eSGordon Ross {
155*8329232eSGordon Ross return (0);
156*8329232eSGordon Ross }
157*8329232eSGordon Ross
158*8329232eSGordon Ross /*
159*8329232eSGordon Ross * Does nothing but VOP_IOCTL must not fail.
160*8329232eSGordon Ross */
161*8329232eSGordon Ross /* ARGSUSED */
162*8329232eSGordon Ross int
fs_ioctl(vnode_t * vp,int com,intptr_t data,int flag,cred_t * cred,int * rvalp)163*8329232eSGordon Ross fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
164*8329232eSGordon Ross int *rvalp)
165*8329232eSGordon Ross {
166*8329232eSGordon Ross return (0);
167*8329232eSGordon Ross }
168*8329232eSGordon Ross
169*8329232eSGordon Ross /*
170*8329232eSGordon Ross * Read/write lock/unlock. Does nothing.
171*8329232eSGordon Ross */
172*8329232eSGordon Ross /* ARGSUSED */
173*8329232eSGordon Ross int
fs_rwlock(vnode_t * vp,int write_lock,caller_context_t * ctp)174*8329232eSGordon Ross fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
175*8329232eSGordon Ross {
176*8329232eSGordon Ross return (-1);
177*8329232eSGordon Ross }
178*8329232eSGordon Ross
179*8329232eSGordon Ross /* ARGSUSED */
180*8329232eSGordon Ross void
fs_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ctp)181*8329232eSGordon Ross fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
182*8329232eSGordon Ross {
183*8329232eSGordon Ross }
184*8329232eSGordon Ross
185*8329232eSGordon Ross /*
186*8329232eSGordon Ross * Compare two vnodes.
187*8329232eSGordon Ross */
188*8329232eSGordon Ross /*ARGSUSED2*/
189*8329232eSGordon Ross int
fs_cmp(vnode_t * vp1,vnode_t * vp2,caller_context_t * ct)190*8329232eSGordon Ross fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
191*8329232eSGordon Ross {
192*8329232eSGordon Ross return (vp1 == vp2);
193*8329232eSGordon Ross }
194*8329232eSGordon Ross
195*8329232eSGordon Ross /*
196*8329232eSGordon Ross * No-op seek operation.
197*8329232eSGordon Ross */
198*8329232eSGordon Ross /* ARGSUSED */
199*8329232eSGordon Ross int
fs_seek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)200*8329232eSGordon Ross fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
201*8329232eSGordon Ross {
202*8329232eSGordon Ross return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0);
203*8329232eSGordon Ross }
204*8329232eSGordon Ross
205*8329232eSGordon Ross /*
206*8329232eSGordon Ross * File and record locking.
207*8329232eSGordon Ross */
208*8329232eSGordon Ross /* ARGSUSED */
209*8329232eSGordon Ross int
fs_frlock(vnode_t * vp,int cmd,struct flock64 * bfp,int flag,offset_t offset,flk_callback_t * flk_cbp,cred_t * cr,caller_context_t * ct)210*8329232eSGordon Ross fs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, offset_t offset,
211*8329232eSGordon Ross flk_callback_t *flk_cbp, cred_t *cr, caller_context_t *ct)
212*8329232eSGordon Ross {
213*8329232eSGordon Ross return (ENOSYS);
214*8329232eSGordon Ross }
215*8329232eSGordon Ross
216*8329232eSGordon Ross /*
217*8329232eSGordon Ross * Allow any flags.
218*8329232eSGordon Ross */
219*8329232eSGordon Ross /* ARGSUSED */
220*8329232eSGordon Ross int
fs_setfl(vnode_t * vp,int oflags,int nflags,cred_t * cr,caller_context_t * ct)221*8329232eSGordon Ross fs_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct)
222*8329232eSGordon Ross {
223*8329232eSGordon Ross return (0);
224*8329232eSGordon Ross }
225*8329232eSGordon Ross
226*8329232eSGordon Ross /*
227*8329232eSGordon Ross * Return the answer requested to poll() for non-device files.
228*8329232eSGordon Ross * Only POLLIN, POLLRDNORM, and POLLOUT are recognized.
229*8329232eSGordon Ross */
230*8329232eSGordon Ross struct pollhead fs_pollhd;
231*8329232eSGordon Ross
232*8329232eSGordon Ross /* ARGSUSED */
233*8329232eSGordon Ross int
fs_poll(vnode_t * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)234*8329232eSGordon Ross fs_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
235*8329232eSGordon Ross struct pollhead **phpp, caller_context_t *ct)
236*8329232eSGordon Ross {
237*8329232eSGordon Ross if (events & POLLET) {
238*8329232eSGordon Ross return (EPERM);
239*8329232eSGordon Ross }
240*8329232eSGordon Ross
241*8329232eSGordon Ross *reventsp = 0;
242*8329232eSGordon Ross if (events & POLLIN)
243*8329232eSGordon Ross *reventsp |= POLLIN;
244*8329232eSGordon Ross if (events & POLLRDNORM)
245*8329232eSGordon Ross *reventsp |= POLLRDNORM;
246*8329232eSGordon Ross if (events & POLLRDBAND)
247*8329232eSGordon Ross *reventsp |= POLLRDBAND;
248*8329232eSGordon Ross if (events & POLLOUT)
249*8329232eSGordon Ross *reventsp |= POLLOUT;
250*8329232eSGordon Ross if (events & POLLWRBAND)
251*8329232eSGordon Ross *reventsp |= POLLWRBAND;
252*8329232eSGordon Ross if (*reventsp == 0 && !anyyet) {
253*8329232eSGordon Ross *phpp = &fs_pollhd;
254*8329232eSGordon Ross }
255*8329232eSGordon Ross return (0);
256*8329232eSGordon Ross }
257*8329232eSGordon Ross
258*8329232eSGordon Ross /*
259*8329232eSGordon Ross * POSIX pathconf() support.
260*8329232eSGordon Ross */
261*8329232eSGordon Ross /* ARGSUSED */
262*8329232eSGordon Ross int
fs_pathconf(vnode_t * vp,int cmd,ulong_t * valp,cred_t * cr,caller_context_t * ct)263*8329232eSGordon Ross fs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
264*8329232eSGordon Ross caller_context_t *ct)
265*8329232eSGordon Ross {
266*8329232eSGordon Ross /* not called */
267*8329232eSGordon Ross return (EINVAL);
268*8329232eSGordon Ross }
269*8329232eSGordon Ross
270*8329232eSGordon Ross /*
271*8329232eSGordon Ross * Dispose of a page.
272*8329232eSGordon Ross */
273*8329232eSGordon Ross /* ARGSUSED */
274*8329232eSGordon Ross void
fs_dispose(struct vnode * vp,page_t * pp,int fl,int dn,struct cred * cr,caller_context_t * ct)275*8329232eSGordon Ross fs_dispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
276*8329232eSGordon Ross caller_context_t *ct)
277*8329232eSGordon Ross {
278*8329232eSGordon Ross }
279*8329232eSGordon Ross
280*8329232eSGordon Ross /* ARGSUSED */
281*8329232eSGordon Ross void
fs_nodispose(struct vnode * vp,page_t * pp,int fl,int dn,struct cred * cr,caller_context_t * ct)282*8329232eSGordon Ross fs_nodispose(struct vnode *vp, page_t *pp, int fl, int dn, struct cred *cr,
283*8329232eSGordon Ross caller_context_t *ct)
284*8329232eSGordon Ross {
285*8329232eSGordon Ross cmn_err(CE_PANIC, "fs_nodispose invoked");
286*8329232eSGordon Ross }
287*8329232eSGordon Ross
288*8329232eSGordon Ross /*
289*8329232eSGordon Ross * fabricate acls for file systems that do not support acls.
290*8329232eSGordon Ross */
291*8329232eSGordon Ross /* ARGSUSED */
292*8329232eSGordon Ross int
fs_fab_acl(vnode_t * vp,vsecattr_t * vsecattr,int flag,cred_t * cr,caller_context_t * ct)293*8329232eSGordon Ross fs_fab_acl(vnode_t *vp, vsecattr_t *vsecattr, int flag, cred_t *cr,
294*8329232eSGordon Ross caller_context_t *ct)
295*8329232eSGordon Ross {
296*8329232eSGordon Ross struct vattr vattr;
297*8329232eSGordon Ross int error;
298*8329232eSGordon Ross
299*8329232eSGordon Ross vsecattr->vsa_aclcnt = 0;
300*8329232eSGordon Ross vsecattr->vsa_aclentsz = 0;
301*8329232eSGordon Ross vsecattr->vsa_aclentp = NULL;
302*8329232eSGordon Ross vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */
303*8329232eSGordon Ross vsecattr->vsa_dfaclentp = NULL;
304*8329232eSGordon Ross
305*8329232eSGordon Ross vattr.va_mask = AT_MODE | AT_UID | AT_GID;
306*8329232eSGordon Ross if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct))
307*8329232eSGordon Ross return (error);
308*8329232eSGordon Ross
309*8329232eSGordon Ross if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) {
310*8329232eSGordon Ross return (ENOSYS);
311*8329232eSGordon Ross }
312*8329232eSGordon Ross
313*8329232eSGordon Ross if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) {
314*8329232eSGordon Ross VERIFY(0 == acl_trivial_create(vattr.va_mode,
315*8329232eSGordon Ross (vp->v_type == VDIR), (ace_t **)&vsecattr->vsa_aclentp,
316*8329232eSGordon Ross &vsecattr->vsa_aclcnt));
317*8329232eSGordon Ross vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t);
318*8329232eSGordon Ross }
319*8329232eSGordon Ross
320*8329232eSGordon Ross return (error);
321*8329232eSGordon Ross }
322*8329232eSGordon Ross
323*8329232eSGordon Ross /*
324*8329232eSGordon Ross * Common code for implementing DOS share reservations
325*8329232eSGordon Ross */
326*8329232eSGordon Ross /* ARGSUSED */
327*8329232eSGordon Ross int
fs_shrlock(struct vnode * vp,int cmd,struct shrlock * shr,int flag,cred_t * cr,caller_context_t * ct)328*8329232eSGordon Ross fs_shrlock(struct vnode *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
329*8329232eSGordon Ross caller_context_t *ct)
330*8329232eSGordon Ross {
331*8329232eSGordon Ross return (ENOSYS);
332*8329232eSGordon Ross }
333*8329232eSGordon Ross
334*8329232eSGordon Ross /*ARGSUSED1*/
335*8329232eSGordon Ross int
fs_vnevent_nosupport(vnode_t * vp,vnevent_t e,vnode_t * dvp,char * fnm,caller_context_t * ct)336*8329232eSGordon Ross fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
337*8329232eSGordon Ross caller_context_t *ct)
338*8329232eSGordon Ross {
339*8329232eSGordon Ross ASSERT(vp != NULL);
340*8329232eSGordon Ross return (ENOTSUP);
341*8329232eSGordon Ross }
342*8329232eSGordon Ross
343*8329232eSGordon Ross /*ARGSUSED1*/
344*8329232eSGordon Ross int
fs_vnevent_support(vnode_t * vp,vnevent_t e,vnode_t * dvp,char * fnm,caller_context_t * ct)345*8329232eSGordon Ross fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm,
346*8329232eSGordon Ross caller_context_t *ct)
347*8329232eSGordon Ross {
348*8329232eSGordon Ross ASSERT(vp != NULL);
349*8329232eSGordon Ross return (0);
350*8329232eSGordon Ross }
351*8329232eSGordon Ross
352*8329232eSGordon Ross // fs_acl_nontrivial
353*8329232eSGordon Ross
354*8329232eSGordon Ross /*
355*8329232eSGordon Ross * Check whether we need a retry to recover from STALE error.
356*8329232eSGordon Ross */
357*8329232eSGordon Ross int
fs_need_estale_retry(int retry_count)358*8329232eSGordon Ross fs_need_estale_retry(int retry_count)
359*8329232eSGordon Ross {
360*8329232eSGordon Ross if (retry_count < fs_estale_retry)
361*8329232eSGordon Ross return (1);
362*8329232eSGordon Ross else
363*8329232eSGordon Ross return (0);
364*8329232eSGordon Ross }
365*8329232eSGordon Ross
366*8329232eSGordon Ross // fs_vscan...
367*8329232eSGordon Ross // reparse...
368*8329232eSGordon Ross
369*8329232eSGordon Ross /*
370*8329232eSGordon Ross * A few things from os/flock.c
371*8329232eSGordon Ross */
372*8329232eSGordon Ross
373*8329232eSGordon Ross /* ARGSUSED */
374*8329232eSGordon Ross void
cleanlocks(vnode_t * vp,pid_t pid,int sysid)375*8329232eSGordon Ross cleanlocks(vnode_t *vp, pid_t pid, int sysid)
376*8329232eSGordon Ross {
377*8329232eSGordon Ross }
378*8329232eSGordon Ross
379*8329232eSGordon Ross /* ARGSUSED */
380*8329232eSGordon Ross void
cleanshares(struct vnode * vp,pid_t pid)381*8329232eSGordon Ross cleanshares(struct vnode *vp, pid_t pid)
382*8329232eSGordon Ross {
383*8329232eSGordon Ross }
384*8329232eSGordon Ross
385*8329232eSGordon Ross /*
386*8329232eSGordon Ross * convoff - converts the given data (start, whence) to the
387*8329232eSGordon Ross * given whence.
388*8329232eSGordon Ross */
389*8329232eSGordon Ross int
convoff(struct vnode * vp,struct flock64 * lckdat,int whence,offset_t offset)390*8329232eSGordon Ross convoff(struct vnode *vp, struct flock64 *lckdat, int whence, offset_t offset)
391*8329232eSGordon Ross {
392*8329232eSGordon Ross int error;
393*8329232eSGordon Ross struct vattr vattr;
394*8329232eSGordon Ross
395*8329232eSGordon Ross if ((lckdat->l_whence == 2) || (whence == 2)) {
396*8329232eSGordon Ross vattr.va_mask = AT_SIZE;
397*8329232eSGordon Ross if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
398*8329232eSGordon Ross return (error);
399*8329232eSGordon Ross }
400*8329232eSGordon Ross
401*8329232eSGordon Ross switch (lckdat->l_whence) {
402*8329232eSGordon Ross case 1:
403*8329232eSGordon Ross lckdat->l_start += offset;
404*8329232eSGordon Ross break;
405*8329232eSGordon Ross case 2:
406*8329232eSGordon Ross lckdat->l_start += vattr.va_size;
407*8329232eSGordon Ross /* FALLTHRU */
408*8329232eSGordon Ross case 0:
409*8329232eSGordon Ross break;
410*8329232eSGordon Ross default:
411*8329232eSGordon Ross return (EINVAL);
412*8329232eSGordon Ross }
413*8329232eSGordon Ross
414*8329232eSGordon Ross if (lckdat->l_start < 0)
415*8329232eSGordon Ross return (EINVAL);
416*8329232eSGordon Ross
417*8329232eSGordon Ross switch (whence) {
418*8329232eSGordon Ross case 1:
419*8329232eSGordon Ross lckdat->l_start -= offset;
420*8329232eSGordon Ross break;
421*8329232eSGordon Ross case 2:
422*8329232eSGordon Ross lckdat->l_start -= vattr.va_size;
423*8329232eSGordon Ross /* FALLTHRU */
424*8329232eSGordon Ross case 0:
425*8329232eSGordon Ross break;
426*8329232eSGordon Ross default:
427*8329232eSGordon Ross return (EINVAL);
428*8329232eSGordon Ross }
429*8329232eSGordon Ross
430*8329232eSGordon Ross lckdat->l_whence = (short)whence;
431*8329232eSGordon Ross return (0);
432*8329232eSGordon Ross }
433