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