162 * close the file still referenced by the original
163 * file descriptor.
164 */
165 mutex_enter(&fp->f_tlock);
166 fp->f_count++;
167 mutex_exit(&fp->f_tlock);
168 if ((retval = ufalloc_file(iarg, fp)) == -1) {
169 /*
170 * New file descriptor can't be allocated.
171 * Revert the reference count.
172 */
173 mutex_enter(&fp->f_tlock);
174 fp->f_count--;
175 mutex_exit(&fp->f_tlock);
176 error = EMFILE;
177 } else {
178 if (cmd == F_DUPFD_CLOEXEC) {
179 f_setfd(retval, FD_CLOEXEC);
180 }
181 }
182 goto done;
183
184 case F_DUP2FD_CLOEXEC:
185 if (fdes == iarg) {
186 error = EINVAL;
187 goto done;
188 }
189
190 /*FALLTHROUGH*/
191
192 case F_DUP2FD:
193 p = curproc;
194 if (fdes == iarg) {
195 retval = iarg;
196 } else if ((uint_t)iarg >= p->p_fno_ctl) {
197 if (iarg >= 0)
198 fd_too_big(p);
199 error = EBADF;
200 } else {
201 /*
202 * We can't hold our getf(fdes) across the call to
203 * closeandsetf() because it creates a window for
204 * deadlock: if one thread is doing dup2(a, b) while
205 * another is doing dup2(b, a), each one will block
206 * waiting for the other to call releasef(). The
207 * solution is to increment the file reference count
208 * (which we have to do anyway), then releasef(fdes),
209 * then closeandsetf(). Incrementing f_count ensures
210 * that fp won't disappear after we call releasef().
211 * When closeandsetf() fails, we try avoid calling
212 * closef() because of all the side effects.
213 */
214 mutex_enter(&fp->f_tlock);
215 fp->f_count++;
216 mutex_exit(&fp->f_tlock);
217 releasef(fdes);
218 if ((error = closeandsetf(iarg, fp)) == 0) {
219 if (cmd == F_DUP2FD_CLOEXEC) {
220 f_setfd(iarg, FD_CLOEXEC);
221 }
222 retval = iarg;
223 } else {
224 mutex_enter(&fp->f_tlock);
225 if (fp->f_count > 1) {
226 fp->f_count--;
227 mutex_exit(&fp->f_tlock);
228 } else {
229 mutex_exit(&fp->f_tlock);
230 (void) closef(fp);
231 }
232 }
233 goto out;
234 }
235 goto done;
236
237 case F_SETFL:
238 vp = fp->f_vnode;
239 flag = fp->f_flag;
240 if ((iarg & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
241 iarg &= ~FNDELAY;
242 if ((error = VOP_SETFL(vp, flag, iarg, fp->f_cred, NULL)) ==
243 0) {
244 iarg &= FMASK;
245 mutex_enter(&fp->f_tlock);
246 fp->f_flag &= ~FMASK | (FREAD|FWRITE);
247 fp->f_flag |= (iarg - FOPEN) & ~(FREAD|FWRITE);
|
162 * close the file still referenced by the original
163 * file descriptor.
164 */
165 mutex_enter(&fp->f_tlock);
166 fp->f_count++;
167 mutex_exit(&fp->f_tlock);
168 if ((retval = ufalloc_file(iarg, fp)) == -1) {
169 /*
170 * New file descriptor can't be allocated.
171 * Revert the reference count.
172 */
173 mutex_enter(&fp->f_tlock);
174 fp->f_count--;
175 mutex_exit(&fp->f_tlock);
176 error = EMFILE;
177 } else {
178 if (cmd == F_DUPFD_CLOEXEC) {
179 f_setfd(retval, FD_CLOEXEC);
180 }
181 }
182
183 if (error == 0 && fp->f_vnode != NULL) {
184 (void) VOP_IOCTL(fp->f_vnode, F_ASSOCI_PID,
185 (intptr_t)p->p_pidp->pid_id, FKIOCTL, kcred,
186 NULL, NULL);
187 }
188
189 goto done;
190
191 case F_DUP2FD_CLOEXEC:
192 if (fdes == iarg) {
193 error = EINVAL;
194 goto done;
195 }
196
197 /*FALLTHROUGH*/
198
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().
218 * When closeandsetf() fails, we try avoid calling
219 * closef() because of all the side effects.
220 */
221 mutex_enter(&fp->f_tlock);
222 fp->f_count++;
223 mutex_exit(&fp->f_tlock);
224 releasef(fdes);
225
226 /* assume we have forked successfully */
227 if (fp->f_vnode != NULL) {
228 (void) VOP_IOCTL(fp->f_vnode, F_ASSOCI_PID,
229 (intptr_t)p->p_pidp->pid_id, 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 (void) VOP_IOCTL(fp->f_vnode,
245 F_DASSOC_PID,
246 (intptr_t)p->p_pidp->pid_id,
247 FKIOCTL, kcred, NULL, NULL);
248 }
249
250 } else {
251 mutex_exit(&fp->f_tlock);
252 (void) closef(fp);
253 }
254 }
255 goto out;
256 }
257 goto done;
258
259 case F_SETFL:
260 vp = fp->f_vnode;
261 flag = fp->f_flag;
262 if ((iarg & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
263 iarg &= ~FNDELAY;
264 if ((error = VOP_SETFL(vp, flag, iarg, fp->f_cred, NULL)) ==
265 0) {
266 iarg &= FMASK;
267 mutex_enter(&fp->f_tlock);
268 fp->f_flag &= ~FMASK | (FREAD|FWRITE);
269 fp->f_flag |= (iarg - FOPEN) & ~(FREAD|FWRITE);
|