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 goto done;
182
183 case F_DUP2FD_CLOEXEC:
184 if (fdes == iarg) {
185 error = EINVAL;
186 goto done;
187 }
188
189 /*FALLTHROUGH*/
190
191 case F_DUP2FD:
192 p = curproc;
193 if (fdes == iarg) {
194 retval = iarg;
195 } else if ((uint_t)iarg >= p->p_fno_ctl) {
196 if (iarg >= 0)
197 fd_too_big(p);
198 error = EBADF;
199 } else {
200 /*
201 * We can't hold our getf(fdes) across the call to
202 * closeandsetf() because it creates a window for
203 * deadlock: if one thread is doing dup2(a, b) while
204 * another is doing dup2(b, a), each one will block
205 * waiting for the other to call releasef(). The
206 * solution is to increment the file reference count
207 * (which we have to do anyway), then releasef(fdes),
208 * then closeandsetf(). Incrementing f_count ensures
209 * that fp won't disappear after we call releasef().
210 * When closeandsetf() fails, we try avoid calling
211 * closef() because of all the side effects.
212 */
213 mutex_enter(&fp->f_tlock);
214 fp->f_count++;
215 mutex_exit(&fp->f_tlock);
216 releasef(fdes);
217 if ((error = closeandsetf(iarg, fp)) == 0) {
218 if (cmd == F_DUP2FD_CLOEXEC) {
219 f_setfd(iarg, FD_CLOEXEC);
220 }
221 retval = iarg;
222 } else {
223 mutex_enter(&fp->f_tlock);
224 if (fp->f_count > 1) {
225 fp->f_count--;
226 mutex_exit(&fp->f_tlock);
227 } else {
228 mutex_exit(&fp->f_tlock);
229 (void) closef(fp);
230 }
231 }
232 goto out;
233 }
234 goto done;
235
236 case F_SETFL:
237 vp = fp->f_vnode;
238 flag = fp->f_flag;
239 if ((iarg & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
240 iarg &= ~FNDELAY;
241 if ((error = VOP_SETFL(vp, flag, iarg, fp->f_cred, NULL)) ==
242 0) {
243 iarg &= FMASK;
244 mutex_enter(&fp->f_tlock);
245 fp->f_flag &= ~FMASK | (FREAD|FWRITE);
246 fp->f_flag |= (iarg - FOPEN) & ~(FREAD|FWRITE);
|
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);
|