xref: /minix3/minix/servers/vfs/filedes.c (revision 71cd1dd4b91859128b87967bab32f4cf48d475b9)
1433d6423SLionel Sambuc /* This file contains the procedures that manipulate file descriptors.
2433d6423SLionel Sambuc  *
3433d6423SLionel Sambuc  * The entry points into this file are
4433d6423SLionel Sambuc  *   get_fd:	    look for free file descriptor and free filp slots
5433d6423SLionel Sambuc  *   get_filp:	    look up the filp entry for a given file descriptor
6433d6423SLionel Sambuc  *   find_filp:	    find a filp slot that points to a given vnode
7433d6423SLionel Sambuc  *   inval_filp:    invalidate a filp and associated fd's, only let close()
8433d6423SLionel Sambuc  *                  happen on it
9433d6423SLionel Sambuc  *   do_copyfd:     copies a file descriptor from or to another endpoint
10433d6423SLionel Sambuc  */
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc #include <sys/select.h>
13433d6423SLionel Sambuc #include <minix/callnr.h>
14433d6423SLionel Sambuc #include <minix/u64.h>
15433d6423SLionel Sambuc #include <assert.h>
16433d6423SLionel Sambuc #include <sys/stat.h>
17433d6423SLionel Sambuc #include "fs.h"
18433d6423SLionel Sambuc #include "file.h"
19433d6423SLionel Sambuc #include "vnode.h"
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc #if LOCK_DEBUG
23433d6423SLionel Sambuc /*===========================================================================*
24433d6423SLionel Sambuc  *				check_filp_locks			     *
25433d6423SLionel Sambuc  *===========================================================================*/
26433d6423SLionel Sambuc void check_filp_locks_by_me(void)
27433d6423SLionel Sambuc {
28433d6423SLionel Sambuc /* Check whether this thread still has filp locks held */
29433d6423SLionel Sambuc   struct filp *f;
30433d6423SLionel Sambuc   int r;
31433d6423SLionel Sambuc 
32433d6423SLionel Sambuc   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
33433d6423SLionel Sambuc 	r = mutex_trylock(&f->filp_lock);
34433d6423SLionel Sambuc 	if (r == -EDEADLK)
35433d6423SLionel Sambuc 		panic("Thread %d still holds filp lock on filp %p call_nr=%d\n",
36433d6423SLionel Sambuc 		      mthread_self(), f, job_call_nr);
37433d6423SLionel Sambuc 	else if (r == 0) {
38433d6423SLionel Sambuc 		/* We just obtained the lock, release it */
39433d6423SLionel Sambuc 		mutex_unlock(&f->filp_lock);
40433d6423SLionel Sambuc 	}
41433d6423SLionel Sambuc   }
42433d6423SLionel Sambuc }
43433d6423SLionel Sambuc #endif
44433d6423SLionel Sambuc 
45433d6423SLionel Sambuc /*===========================================================================*
46433d6423SLionel Sambuc  *				check_filp_locks			     *
47433d6423SLionel Sambuc  *===========================================================================*/
48433d6423SLionel Sambuc void check_filp_locks(void)
49433d6423SLionel Sambuc {
50433d6423SLionel Sambuc   struct filp *f;
51433d6423SLionel Sambuc   int r, count = 0;
52433d6423SLionel Sambuc 
53433d6423SLionel Sambuc   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
54433d6423SLionel Sambuc 	r = mutex_trylock(&f->filp_lock);
55433d6423SLionel Sambuc 	if (r == -EBUSY) {
56433d6423SLionel Sambuc 		/* Mutex is still locked */
57433d6423SLionel Sambuc 		count++;
58433d6423SLionel Sambuc 	} else if (r == 0) {
59433d6423SLionel Sambuc 		/* We just obtained a lock, don't want it */
60433d6423SLionel Sambuc 		mutex_unlock(&f->filp_lock);
61433d6423SLionel Sambuc 	} else
62433d6423SLionel Sambuc 		panic("filp_lock weird state");
63433d6423SLionel Sambuc   }
64433d6423SLionel Sambuc   if (count) panic("locked filps");
65433d6423SLionel Sambuc #if 0
66433d6423SLionel Sambuc   else printf("check_filp_locks OK\n");
67433d6423SLionel Sambuc #endif
68433d6423SLionel Sambuc }
69433d6423SLionel Sambuc 
70433d6423SLionel Sambuc /*===========================================================================*
71433d6423SLionel Sambuc  *				init_filps				     *
72433d6423SLionel Sambuc  *===========================================================================*/
73433d6423SLionel Sambuc void init_filps(void)
74433d6423SLionel Sambuc {
75433d6423SLionel Sambuc /* Initialize filps */
76433d6423SLionel Sambuc   struct filp *f;
77433d6423SLionel Sambuc 
78433d6423SLionel Sambuc   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
79433d6423SLionel Sambuc 	if (mutex_init(&f->filp_lock, NULL) != 0)
80433d6423SLionel Sambuc 		panic("Failed to initialize filp mutex");
81433d6423SLionel Sambuc   }
82433d6423SLionel Sambuc 
83433d6423SLionel Sambuc }
84433d6423SLionel Sambuc 
85433d6423SLionel Sambuc /*===========================================================================*
86433d6423SLionel Sambuc  *				get_fd					     *
87433d6423SLionel Sambuc  *===========================================================================*/
88433d6423SLionel Sambuc int get_fd(struct fproc *rfp, int start, mode_t bits, int *k, struct filp **fpt)
89433d6423SLionel Sambuc {
90433d6423SLionel Sambuc /* Look for a free file descriptor and a free filp slot.  Fill in the mode word
91433d6423SLionel Sambuc  * in the latter, but don't claim either one yet, since the open() or creat()
92433d6423SLionel Sambuc  * may yet fail.
93433d6423SLionel Sambuc  */
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc   register struct filp *f;
96433d6423SLionel Sambuc   register int i;
97433d6423SLionel Sambuc 
98433d6423SLionel Sambuc   /* Search the fproc fp_filp table for a free file descriptor. */
99433d6423SLionel Sambuc   for (i = start; i < OPEN_MAX; i++) {
100433d6423SLionel Sambuc 	if (rfp->fp_filp[i] == NULL) {
101433d6423SLionel Sambuc 		/* A file descriptor has been located. */
102433d6423SLionel Sambuc 		*k = i;
103433d6423SLionel Sambuc 		break;
104433d6423SLionel Sambuc 	}
105433d6423SLionel Sambuc   }
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc   /* Check to see if a file descriptor has been found. */
108433d6423SLionel Sambuc   if (i >= OPEN_MAX) return(EMFILE);
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc   /* If we don't care about a filp, return now */
111433d6423SLionel Sambuc   if (fpt == NULL) return(OK);
112433d6423SLionel Sambuc 
113433d6423SLionel Sambuc   /* Now that a file descriptor has been found, look for a free filp slot. */
114433d6423SLionel Sambuc   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
115433d6423SLionel Sambuc 	assert(f->filp_count >= 0);
116433d6423SLionel Sambuc 	if (f->filp_count == 0 && mutex_trylock(&f->filp_lock) == 0) {
117433d6423SLionel Sambuc 		f->filp_mode = bits;
118433d6423SLionel Sambuc 		f->filp_pos = 0;
119433d6423SLionel Sambuc 		f->filp_selectors = 0;
120433d6423SLionel Sambuc 		f->filp_select_ops = 0;
121433d6423SLionel Sambuc 		f->filp_pipe_select_ops = 0;
12227d0ecdbSDavid van Moolenbroek 		f->filp_char_select_dev = NO_DEV;
123433d6423SLionel Sambuc 		f->filp_flags = 0;
124433d6423SLionel Sambuc 		f->filp_select_flags = 0;
125433d6423SLionel Sambuc 		f->filp_softlock = NULL;
126433d6423SLionel Sambuc 		f->filp_ioctl_fp = NULL;
127433d6423SLionel Sambuc 		*fpt = f;
128433d6423SLionel Sambuc 		return(OK);
129433d6423SLionel Sambuc 	}
130433d6423SLionel Sambuc   }
131433d6423SLionel Sambuc 
132433d6423SLionel Sambuc   /* If control passes here, the filp table must be full.  Report that back. */
133433d6423SLionel Sambuc   return(ENFILE);
134433d6423SLionel Sambuc }
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc 
137433d6423SLionel Sambuc /*===========================================================================*
138433d6423SLionel Sambuc  *				get_filp				     *
139433d6423SLionel Sambuc  *===========================================================================*/
140433d6423SLionel Sambuc struct filp *get_filp(fild, locktype)
141433d6423SLionel Sambuc int fild;			/* file descriptor */
142433d6423SLionel Sambuc tll_access_t locktype;
143433d6423SLionel Sambuc {
144433d6423SLionel Sambuc /* See if 'fild' refers to a valid file descr.  If so, return its filp ptr. */
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc   return get_filp2(fp, fild, locktype);
147433d6423SLionel Sambuc }
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc 
150433d6423SLionel Sambuc /*===========================================================================*
151433d6423SLionel Sambuc  *				get_filp2				     *
152433d6423SLionel Sambuc  *===========================================================================*/
153433d6423SLionel Sambuc struct filp *get_filp2(rfp, fild, locktype)
154433d6423SLionel Sambuc register struct fproc *rfp;
155433d6423SLionel Sambuc int fild;			/* file descriptor */
156433d6423SLionel Sambuc tll_access_t locktype;
157433d6423SLionel Sambuc {
158433d6423SLionel Sambuc /* See if 'fild' refers to a valid file descr.  If so, return its filp ptr. */
159433d6423SLionel Sambuc   struct filp *filp;
160433d6423SLionel Sambuc 
161433d6423SLionel Sambuc   filp = NULL;
162433d6423SLionel Sambuc   if (fild < 0 || fild >= OPEN_MAX)
163433d6423SLionel Sambuc 	err_code = EBADF;
164433d6423SLionel Sambuc   else if (locktype != VNODE_OPCL && rfp->fp_filp[fild] != NULL &&
165433d6423SLionel Sambuc 		rfp->fp_filp[fild]->filp_mode == FILP_CLOSED)
166433d6423SLionel Sambuc 	err_code = EIO; /* disallow all use except close(2) */
167433d6423SLionel Sambuc   else if ((filp = rfp->fp_filp[fild]) == NULL)
168433d6423SLionel Sambuc 	err_code = EBADF;
169433d6423SLionel Sambuc   else if (locktype != VNODE_NONE)	/* Only lock the filp if requested */
170433d6423SLionel Sambuc 	lock_filp(filp, locktype);	/* All is fine */
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc   return(filp);	/* may also be NULL */
173433d6423SLionel Sambuc }
174433d6423SLionel Sambuc 
175433d6423SLionel Sambuc 
176433d6423SLionel Sambuc /*===========================================================================*
177433d6423SLionel Sambuc  *				find_filp				     *
178433d6423SLionel Sambuc  *===========================================================================*/
179433d6423SLionel Sambuc struct filp *find_filp(struct vnode *vp, mode_t bits)
180433d6423SLionel Sambuc {
181433d6423SLionel Sambuc /* Find a filp slot that refers to the vnode 'vp' in a way as described
182433d6423SLionel Sambuc  * by the mode bit 'bits'. Used for determining whether somebody is still
183433d6423SLionel Sambuc  * interested in either end of a pipe.  Also used when opening a FIFO to
184433d6423SLionel Sambuc  * find partners to share a filp field with (to shared the file position).
185433d6423SLionel Sambuc  * Like 'get_fd' it performs its job by linear search through the filp table.
186433d6423SLionel Sambuc  */
187433d6423SLionel Sambuc 
188433d6423SLionel Sambuc   struct filp *f;
189433d6423SLionel Sambuc 
190433d6423SLionel Sambuc   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
191433d6423SLionel Sambuc 	if (f->filp_count != 0 && f->filp_vno == vp && (f->filp_mode & bits)) {
192433d6423SLionel Sambuc 		return(f);
193433d6423SLionel Sambuc 	}
194433d6423SLionel Sambuc   }
195433d6423SLionel Sambuc 
196433d6423SLionel Sambuc   /* If control passes here, the filp wasn't there.  Report that back. */
197433d6423SLionel Sambuc   return(NULL);
198433d6423SLionel Sambuc }
199433d6423SLionel Sambuc 
200433d6423SLionel Sambuc /*===========================================================================*
201433d6423SLionel Sambuc  *				invalidate_filp				     *
202433d6423SLionel Sambuc  *===========================================================================*/
203433d6423SLionel Sambuc void invalidate_filp(struct filp *rfilp)
204433d6423SLionel Sambuc {
205433d6423SLionel Sambuc /* Invalidate filp. */
206433d6423SLionel Sambuc 
207433d6423SLionel Sambuc   rfilp->filp_mode = FILP_CLOSED;
208433d6423SLionel Sambuc }
209433d6423SLionel Sambuc 
210433d6423SLionel Sambuc /*===========================================================================*
211433d6423SLionel Sambuc  *			invalidate_filp_by_char_major			     *
212433d6423SLionel Sambuc  *===========================================================================*/
2133b468884SDavid van Moolenbroek void invalidate_filp_by_char_major(devmajor_t major)
214433d6423SLionel Sambuc {
215433d6423SLionel Sambuc   struct filp *f;
216433d6423SLionel Sambuc 
217433d6423SLionel Sambuc   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
218433d6423SLionel Sambuc 	if (f->filp_count != 0 && f->filp_vno != NULL) {
219433d6423SLionel Sambuc 		if (major(f->filp_vno->v_sdev) == major &&
220433d6423SLionel Sambuc 		    S_ISCHR(f->filp_vno->v_mode)) {
221433d6423SLionel Sambuc 			invalidate_filp(f);
222433d6423SLionel Sambuc 		}
223433d6423SLionel Sambuc 	}
224433d6423SLionel Sambuc   }
225433d6423SLionel Sambuc }
226433d6423SLionel Sambuc 
227433d6423SLionel Sambuc /*===========================================================================*
228433d6423SLionel Sambuc  *			invalidate_filp_by_endpt			     *
229433d6423SLionel Sambuc  *===========================================================================*/
230433d6423SLionel Sambuc void invalidate_filp_by_endpt(endpoint_t proc_e)
231433d6423SLionel Sambuc {
232433d6423SLionel Sambuc   struct filp *f;
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
235433d6423SLionel Sambuc 	if (f->filp_count != 0 && f->filp_vno != NULL) {
236433d6423SLionel Sambuc 		if (f->filp_vno->v_fs_e == proc_e)
237433d6423SLionel Sambuc 			invalidate_filp(f);
238433d6423SLionel Sambuc 	}
239433d6423SLionel Sambuc   }
240433d6423SLionel Sambuc }
241433d6423SLionel Sambuc 
242433d6423SLionel Sambuc /*===========================================================================*
243433d6423SLionel Sambuc  *				lock_filp				     *
244433d6423SLionel Sambuc  *===========================================================================*/
245433d6423SLionel Sambuc void lock_filp(filp, locktype)
246433d6423SLionel Sambuc struct filp *filp;
247433d6423SLionel Sambuc tll_access_t locktype;
248433d6423SLionel Sambuc {
249433d6423SLionel Sambuc   struct worker_thread *org_self;
250433d6423SLionel Sambuc   struct vnode *vp;
251433d6423SLionel Sambuc 
252433d6423SLionel Sambuc   assert(filp->filp_count > 0);
253433d6423SLionel Sambuc   vp = filp->filp_vno;
254433d6423SLionel Sambuc   assert(vp != NULL);
255433d6423SLionel Sambuc 
256433d6423SLionel Sambuc   /* Lock vnode only if we haven't already locked it. If already locked by us,
257433d6423SLionel Sambuc    * we're allowed to have one additional 'soft' lock. */
258433d6423SLionel Sambuc   if (tll_locked_by_me(&vp->v_lock)) {
259433d6423SLionel Sambuc 	assert(filp->filp_softlock == NULL);
260433d6423SLionel Sambuc 	filp->filp_softlock = fp;
261433d6423SLionel Sambuc   } else {
262433d6423SLionel Sambuc 	/* We have to make an exception for vnodes belonging to pipes. Even
263433d6423SLionel Sambuc 	 * read(2) operations on pipes change the vnode and therefore require
264433d6423SLionel Sambuc 	 * exclusive access.
265433d6423SLionel Sambuc 	 */
266433d6423SLionel Sambuc 	if (S_ISFIFO(vp->v_mode) && locktype == VNODE_READ)
267433d6423SLionel Sambuc 		locktype = VNODE_WRITE;
268433d6423SLionel Sambuc 	lock_vnode(vp, locktype);
269433d6423SLionel Sambuc   }
270433d6423SLionel Sambuc 
271433d6423SLionel Sambuc   assert(vp->v_ref_count > 0);	/* vnode still in use? */
272433d6423SLionel Sambuc   assert(filp->filp_vno == vp);	/* vnode still what we think it is? */
273433d6423SLionel Sambuc 
274433d6423SLionel Sambuc   /* First try to get filp lock right off the bat */
275433d6423SLionel Sambuc   if (mutex_trylock(&filp->filp_lock) != 0) {
276433d6423SLionel Sambuc 
277433d6423SLionel Sambuc 	/* Already in use, let's wait for our turn */
278433d6423SLionel Sambuc 	org_self = worker_suspend();
279433d6423SLionel Sambuc 
280433d6423SLionel Sambuc 	if (mutex_lock(&filp->filp_lock) != 0)
281433d6423SLionel Sambuc 		panic("unable to obtain lock on filp");
282433d6423SLionel Sambuc 
283433d6423SLionel Sambuc 	worker_resume(org_self);
284433d6423SLionel Sambuc   }
285433d6423SLionel Sambuc }
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc /*===========================================================================*
288433d6423SLionel Sambuc  *				unlock_filp				     *
289433d6423SLionel Sambuc  *===========================================================================*/
290433d6423SLionel Sambuc void unlock_filp(filp)
291433d6423SLionel Sambuc struct filp *filp;
292433d6423SLionel Sambuc {
293433d6423SLionel Sambuc   /* If this filp holds a soft lock on the vnode, we must be the owner */
294433d6423SLionel Sambuc   if (filp->filp_softlock != NULL)
295433d6423SLionel Sambuc 	assert(filp->filp_softlock == fp);
296433d6423SLionel Sambuc 
297433d6423SLionel Sambuc   if (filp->filp_count > 0) {
298433d6423SLionel Sambuc 	/* Only unlock vnode if filp is still in use */
299433d6423SLionel Sambuc 
300433d6423SLionel Sambuc 	/* and if we don't hold a soft lock */
301433d6423SLionel Sambuc 	if (filp->filp_softlock == NULL) {
302433d6423SLionel Sambuc 		assert(tll_islocked(&(filp->filp_vno->v_lock)));
303433d6423SLionel Sambuc 		unlock_vnode(filp->filp_vno);
304433d6423SLionel Sambuc 	}
305433d6423SLionel Sambuc   }
306433d6423SLionel Sambuc 
307433d6423SLionel Sambuc   filp->filp_softlock = NULL;
308433d6423SLionel Sambuc   if (mutex_unlock(&filp->filp_lock) != 0)
309433d6423SLionel Sambuc 	panic("unable to release lock on filp");
310433d6423SLionel Sambuc }
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc /*===========================================================================*
313433d6423SLionel Sambuc  *				unlock_filps				     *
314433d6423SLionel Sambuc  *===========================================================================*/
315433d6423SLionel Sambuc void unlock_filps(filp1, filp2)
316433d6423SLionel Sambuc struct filp *filp1;
317433d6423SLionel Sambuc struct filp *filp2;
318433d6423SLionel Sambuc {
319433d6423SLionel Sambuc /* Unlock two filps that are tied to the same vnode. As a thread can lock a
320433d6423SLionel Sambuc  * vnode only once, unlocking the vnode twice would result in an error. */
321433d6423SLionel Sambuc 
322433d6423SLionel Sambuc   /* No NULL pointers and not equal */
323433d6423SLionel Sambuc   assert(filp1);
324433d6423SLionel Sambuc   assert(filp2);
325433d6423SLionel Sambuc   assert(filp1 != filp2);
326433d6423SLionel Sambuc 
327433d6423SLionel Sambuc   /* Must be tied to the same vnode and not NULL */
328433d6423SLionel Sambuc   assert(filp1->filp_vno == filp2->filp_vno);
329433d6423SLionel Sambuc   assert(filp1->filp_vno != NULL);
330433d6423SLionel Sambuc 
331433d6423SLionel Sambuc   if (filp1->filp_count > 0 && filp2->filp_count > 0) {
332433d6423SLionel Sambuc 	/* Only unlock vnode if filps are still in use */
333433d6423SLionel Sambuc 	unlock_vnode(filp1->filp_vno);
334433d6423SLionel Sambuc   }
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc   filp1->filp_softlock = NULL;
337433d6423SLionel Sambuc   filp2->filp_softlock = NULL;
338433d6423SLionel Sambuc   if (mutex_unlock(&filp2->filp_lock) != 0)
339433d6423SLionel Sambuc 	panic("unable to release filp lock on filp2");
340433d6423SLionel Sambuc   if (mutex_unlock(&filp1->filp_lock) != 0)
341433d6423SLionel Sambuc 	panic("unable to release filp lock on filp1");
342433d6423SLionel Sambuc }
343433d6423SLionel Sambuc 
344433d6423SLionel Sambuc /*===========================================================================*
345433d6423SLionel Sambuc  *				close_filp				     *
346433d6423SLionel Sambuc  *===========================================================================*/
347433d6423SLionel Sambuc void close_filp(f)
348433d6423SLionel Sambuc struct filp *f;
349433d6423SLionel Sambuc {
350433d6423SLionel Sambuc /* Close a file. Will also unlock filp when done */
351433d6423SLionel Sambuc 
352433d6423SLionel Sambuc   int rw;
353433d6423SLionel Sambuc   dev_t dev;
354433d6423SLionel Sambuc   struct vnode *vp;
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc   /* Must be locked */
357433d6423SLionel Sambuc   assert(mutex_trylock(&f->filp_lock) == -EDEADLK);
358433d6423SLionel Sambuc   assert(tll_islocked(&f->filp_vno->v_lock));
359433d6423SLionel Sambuc 
360433d6423SLionel Sambuc   vp = f->filp_vno;
361433d6423SLionel Sambuc 
362433d6423SLionel Sambuc   if (f->filp_count - 1 == 0 && f->filp_mode != FILP_CLOSED) {
363433d6423SLionel Sambuc 	/* Check to see if the file is special. */
364433d6423SLionel Sambuc 	if (S_ISCHR(vp->v_mode) || S_ISBLK(vp->v_mode)) {
365433d6423SLionel Sambuc 		dev = vp->v_sdev;
366433d6423SLionel Sambuc 		if (S_ISBLK(vp->v_mode))  {
367433d6423SLionel Sambuc 			lock_bsf();
368*71cd1dd4SDavid van Moolenbroek 			if (vp->v_bfs_e == ROOT_FS_E && dev != ROOT_DEV) {
369433d6423SLionel Sambuc 				/* Invalidate the cache unless the special is
370*71cd1dd4SDavid van Moolenbroek 				 * mounted. Be careful not to flush the root
371*71cd1dd4SDavid van Moolenbroek 				 * file system either.
372433d6423SLionel Sambuc 				 */
373*71cd1dd4SDavid van Moolenbroek 				(void) req_flush(vp->v_bfs_e, dev);
374433d6423SLionel Sambuc 			}
375433d6423SLionel Sambuc 			unlock_bsf();
376433d6423SLionel Sambuc 
377433d6423SLionel Sambuc 			(void) bdev_close(dev);	/* Ignore errors */
378433d6423SLionel Sambuc 		} else {
379433d6423SLionel Sambuc 			(void) cdev_close(dev);	/* Ignore errors */
380433d6423SLionel Sambuc 		}
381433d6423SLionel Sambuc 
382433d6423SLionel Sambuc 		f->filp_mode = FILP_CLOSED;
383433d6423SLionel Sambuc 	}
384433d6423SLionel Sambuc   }
385433d6423SLionel Sambuc 
386433d6423SLionel Sambuc   /* If the inode being closed is a pipe, release everyone hanging on it. */
387433d6423SLionel Sambuc   if (S_ISFIFO(vp->v_mode)) {
388433d6423SLionel Sambuc 	rw = (f->filp_mode & R_BIT ? VFS_WRITE : VFS_READ);
389433d6423SLionel Sambuc 	release(vp, rw, susp_count);
390433d6423SLionel Sambuc   }
391433d6423SLionel Sambuc 
392433d6423SLionel Sambuc   if (--f->filp_count == 0) {
393433d6423SLionel Sambuc 	if (S_ISFIFO(vp->v_mode)) {
394433d6423SLionel Sambuc 		/* Last reader or writer is going. Tell PFS about latest
395433d6423SLionel Sambuc 		 * pipe size.
396433d6423SLionel Sambuc 		 */
397433d6423SLionel Sambuc 		truncate_vnode(vp, vp->v_size);
398433d6423SLionel Sambuc 	}
399433d6423SLionel Sambuc 
400433d6423SLionel Sambuc 	unlock_vnode(f->filp_vno);
401433d6423SLionel Sambuc 	put_vnode(f->filp_vno);
402433d6423SLionel Sambuc 	f->filp_vno = NULL;
403433d6423SLionel Sambuc 	f->filp_mode = FILP_CLOSED;
404433d6423SLionel Sambuc 	f->filp_count = 0;
405433d6423SLionel Sambuc   } else if (f->filp_count < 0) {
406433d6423SLionel Sambuc 	panic("VFS: invalid filp count: %d ino %llx/%llu", f->filp_count,
407433d6423SLionel Sambuc 	      vp->v_dev, vp->v_inode_nr);
408433d6423SLionel Sambuc   } else {
409433d6423SLionel Sambuc 	unlock_vnode(f->filp_vno);
410433d6423SLionel Sambuc   }
411433d6423SLionel Sambuc 
412433d6423SLionel Sambuc   mutex_unlock(&f->filp_lock);
413433d6423SLionel Sambuc }
414433d6423SLionel Sambuc 
415433d6423SLionel Sambuc /*===========================================================================*
416433d6423SLionel Sambuc  *				do_copyfd				     *
417433d6423SLionel Sambuc  *===========================================================================*/
418433d6423SLionel Sambuc int do_copyfd(void)
419433d6423SLionel Sambuc {
420433d6423SLionel Sambuc /* Copy a file descriptor between processes, or close a remote file descriptor.
421433d6423SLionel Sambuc  * This call is used as back-call by device drivers (UDS, VND), and is expected
422433d6423SLionel Sambuc  * to be used in response to an IOCTL to such device drivers.
423433d6423SLionel Sambuc  */
424433d6423SLionel Sambuc   struct fproc *rfp;
425433d6423SLionel Sambuc   struct filp *rfilp;
426433d6423SLionel Sambuc   endpoint_t endpt;
427433d6423SLionel Sambuc   int r, fd, what, slot;
428433d6423SLionel Sambuc 
429433d6423SLionel Sambuc   /* This should be replaced with an ACL check. */
430433d6423SLionel Sambuc   if (!super_user) return(EPERM);
431433d6423SLionel Sambuc 
432433d6423SLionel Sambuc   endpt = job_m_in.m_lsys_vfs_copyfd.endpt;
433433d6423SLionel Sambuc   fd = job_m_in.m_lsys_vfs_copyfd.fd;
434433d6423SLionel Sambuc   what = job_m_in.m_lsys_vfs_copyfd.what;
435433d6423SLionel Sambuc 
436433d6423SLionel Sambuc   if (isokendpt(endpt, &slot) != OK) return(EINVAL);
437433d6423SLionel Sambuc   rfp = &fproc[slot];
438433d6423SLionel Sambuc 
439433d6423SLionel Sambuc   /* FIXME: we should now check that the user process is indeed blocked on an
440433d6423SLionel Sambuc    * IOCTL call, so that we can safely mess with its file descriptors.  We
441433d6423SLionel Sambuc    * currently do not have the necessary state to verify this, so we assume
442433d6423SLionel Sambuc    * that the call is always used in the right way.
443433d6423SLionel Sambuc    */
444433d6423SLionel Sambuc 
445433d6423SLionel Sambuc   /* Depending on the operation, get the file descriptor from the caller or the
446433d6423SLionel Sambuc    * user process.  Do not lock the filp yet: we first need to make sure that
447433d6423SLionel Sambuc    * locking it will not result in a deadlock.
448433d6423SLionel Sambuc    */
449433d6423SLionel Sambuc   rfilp = get_filp2((what == COPYFD_TO) ? fp : rfp, fd, VNODE_NONE);
450433d6423SLionel Sambuc   if (rfilp == NULL)
451433d6423SLionel Sambuc 	return(err_code);
452433d6423SLionel Sambuc 
453433d6423SLionel Sambuc   /* If the filp is involved in an IOCTL by the user process, locking the filp
454433d6423SLionel Sambuc    * here would result in a deadlock.  This would happen if a user process
455433d6423SLionel Sambuc    * passes in the file descriptor to the device node on which it is performing
456433d6423SLionel Sambuc    * the IOCTL.  We do not allow manipulation of such device nodes.  In
457433d6423SLionel Sambuc    * practice, this only applies to block-special files (and thus VND), because
458433d6423SLionel Sambuc    * character-special files (as used by UDS) are unlocked during the IOCTL.
459433d6423SLionel Sambuc    */
460433d6423SLionel Sambuc   if (rfilp->filp_ioctl_fp == rfp)
461433d6423SLionel Sambuc 	return(EBADF);
462433d6423SLionel Sambuc 
463433d6423SLionel Sambuc   /* Now we can safely lock the filp, copy or close it, and unlock it again. */
464433d6423SLionel Sambuc   lock_filp(rfilp, VNODE_READ);
465433d6423SLionel Sambuc 
466433d6423SLionel Sambuc   switch (what) {
467433d6423SLionel Sambuc   case COPYFD_FROM:
468433d6423SLionel Sambuc 	rfp = fp;
469433d6423SLionel Sambuc 
470433d6423SLionel Sambuc 	/* FALLTHROUGH */
471433d6423SLionel Sambuc   case COPYFD_TO:
472433d6423SLionel Sambuc 	/* Find a free file descriptor slot in the local or remote process. */
473433d6423SLionel Sambuc 	for (fd = 0; fd < OPEN_MAX; fd++)
474433d6423SLionel Sambuc 		if (rfp->fp_filp[fd] == NULL)
475433d6423SLionel Sambuc 			break;
476433d6423SLionel Sambuc 
477433d6423SLionel Sambuc 	/* If found, fill the slot and return the slot number. */
478433d6423SLionel Sambuc 	if (fd < OPEN_MAX) {
479433d6423SLionel Sambuc 		rfp->fp_filp[fd] = rfilp;
480433d6423SLionel Sambuc 		rfilp->filp_count++;
481433d6423SLionel Sambuc 		r = fd;
482433d6423SLionel Sambuc 	} else
483433d6423SLionel Sambuc 		r = EMFILE;
484433d6423SLionel Sambuc 
485433d6423SLionel Sambuc 	break;
486433d6423SLionel Sambuc 
487433d6423SLionel Sambuc   case COPYFD_CLOSE:
488433d6423SLionel Sambuc 	/* This should be used ONLY to revert a successful copy-to operation,
489433d6423SLionel Sambuc 	 * and assumes that the filp is still in use by the caller as well.
490433d6423SLionel Sambuc 	 */
491433d6423SLionel Sambuc 	if (rfilp->filp_count > 1) {
492433d6423SLionel Sambuc 		rfilp->filp_count--;
493433d6423SLionel Sambuc 		rfp->fp_filp[fd] = NULL;
494433d6423SLionel Sambuc 		r = OK;
495433d6423SLionel Sambuc 	} else
496433d6423SLionel Sambuc 		r = EBADF;
497433d6423SLionel Sambuc 
498433d6423SLionel Sambuc 	break;
499433d6423SLionel Sambuc 
500433d6423SLionel Sambuc   default:
501433d6423SLionel Sambuc 	r = EINVAL;
502433d6423SLionel Sambuc   }
503433d6423SLionel Sambuc 
504433d6423SLionel Sambuc   unlock_filp(rfilp);
505433d6423SLionel Sambuc 
506433d6423SLionel Sambuc   return(r);
507433d6423SLionel Sambuc }
508