1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
25 */
26
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
33 */
34
35
36 #include <sys/param.h>
37 #include <sys/isa_defs.h>
38 #include <sys/types.h>
39 #include <sys/sysmacros.h>
40 #include <sys/systm.h>
41 #include <sys/errno.h>
42 #include <sys/fcntl.h>
43 #include <sys/flock.h>
44 #include <sys/vnode.h>
45 #include <sys/file.h>
46 #include <sys/mode.h>
47 #include <sys/proc.h>
48 #include <sys/filio.h>
49 #include <sys/share.h>
50 #include <sys/debug.h>
51 #include <sys/rctl.h>
52 #include <sys/nbmlock.h>
53
54 #include <sys/cmn_err.h>
55
56 static int flock_check(vnode_t *, flock64_t *, offset_t, offset_t);
57 static int flock_get_start(vnode_t *, flock64_t *, offset_t, u_offset_t *);
58 static void fd_too_big(proc_t *);
59
60 /*
61 * File control.
62 */
63 int
64 fcntl(int fdes, int cmd, intptr_t arg)
65 {
66 int iarg;
67 int error = 0;
68 int retval;
69 proc_t *p;
70 file_t *fp;
71 vnode_t *vp;
72 u_offset_t offset;
73 u_offset_t start;
74 struct vattr vattr;
75 int in_crit;
76 int flag;
77 struct flock sbf;
78 struct flock64 bf;
79 struct o_flock obf;
80 struct flock64_32 bf64_32;
81 struct fshare fsh;
82 struct shrlock shr;
83 struct shr_locowner shr_own;
84 offset_t maxoffset;
85 model_t datamodel;
86 int fdres;
87
88 #if defined(_ILP32) && !defined(lint) && defined(_SYSCALL32)
89 ASSERT(sizeof (struct flock) == sizeof (struct flock32));
90 ASSERT(sizeof (struct flock64) == sizeof (struct flock64_32));
91 #endif
92 #if defined(_LP64) && !defined(lint) && defined(_SYSCALL32)
93 ASSERT(sizeof (struct flock) == sizeof (struct flock64_64));
94 ASSERT(sizeof (struct flock64) == sizeof (struct flock64_64));
95 #endif
96
97 /*
98 * First, for speed, deal with the subset of cases
99 * that do not require getf() / releasef().
100 */
101 switch (cmd) {
102 case F_GETFD:
103 if ((error = f_getfd_error(fdes, &flag)) == 0)
104 retval = flag;
105 goto out;
106
107 case F_SETFD:
108 error = f_setfd_error(fdes, (int)arg);
109 retval = 0;
110 goto out;
111
112 case F_GETFL:
113 if ((error = f_getfl(fdes, &flag)) == 0) {
114 retval = (flag & (FMASK | FASYNC));
115 if ((flag & (FSEARCH | FEXEC)) == 0)
116 retval += FOPEN;
117 else
118 retval |= (flag & (FSEARCH | FEXEC));
119 }
120 goto out;
121
122 case F_GETXFL:
123 if ((error = f_getfl(fdes, &flag)) == 0) {
124 retval = flag;
125 if ((flag & (FSEARCH | FEXEC)) == 0)
126 retval += FOPEN;
127 }
128 goto out;
129
130 case F_BADFD:
131 if ((error = f_badfd(fdes, &fdres, (int)arg)) == 0)
132 retval = fdres;
133 goto out;
134 }
135
136 /*
137 * Second, for speed, deal with the subset of cases that
138 * require getf() / releasef() but do not require copyin.
139 */
140 if ((fp = getf(fdes)) == NULL) {
141 error = EBADF;
142 goto out;
143 }
144 iarg = (int)arg;
145
146 switch (cmd) {
147 case F_DUPFD:
148 case F_DUPFD_CLOEXEC:
149 p = curproc;
150 if ((uint_t)iarg >= p->p_fno_ctl) {
151 if (iarg >= 0)
152 fd_too_big(p);
153 error = EINVAL;
154 goto done;
155 }
156 /*
157 * We need to increment the f_count reference counter
158 * before allocating a new file descriptor.
159 * Doing it other way round opens a window for race condition
160 * with closeandsetf() on the target file descriptor which can
161 * close the file still referenced by the original
162 * file descriptor.
163 */
164 mutex_enter(&fp->f_tlock);
165 fp->f_count++;
166 mutex_exit(&fp->f_tlock);
167 if ((retval = ufalloc_file(iarg, fp)) == -1) {
168 /*
169 * New file descriptor can't be allocated.
170 * Revert the reference count.
171 */
172 mutex_enter(&fp->f_tlock);
173 fp->f_count--;
174 mutex_exit(&fp->f_tlock);
175 error = EMFILE;
176 } else {
177 if (cmd == F_DUPFD_CLOEXEC) {
178 f_setfd(retval, FD_CLOEXEC);
179 }
180 }
181
182 if (error == 0 && fp->f_vnode != NULL) {
183 (void) VOP_IOCTL(fp->f_vnode, F_FORKED,
184 (intptr_t) p, FKIOCTL,
185 kcred, NULL, NULL);
186 }
187
188 goto done;
189
190 case F_DUP2FD_CLOEXEC:
191 if (fdes == iarg) {
192 error = EINVAL;
193 goto done;
194 }
195
196 /*FALLTHROUGH*/
197
198 case F_DUP2FD:
199 p = curproc;
200 if (fdes == iarg) {
201 retval = iarg;
202 } else if ((uint_t)iarg >= p->p_fno_ctl) {
203 if (iarg >= 0)
204 fd_too_big(p);
205 error = EBADF;
206 } else {
207 /*
208 * We can't hold our getf(fdes) across the call to
209 * closeandsetf() because it creates a window for
210 * deadlock: if one thread is doing dup2(a, b) while
211 * another is doing dup2(b, a), each one will block
212 * waiting for the other to call releasef(). The
213 * solution is to increment the file reference count
214 * (which we have to do anyway), then releasef(fdes),
215 * then closeandsetf(). Incrementing f_count ensures
216 * that fp won't disappear after we call releasef().
217 * When closeandsetf() fails, we try avoid calling
218 * closef() because of all the side effects.
219 */
220 mutex_enter(&fp->f_tlock);
221 fp->f_count++;
222 mutex_exit(&fp->f_tlock);
223 releasef(fdes);
224
225 /* assume we have forked successfully */
226
227 if (fp->f_vnode != NULL) {
228 (void) VOP_IOCTL(fp->f_vnode, F_FORKED,
229 (intptr_t) p, FKIOCTL,
230 kcred, NULL, NULL);
231 }
232
233 if ((error = closeandsetf(iarg, fp)) == 0) {
234 if (cmd == F_DUP2FD_CLOEXEC) {
235 f_setfd(iarg, FD_CLOEXEC);
236 }
237 retval = iarg;
238 } else {
239 mutex_enter(&fp->f_tlock);
240 if (fp->f_count > 1) {
241 fp->f_count--;
242 mutex_exit(&fp->f_tlock);
243 if (fp->f_vnode != NULL) {
244 VOP_IOCTL(fp->f_vnode, F_CLOSED,
245 (intptr_t) p, FKIOCTL,
246 kcred, NULL, NULL);
247 }
248
249 } else {
250 mutex_exit(&fp->f_tlock);
251 (void) closef(fp);
252 }
253 }
254 goto out;
255 }
256 goto done;
257
258 case F_SETFL:
259 vp = fp->f_vnode;
260 flag = fp->f_flag;
261 if ((iarg & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
262 iarg &= ~FNDELAY;
263 if ((error = VOP_SETFL(vp, flag, iarg, fp->f_cred, NULL)) ==
264 0) {
265 iarg &= FMASK;
266 mutex_enter(&fp->f_tlock);
267 fp->f_flag &= ~FMASK | (FREAD|FWRITE);
268 fp->f_flag |= (iarg - FOPEN) & ~(FREAD|FWRITE);
269 mutex_exit(&fp->f_tlock);
270 }
271 retval = 0;
272 goto done;
273 }
274
275 /*
276 * Finally, deal with the expensive cases.
277 */
278 retval = 0;
279 in_crit = 0;
280 maxoffset = MAXOFF_T;
281 datamodel = DATAMODEL_NATIVE;
282 #if defined(_SYSCALL32_IMPL)
283 if ((datamodel = get_udatamodel()) == DATAMODEL_ILP32)
284 maxoffset = MAXOFF32_T;
285 #endif
286
287 vp = fp->f_vnode;
288 flag = fp->f_flag;
289 offset = fp->f_offset;
290
291 switch (cmd) {
292 /*
293 * The file system and vnode layers understand and implement
294 * locking with flock64 structures. So here once we pass through
295 * the test for compatibility as defined by LFS API, (for F_SETLK,
296 * F_SETLKW, F_GETLK, F_GETLKW, F_FREESP) we transform
297 * the flock structure to a flock64 structure and send it to the
298 * lower layers. Similarly in case of GETLK the returned flock64
299 * structure is transformed to a flock structure if everything fits
300 * in nicely, otherwise we return EOVERFLOW.
301 */
302
303 case F_GETLK:
304 case F_O_GETLK:
305 case F_SETLK:
306 case F_SETLKW:
307 case F_SETLK_NBMAND:
308
309 /*
310 * Copy in input fields only.
311 */
312
313 if (cmd == F_O_GETLK) {
314 if (datamodel != DATAMODEL_ILP32) {
315 error = EINVAL;
316 break;
317 }
318
319 if (copyin((void *)arg, &obf, sizeof (obf))) {
320 error = EFAULT;
321 break;
322 }
323 bf.l_type = obf.l_type;
324 bf.l_whence = obf.l_whence;
325 bf.l_start = (off64_t)obf.l_start;
326 bf.l_len = (off64_t)obf.l_len;
327 bf.l_sysid = (int)obf.l_sysid;
328 bf.l_pid = obf.l_pid;
329 } else if (datamodel == DATAMODEL_NATIVE) {
330 if (copyin((void *)arg, &sbf, sizeof (sbf))) {
331 error = EFAULT;
332 break;
333 }
334 /*
335 * XXX In an LP64 kernel with an LP64 application
336 * there's no need to do a structure copy here
337 * struct flock == struct flock64. However,
338 * we did it this way to avoid more conditional
339 * compilation.
340 */
341 bf.l_type = sbf.l_type;
342 bf.l_whence = sbf.l_whence;
343 bf.l_start = (off64_t)sbf.l_start;
344 bf.l_len = (off64_t)sbf.l_len;
345 bf.l_sysid = sbf.l_sysid;
346 bf.l_pid = sbf.l_pid;
347 }
348 #if defined(_SYSCALL32_IMPL)
349 else {
350 struct flock32 sbf32;
351 if (copyin((void *)arg, &sbf32, sizeof (sbf32))) {
352 error = EFAULT;
353 break;
354 }
355 bf.l_type = sbf32.l_type;
356 bf.l_whence = sbf32.l_whence;
357 bf.l_start = (off64_t)sbf32.l_start;
358 bf.l_len = (off64_t)sbf32.l_len;
359 bf.l_sysid = sbf32.l_sysid;
360 bf.l_pid = sbf32.l_pid;
361 }
362 #endif /* _SYSCALL32_IMPL */
363
364 /*
365 * 64-bit support: check for overflow for 32-bit lock ops
366 */
367 if ((error = flock_check(vp, &bf, offset, maxoffset)) != 0)
368 break;
369
370 /*
371 * Not all of the filesystems understand F_O_GETLK, and
372 * there's no need for them to know. Map it to F_GETLK.
373 */
374 if ((error = VOP_FRLOCK(vp, (cmd == F_O_GETLK) ? F_GETLK : cmd,
375 &bf, flag, offset, NULL, fp->f_cred, NULL)) != 0)
376 break;
377
378 /*
379 * If command is GETLK and no lock is found, only
380 * the type field is changed.
381 */
382 if ((cmd == F_O_GETLK || cmd == F_GETLK) &&
383 bf.l_type == F_UNLCK) {
384 /* l_type always first entry, always a short */
385 if (copyout(&bf.l_type, &((struct flock *)arg)->l_type,
386 sizeof (bf.l_type)))
387 error = EFAULT;
388 break;
389 }
390
391 if (cmd == F_O_GETLK) {
392 /*
393 * Return an SVR3 flock structure to the user.
394 */
395 obf.l_type = (int16_t)bf.l_type;
396 obf.l_whence = (int16_t)bf.l_whence;
397 obf.l_start = (int32_t)bf.l_start;
398 obf.l_len = (int32_t)bf.l_len;
399 if (bf.l_sysid > SHRT_MAX || bf.l_pid > SHRT_MAX) {
400 /*
401 * One or both values for the above fields
402 * is too large to store in an SVR3 flock
403 * structure.
404 */
405 error = EOVERFLOW;
406 break;
407 }
408 obf.l_sysid = (int16_t)bf.l_sysid;
409 obf.l_pid = (int16_t)bf.l_pid;
410 if (copyout(&obf, (void *)arg, sizeof (obf)))
411 error = EFAULT;
412 } else if (cmd == F_GETLK) {
413 /*
414 * Copy out SVR4 flock.
415 */
416 int i;
417
418 if (bf.l_start > maxoffset || bf.l_len > maxoffset) {
419 error = EOVERFLOW;
420 break;
421 }
422
423 if (datamodel == DATAMODEL_NATIVE) {
424 for (i = 0; i < 4; i++)
425 sbf.l_pad[i] = 0;
426 /*
427 * XXX In an LP64 kernel with an LP64
428 * application there's no need to do a
429 * structure copy here as currently
430 * struct flock == struct flock64.
431 * We did it this way to avoid more
432 * conditional compilation.
433 */
434 sbf.l_type = bf.l_type;
435 sbf.l_whence = bf.l_whence;
436 sbf.l_start = (off_t)bf.l_start;
437 sbf.l_len = (off_t)bf.l_len;
438 sbf.l_sysid = bf.l_sysid;
439 sbf.l_pid = bf.l_pid;
440 if (copyout(&sbf, (void *)arg, sizeof (sbf)))
441 error = EFAULT;
442 }
443 #if defined(_SYSCALL32_IMPL)
444 else {
445 struct flock32 sbf32;
446 if (bf.l_start > MAXOFF32_T ||
447 bf.l_len > MAXOFF32_T) {
448 error = EOVERFLOW;
449 break;
450 }
451 for (i = 0; i < 4; i++)
452 sbf32.l_pad[i] = 0;
453 sbf32.l_type = (int16_t)bf.l_type;
454 sbf32.l_whence = (int16_t)bf.l_whence;
455 sbf32.l_start = (off32_t)bf.l_start;
456 sbf32.l_len = (off32_t)bf.l_len;
457 sbf32.l_sysid = (int32_t)bf.l_sysid;
458 sbf32.l_pid = (pid32_t)bf.l_pid;
459 if (copyout(&sbf32,
460 (void *)arg, sizeof (sbf32)))
461 error = EFAULT;
462 }
463 #endif
464 }
465 break;
466
467 case F_CHKFL:
468 /*
469 * This is for internal use only, to allow the vnode layer
470 * to validate a flags setting before applying it. User
471 * programs can't issue it.
472 */
473 error = EINVAL;
474 break;
475
476 case F_ALLOCSP:
477 case F_FREESP:
478 case F_ALLOCSP64:
479 case F_FREESP64:
480 /*
481 * Test for not-a-regular-file (and returning EINVAL)
482 * before testing for open-for-writing (and returning EBADF).
483 * This is relied upon by posix_fallocate() in libc.
484 */
485 if (vp->v_type != VREG) {
486 error = EINVAL;
487 break;
488 }
489
490 if ((flag & FWRITE) == 0) {
491 error = EBADF;
492 break;
493 }
494
495 if (datamodel != DATAMODEL_ILP32 &&
496 (cmd == F_ALLOCSP64 || cmd == F_FREESP64)) {
497 error = EINVAL;
498 break;
499 }
500
501 #if defined(_ILP32) || defined(_SYSCALL32_IMPL)
502 if (datamodel == DATAMODEL_ILP32 &&
503 (cmd == F_ALLOCSP || cmd == F_FREESP)) {
504 struct flock32 sbf32;
505 /*
506 * For compatibility we overlay an SVR3 flock on an SVR4
507 * flock. This works because the input field offsets
508 * in "struct flock" were preserved.
509 */
510 if (copyin((void *)arg, &sbf32, sizeof (sbf32))) {
511 error = EFAULT;
512 break;
513 } else {
514 bf.l_type = sbf32.l_type;
515 bf.l_whence = sbf32.l_whence;
516 bf.l_start = (off64_t)sbf32.l_start;
517 bf.l_len = (off64_t)sbf32.l_len;
518 bf.l_sysid = sbf32.l_sysid;
519 bf.l_pid = sbf32.l_pid;
520 }
521 }
522 #endif /* _ILP32 || _SYSCALL32_IMPL */
523
524 #if defined(_LP64)
525 if (datamodel == DATAMODEL_LP64 &&
526 (cmd == F_ALLOCSP || cmd == F_FREESP)) {
527 if (copyin((void *)arg, &bf, sizeof (bf))) {
528 error = EFAULT;
529 break;
530 }
531 }
532 #endif /* defined(_LP64) */
533
534 #if !defined(_LP64) || defined(_SYSCALL32_IMPL)
535 if (datamodel == DATAMODEL_ILP32 &&
536 (cmd == F_ALLOCSP64 || cmd == F_FREESP64)) {
537 if (copyin((void *)arg, &bf64_32, sizeof (bf64_32))) {
538 error = EFAULT;
539 break;
540 } else {
541 /*
542 * Note that the size of flock64 is different in
543 * the ILP32 and LP64 models, due to the l_pad
544 * field. We do not want to assume that the
545 * flock64 structure is laid out the same in
546 * ILP32 and LP64 environments, so we will
547 * copy in the ILP32 version of flock64
548 * explicitly and copy it to the native
549 * flock64 structure.
550 */
551 bf.l_type = (short)bf64_32.l_type;
552 bf.l_whence = (short)bf64_32.l_whence;
553 bf.l_start = bf64_32.l_start;
554 bf.l_len = bf64_32.l_len;
555 bf.l_sysid = (int)bf64_32.l_sysid;
556 bf.l_pid = (pid_t)bf64_32.l_pid;
557 }
558 }
559 #endif /* !defined(_LP64) || defined(_SYSCALL32_IMPL) */
560
561 if (cmd == F_ALLOCSP || cmd == F_FREESP)
562 error = flock_check(vp, &bf, offset, maxoffset);
563 else if (cmd == F_ALLOCSP64 || cmd == F_FREESP64)
564 error = flock_check(vp, &bf, offset, MAXOFFSET_T);
565 if (error)
566 break;
567
568 if (vp->v_type == VREG && bf.l_len == 0 &&
569 bf.l_start > OFFSET_MAX(fp)) {
570 error = EFBIG;
571 break;
572 }
573
574 /*
575 * Make sure that there are no conflicting non-blocking
576 * mandatory locks in the region being manipulated. If
577 * there are such locks then return EACCES.
578 */
579 if ((error = flock_get_start(vp, &bf, offset, &start)) != 0)
580 break;
581
582 if (nbl_need_check(vp)) {
583 u_offset_t begin;
584 ssize_t length;
585
586 nbl_start_crit(vp, RW_READER);
587 in_crit = 1;
588 vattr.va_mask = AT_SIZE;
589 if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
590 != 0)
591 break;
592 begin = start > vattr.va_size ? vattr.va_size : start;
593 length = vattr.va_size > start ? vattr.va_size - start :
594 start - vattr.va_size;
595 if (nbl_conflict(vp, NBL_WRITE, begin, length, 0,
596 NULL)) {
597 error = EACCES;
598 break;
599 }
600 }
601
602 if (cmd == F_ALLOCSP64)
603 cmd = F_ALLOCSP;
604 else if (cmd == F_FREESP64)
605 cmd = F_FREESP;
606
607 error = VOP_SPACE(vp, cmd, &bf, flag, offset, fp->f_cred, NULL);
608
609 break;
610
611 #if !defined(_LP64) || defined(_SYSCALL32_IMPL)
612 case F_GETLK64:
613 case F_SETLK64:
614 case F_SETLKW64:
615 case F_SETLK64_NBMAND:
616 /*
617 * Large Files: Here we set cmd as *LK and send it to
618 * lower layers. *LK64 is only for the user land.
619 * Most of the comments described above for F_SETLK
620 * applies here too.
621 * Large File support is only needed for ILP32 apps!
622 */
623 if (datamodel != DATAMODEL_ILP32) {
624 error = EINVAL;
625 break;
626 }
627
628 if (cmd == F_GETLK64)
629 cmd = F_GETLK;
630 else if (cmd == F_SETLK64)
631 cmd = F_SETLK;
632 else if (cmd == F_SETLKW64)
633 cmd = F_SETLKW;
634 else if (cmd == F_SETLK64_NBMAND)
635 cmd = F_SETLK_NBMAND;
636
637 /*
638 * Note that the size of flock64 is different in the ILP32
639 * and LP64 models, due to the sucking l_pad field.
640 * We do not want to assume that the flock64 structure is
641 * laid out in the same in ILP32 and LP64 environments, so
642 * we will copy in the ILP32 version of flock64 explicitly
643 * and copy it to the native flock64 structure.
644 */
645
646 if (copyin((void *)arg, &bf64_32, sizeof (bf64_32))) {
647 error = EFAULT;
648 break;
649 }
650
651 bf.l_type = (short)bf64_32.l_type;
652 bf.l_whence = (short)bf64_32.l_whence;
653 bf.l_start = bf64_32.l_start;
654 bf.l_len = bf64_32.l_len;
655 bf.l_sysid = (int)bf64_32.l_sysid;
656 bf.l_pid = (pid_t)bf64_32.l_pid;
657
658 if ((error = flock_check(vp, &bf, offset, MAXOFFSET_T)) != 0)
659 break;
660
661 if ((error = VOP_FRLOCK(vp, cmd, &bf, flag, offset,
662 NULL, fp->f_cred, NULL)) != 0)
663 break;
664
665 if ((cmd == F_GETLK) && bf.l_type == F_UNLCK) {
666 if (copyout(&bf.l_type, &((struct flock *)arg)->l_type,
667 sizeof (bf.l_type)))
668 error = EFAULT;
669 break;
670 }
671
672 if (cmd == F_GETLK) {
673 int i;
674
675 /*
676 * We do not want to assume that the flock64 structure
677 * is laid out in the same in ILP32 and LP64
678 * environments, so we will copy out the ILP32 version
679 * of flock64 explicitly after copying the native
680 * flock64 structure to it.
681 */
682 for (i = 0; i < 4; i++)
683 bf64_32.l_pad[i] = 0;
684 bf64_32.l_type = (int16_t)bf.l_type;
685 bf64_32.l_whence = (int16_t)bf.l_whence;
686 bf64_32.l_start = bf.l_start;
687 bf64_32.l_len = bf.l_len;
688 bf64_32.l_sysid = (int32_t)bf.l_sysid;
689 bf64_32.l_pid = (pid32_t)bf.l_pid;
690 if (copyout(&bf64_32, (void *)arg, sizeof (bf64_32)))
691 error = EFAULT;
692 }
693 break;
694 #endif /* !defined(_LP64) || defined(_SYSCALL32_IMPL) */
695
696 case F_SHARE:
697 case F_SHARE_NBMAND:
698 case F_UNSHARE:
699
700 /*
701 * Copy in input fields only.
702 */
703 if (copyin((void *)arg, &fsh, sizeof (fsh))) {
704 error = EFAULT;
705 break;
706 }
707
708 /*
709 * Local share reservations always have this simple form
710 */
711 shr.s_access = fsh.f_access;
712 shr.s_deny = fsh.f_deny;
713 shr.s_sysid = 0;
714 shr.s_pid = ttoproc(curthread)->p_pid;
715 shr_own.sl_pid = shr.s_pid;
716 shr_own.sl_id = fsh.f_id;
717 shr.s_own_len = sizeof (shr_own);
718 shr.s_owner = (caddr_t)&shr_own;
719 error = VOP_SHRLOCK(vp, cmd, &shr, flag, fp->f_cred, NULL);
720 break;
721
722 default:
723 error = EINVAL;
724 break;
725 }
726
727 if (in_crit)
728 nbl_end_crit(vp);
729
730 done:
731 releasef(fdes);
732 out:
733 if (error)
734 return (set_errno(error));
735 return (retval);
736 }
737
738 int
739 flock_check(vnode_t *vp, flock64_t *flp, offset_t offset, offset_t max)
740 {
741 struct vattr vattr;
742 int error;
743 u_offset_t start, end;
744
745 /*
746 * Determine the starting point of the request
747 */
748 switch (flp->l_whence) {
749 case 0: /* SEEK_SET */
750 start = (u_offset_t)flp->l_start;
751 if (start > max)
752 return (EINVAL);
753 break;
754 case 1: /* SEEK_CUR */
755 if (flp->l_start > (max - offset))
756 return (EOVERFLOW);
757 start = (u_offset_t)(flp->l_start + offset);
758 if (start > max)
759 return (EINVAL);
760 break;
761 case 2: /* SEEK_END */
762 vattr.va_mask = AT_SIZE;
763 if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
764 return (error);
765 if (flp->l_start > (max - (offset_t)vattr.va_size))
766 return (EOVERFLOW);
767 start = (u_offset_t)(flp->l_start + (offset_t)vattr.va_size);
768 if (start > max)
769 return (EINVAL);
770 break;
771 default:
772 return (EINVAL);
773 }
774
775 /*
776 * Determine the range covered by the request.
777 */
778 if (flp->l_len == 0)
779 end = MAXEND;
780 else if ((offset_t)flp->l_len > 0) {
781 if (flp->l_len > (max - start + 1))
782 return (EOVERFLOW);
783 end = (u_offset_t)(start + (flp->l_len - 1));
784 ASSERT(end <= max);
785 } else {
786 /*
787 * Negative length; why do we even allow this ?
788 * Because this allows easy specification of
789 * the last n bytes of the file.
790 */
791 end = start;
792 start += (u_offset_t)flp->l_len;
793 (start)++;
794 if (start > max)
795 return (EINVAL);
796 ASSERT(end <= max);
797 }
798 ASSERT(start <= max);
799 if (flp->l_type == F_UNLCK && flp->l_len > 0 &&
800 end == (offset_t)max) {
801 flp->l_len = 0;
802 }
803 if (start > end)
804 return (EINVAL);
805 return (0);
806 }
807
808 static int
809 flock_get_start(vnode_t *vp, flock64_t *flp, offset_t offset, u_offset_t *start)
810 {
811 struct vattr vattr;
812 int error;
813
814 /*
815 * Determine the starting point of the request. Assume that it is
816 * a valid starting point.
817 */
818 switch (flp->l_whence) {
819 case 0: /* SEEK_SET */
820 *start = (u_offset_t)flp->l_start;
821 break;
822 case 1: /* SEEK_CUR */
823 *start = (u_offset_t)(flp->l_start + offset);
824 break;
825 case 2: /* SEEK_END */
826 vattr.va_mask = AT_SIZE;
827 if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL))
828 return (error);
829 *start = (u_offset_t)(flp->l_start + (offset_t)vattr.va_size);
830 break;
831 default:
832 return (EINVAL);
833 }
834
835 return (0);
836 }
837
838 /*
839 * Take rctl action when the requested file descriptor is too big.
840 */
841 static void
842 fd_too_big(proc_t *p)
843 {
844 mutex_enter(&p->p_lock);
845 (void) rctl_action(rctlproc_legacy[RLIMIT_NOFILE],
846 p->p_rctls, p, RCA_SAFE);
847 mutex_exit(&p->p_lock);
848 }