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 /*
227 * Assume we succeed to duplicate the file descriptor
228 * and associate the pid to the vnode.
229 */
230 if (fp->f_vnode != NULL) {
231 (void) VOP_IOCTL(fp->f_vnode, F_ASSOCI_PID,
232 (intptr_t)p->p_pidp->pid_id, FKIOCTL,
233 kcred, NULL, NULL);
234 }
235
236 if ((error = closeandsetf(iarg, fp)) == 0) {
237 if (cmd == F_DUP2FD_CLOEXEC) {
238 f_setfd(iarg, FD_CLOEXEC);
239 }
240 retval = iarg;
241 } else {
242 mutex_enter(&fp->f_tlock);
243 if (fp->f_count > 1) {
244 fp->f_count--;
245 mutex_exit(&fp->f_tlock);
246 /*
247 * Failed to duplicate fdes,
248 * disassociate the pid from the vnode.
249 */
250 if (fp->f_vnode != NULL) {
251 (void) VOP_IOCTL(fp->f_vnode,
252 F_DASSOC_PID,
253 (intptr_t)p->p_pidp->pid_id,
254 FKIOCTL, kcred, NULL, NULL);
255 }
256
257 } else {
258 mutex_exit(&fp->f_tlock);
259 (void) closef(fp);
260 }
261 }
262 goto out;
263 }
264 goto done;
265
266 case F_SETFL:
267 vp = fp->f_vnode;
268 flag = fp->f_flag;
269 if ((iarg & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY))
270 iarg &= ~FNDELAY;
271 if ((error = VOP_SETFL(vp, flag, iarg, fp->f_cred, NULL)) ==
272 0) {
273 iarg &= FMASK;
274 mutex_enter(&fp->f_tlock);
275 fp->f_flag &= ~FMASK | (FREAD|FWRITE);
276 fp->f_flag |= (iarg - FOPEN) & ~(FREAD|FWRITE);
|