xref: /minix3/minix/servers/vfs/filedes.c (revision 27852ebe53d5bf221cf5058cb7e858fa8fa8895e)
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  *===========================================================================*/
check_filp_locks_by_me(void)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  *===========================================================================*/
check_filp_locks(void)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  *===========================================================================*/
init_filps(void)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 /*===========================================================================*
86e3b8d4bbSDavid van Moolenbroek  *				check_fds				     *
87e3b8d4bbSDavid van Moolenbroek  *===========================================================================*/
check_fds(struct fproc * rfp,int nfds)88e3b8d4bbSDavid van Moolenbroek int check_fds(struct fproc *rfp, int nfds)
89e3b8d4bbSDavid van Moolenbroek {
90e3b8d4bbSDavid van Moolenbroek /* Check whether at least 'nfds' file descriptors can be created in the process
91e3b8d4bbSDavid van Moolenbroek  * 'rfp'.  Return OK on success, or otherwise an appropriate error code.
92e3b8d4bbSDavid van Moolenbroek  */
93e3b8d4bbSDavid van Moolenbroek   int i;
94e3b8d4bbSDavid van Moolenbroek 
95e3b8d4bbSDavid van Moolenbroek   assert(nfds >= 1);
96e3b8d4bbSDavid van Moolenbroek 
97e3b8d4bbSDavid van Moolenbroek   for (i = 0; i < OPEN_MAX; i++) {
98e3b8d4bbSDavid van Moolenbroek 	if (rfp->fp_filp[i] == NULL) {
99e3b8d4bbSDavid van Moolenbroek 		if (--nfds == 0)
100e3b8d4bbSDavid van Moolenbroek 			return OK;
101e3b8d4bbSDavid van Moolenbroek 	}
102e3b8d4bbSDavid van Moolenbroek   }
103e3b8d4bbSDavid van Moolenbroek 
104e3b8d4bbSDavid van Moolenbroek   return EMFILE;
105e3b8d4bbSDavid van Moolenbroek }
106e3b8d4bbSDavid van Moolenbroek 
107e3b8d4bbSDavid van Moolenbroek /*===========================================================================*
108433d6423SLionel Sambuc  *				get_fd					     *
109433d6423SLionel Sambuc  *===========================================================================*/
get_fd(struct fproc * rfp,int start,mode_t bits,int * k,struct filp ** fpt)110433d6423SLionel Sambuc int get_fd(struct fproc *rfp, int start, mode_t bits, int *k, struct filp **fpt)
111433d6423SLionel Sambuc {
112433d6423SLionel Sambuc /* Look for a free file descriptor and a free filp slot.  Fill in the mode word
113433d6423SLionel Sambuc  * in the latter, but don't claim either one yet, since the open() or creat()
114433d6423SLionel Sambuc  * may yet fail.
115433d6423SLionel Sambuc  */
116433d6423SLionel Sambuc 
117433d6423SLionel Sambuc   register struct filp *f;
118433d6423SLionel Sambuc   register int i;
119433d6423SLionel Sambuc 
120433d6423SLionel Sambuc   /* Search the fproc fp_filp table for a free file descriptor. */
121433d6423SLionel Sambuc   for (i = start; i < OPEN_MAX; i++) {
122433d6423SLionel Sambuc 	if (rfp->fp_filp[i] == NULL) {
123433d6423SLionel Sambuc 		/* A file descriptor has been located. */
124433d6423SLionel Sambuc 		*k = i;
125433d6423SLionel Sambuc 		break;
126433d6423SLionel Sambuc 	}
127433d6423SLionel Sambuc   }
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc   /* Check to see if a file descriptor has been found. */
130433d6423SLionel Sambuc   if (i >= OPEN_MAX) return(EMFILE);
131433d6423SLionel Sambuc 
132433d6423SLionel Sambuc   /* If we don't care about a filp, return now */
133433d6423SLionel Sambuc   if (fpt == NULL) return(OK);
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc   /* Now that a file descriptor has been found, look for a free filp slot. */
136433d6423SLionel Sambuc   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
137433d6423SLionel Sambuc 	assert(f->filp_count >= 0);
138433d6423SLionel Sambuc 	if (f->filp_count == 0 && mutex_trylock(&f->filp_lock) == 0) {
139433d6423SLionel Sambuc 		f->filp_mode = bits;
140433d6423SLionel Sambuc 		f->filp_pos = 0;
141433d6423SLionel Sambuc 		f->filp_selectors = 0;
142433d6423SLionel Sambuc 		f->filp_select_ops = 0;
143433d6423SLionel Sambuc 		f->filp_pipe_select_ops = 0;
144e3b8d4bbSDavid van Moolenbroek 		f->filp_select_dev = NO_DEV;
145433d6423SLionel Sambuc 		f->filp_flags = 0;
146433d6423SLionel Sambuc 		f->filp_select_flags = 0;
147433d6423SLionel Sambuc 		f->filp_softlock = NULL;
148433d6423SLionel Sambuc 		f->filp_ioctl_fp = NULL;
149433d6423SLionel Sambuc 		*fpt = f;
150433d6423SLionel Sambuc 		return(OK);
151433d6423SLionel Sambuc 	}
152433d6423SLionel Sambuc   }
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc   /* If control passes here, the filp table must be full.  Report that back. */
155433d6423SLionel Sambuc   return(ENFILE);
156433d6423SLionel Sambuc }
157433d6423SLionel Sambuc 
158433d6423SLionel Sambuc 
159433d6423SLionel Sambuc /*===========================================================================*
160433d6423SLionel Sambuc  *				get_filp				     *
161433d6423SLionel Sambuc  *===========================================================================*/
162a0814afbSRichard Sailer struct filp *
get_filp(int fild,tll_access_t locktype)163a0814afbSRichard Sailer get_filp(
164a0814afbSRichard Sailer 	int fild,			/* file descriptor */
165a0814afbSRichard Sailer 	tll_access_t locktype
166a0814afbSRichard Sailer )
167433d6423SLionel Sambuc {
168433d6423SLionel Sambuc /* See if 'fild' refers to a valid file descr.  If so, return its filp ptr. */
169433d6423SLionel Sambuc 
170433d6423SLionel Sambuc   return get_filp2(fp, fild, locktype);
171433d6423SLionel Sambuc }
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc /*===========================================================================*
175433d6423SLionel Sambuc  *				get_filp2				     *
176433d6423SLionel Sambuc  *===========================================================================*/
177a0814afbSRichard Sailer struct filp *
get_filp2(register struct fproc * rfp,int fild,tll_access_t locktype)178a0814afbSRichard Sailer get_filp2(
179a0814afbSRichard Sailer 	register struct fproc *rfp,
180a0814afbSRichard Sailer 	int fild,			/* file descriptor */
181a0814afbSRichard Sailer 	tll_access_t locktype
182a0814afbSRichard Sailer )
183433d6423SLionel Sambuc {
184433d6423SLionel Sambuc /* See if 'fild' refers to a valid file descr.  If so, return its filp ptr. */
185433d6423SLionel Sambuc   struct filp *filp;
186433d6423SLionel Sambuc 
187433d6423SLionel Sambuc   filp = NULL;
188433d6423SLionel Sambuc   if (fild < 0 || fild >= OPEN_MAX)
189433d6423SLionel Sambuc 	err_code = EBADF;
190433d6423SLionel Sambuc   else if (locktype != VNODE_OPCL && rfp->fp_filp[fild] != NULL &&
191433d6423SLionel Sambuc 		rfp->fp_filp[fild]->filp_mode == FILP_CLOSED)
192433d6423SLionel Sambuc 	err_code = EIO; /* disallow all use except close(2) */
193433d6423SLionel Sambuc   else if ((filp = rfp->fp_filp[fild]) == NULL)
194433d6423SLionel Sambuc 	err_code = EBADF;
195433d6423SLionel Sambuc   else if (locktype != VNODE_NONE)	/* Only lock the filp if requested */
196433d6423SLionel Sambuc 	lock_filp(filp, locktype);	/* All is fine */
197433d6423SLionel Sambuc 
198433d6423SLionel Sambuc   return(filp);	/* may also be NULL */
199433d6423SLionel Sambuc }
200433d6423SLionel Sambuc 
201433d6423SLionel Sambuc 
202433d6423SLionel Sambuc /*===========================================================================*
203433d6423SLionel Sambuc  *				find_filp				     *
204433d6423SLionel Sambuc  *===========================================================================*/
find_filp(struct vnode * vp,mode_t bits)205433d6423SLionel Sambuc struct filp *find_filp(struct vnode *vp, mode_t bits)
206433d6423SLionel Sambuc {
207433d6423SLionel Sambuc /* Find a filp slot that refers to the vnode 'vp' in a way as described
208433d6423SLionel Sambuc  * by the mode bit 'bits'. Used for determining whether somebody is still
209433d6423SLionel Sambuc  * interested in either end of a pipe.  Also used when opening a FIFO to
210433d6423SLionel Sambuc  * find partners to share a filp field with (to shared the file position).
211433d6423SLionel Sambuc  * Like 'get_fd' it performs its job by linear search through the filp table.
212433d6423SLionel Sambuc  */
213433d6423SLionel Sambuc 
214433d6423SLionel Sambuc   struct filp *f;
215433d6423SLionel Sambuc 
216433d6423SLionel Sambuc   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
217433d6423SLionel Sambuc 	if (f->filp_count != 0 && f->filp_vno == vp && (f->filp_mode & bits)) {
218433d6423SLionel Sambuc 		return(f);
219433d6423SLionel Sambuc 	}
220433d6423SLionel Sambuc   }
221433d6423SLionel Sambuc 
222433d6423SLionel Sambuc   /* If control passes here, the filp wasn't there.  Report that back. */
223433d6423SLionel Sambuc   return(NULL);
224433d6423SLionel Sambuc }
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc /*===========================================================================*
227e3b8d4bbSDavid van Moolenbroek  *				find_filp_by_sock_dev			     *
228e3b8d4bbSDavid van Moolenbroek  *===========================================================================*/
find_filp_by_sock_dev(dev_t dev)229e3b8d4bbSDavid van Moolenbroek struct filp *find_filp_by_sock_dev(dev_t dev)
230e3b8d4bbSDavid van Moolenbroek {
231e3b8d4bbSDavid van Moolenbroek /* See if there is a file pointer for a socket with the given socket device
232e3b8d4bbSDavid van Moolenbroek  * number.
233e3b8d4bbSDavid van Moolenbroek  */
234e3b8d4bbSDavid van Moolenbroek   struct filp *f;
235e3b8d4bbSDavid van Moolenbroek 
236e3b8d4bbSDavid van Moolenbroek   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
237e3b8d4bbSDavid van Moolenbroek 	if (f->filp_count != 0 && f->filp_vno != NULL &&
238e3b8d4bbSDavid van Moolenbroek 	    S_ISSOCK(f->filp_vno->v_mode) && f->filp_vno->v_sdev == dev &&
239e3b8d4bbSDavid van Moolenbroek 	    f->filp_mode != FILP_CLOSED) {
240e3b8d4bbSDavid van Moolenbroek 		return f;
241e3b8d4bbSDavid van Moolenbroek 	}
242e3b8d4bbSDavid van Moolenbroek   }
243e3b8d4bbSDavid van Moolenbroek 
244e3b8d4bbSDavid van Moolenbroek   return NULL;
245e3b8d4bbSDavid van Moolenbroek }
246e3b8d4bbSDavid van Moolenbroek 
247e3b8d4bbSDavid van Moolenbroek /*===========================================================================*
248433d6423SLionel Sambuc  *				invalidate_filp				     *
249433d6423SLionel Sambuc  *===========================================================================*/
invalidate_filp(struct filp * rfilp)250433d6423SLionel Sambuc void invalidate_filp(struct filp *rfilp)
251433d6423SLionel Sambuc {
252433d6423SLionel Sambuc /* Invalidate filp. */
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc   rfilp->filp_mode = FILP_CLOSED;
255433d6423SLionel Sambuc }
256433d6423SLionel Sambuc 
257433d6423SLionel Sambuc /*===========================================================================*
258433d6423SLionel Sambuc  *			invalidate_filp_by_char_major			     *
259433d6423SLionel Sambuc  *===========================================================================*/
invalidate_filp_by_char_major(devmajor_t major)2603b468884SDavid van Moolenbroek void invalidate_filp_by_char_major(devmajor_t major)
261433d6423SLionel Sambuc {
262433d6423SLionel Sambuc   struct filp *f;
263433d6423SLionel Sambuc 
264433d6423SLionel Sambuc   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
265433d6423SLionel Sambuc 	if (f->filp_count != 0 && f->filp_vno != NULL) {
266433d6423SLionel Sambuc 		if (major(f->filp_vno->v_sdev) == major &&
267433d6423SLionel Sambuc 		    S_ISCHR(f->filp_vno->v_mode)) {
268433d6423SLionel Sambuc 			invalidate_filp(f);
269433d6423SLionel Sambuc 		}
270433d6423SLionel Sambuc 	}
271433d6423SLionel Sambuc   }
272433d6423SLionel Sambuc }
273433d6423SLionel Sambuc 
274433d6423SLionel Sambuc /*===========================================================================*
275e3b8d4bbSDavid van Moolenbroek  *			invalidate_filp_by_sock_drv			     *
276e3b8d4bbSDavid van Moolenbroek  *===========================================================================*/
invalidate_filp_by_sock_drv(unsigned int num)277e3b8d4bbSDavid van Moolenbroek void invalidate_filp_by_sock_drv(unsigned int num)
278e3b8d4bbSDavid van Moolenbroek {
279e3b8d4bbSDavid van Moolenbroek /* Invalidate all file pointers for sockets owned by the socket driver with the
280e3b8d4bbSDavid van Moolenbroek  * smap number 'num'.
281e3b8d4bbSDavid van Moolenbroek  */
282e3b8d4bbSDavid van Moolenbroek   struct filp *f;
283e3b8d4bbSDavid van Moolenbroek   struct smap *sp;
284e3b8d4bbSDavid van Moolenbroek 
285e3b8d4bbSDavid van Moolenbroek   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
286e3b8d4bbSDavid van Moolenbroek 	if (f->filp_count != 0 && f->filp_vno != NULL) {
287e3b8d4bbSDavid van Moolenbroek 		if (S_ISSOCK(f->filp_vno->v_mode) &&
288e3b8d4bbSDavid van Moolenbroek 		    (sp = get_smap_by_dev(f->filp_vno->v_sdev, NULL)) != NULL
289e3b8d4bbSDavid van Moolenbroek 		    && sp->smap_num == num)
290e3b8d4bbSDavid van Moolenbroek 			invalidate_filp(f);
291e3b8d4bbSDavid van Moolenbroek 	}
292e3b8d4bbSDavid van Moolenbroek   }
293e3b8d4bbSDavid van Moolenbroek }
294e3b8d4bbSDavid van Moolenbroek 
295e3b8d4bbSDavid van Moolenbroek /*===========================================================================*
296433d6423SLionel Sambuc  *			invalidate_filp_by_endpt			     *
297433d6423SLionel Sambuc  *===========================================================================*/
invalidate_filp_by_endpt(endpoint_t proc_e)298433d6423SLionel Sambuc void invalidate_filp_by_endpt(endpoint_t proc_e)
299433d6423SLionel Sambuc {
300433d6423SLionel Sambuc   struct filp *f;
301433d6423SLionel Sambuc 
302433d6423SLionel Sambuc   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
303433d6423SLionel Sambuc 	if (f->filp_count != 0 && f->filp_vno != NULL) {
304433d6423SLionel Sambuc 		if (f->filp_vno->v_fs_e == proc_e)
305433d6423SLionel Sambuc 			invalidate_filp(f);
306433d6423SLionel Sambuc 	}
307433d6423SLionel Sambuc   }
308433d6423SLionel Sambuc }
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc /*===========================================================================*
311433d6423SLionel Sambuc  *				lock_filp				     *
312433d6423SLionel Sambuc  *===========================================================================*/
313a0814afbSRichard Sailer void
lock_filp(struct filp * filp,tll_access_t locktype)314a0814afbSRichard Sailer lock_filp(struct filp *filp, tll_access_t locktype)
315433d6423SLionel Sambuc {
316433d6423SLionel Sambuc   struct worker_thread *org_self;
317433d6423SLionel Sambuc   struct vnode *vp;
318433d6423SLionel Sambuc 
319433d6423SLionel Sambuc   assert(filp->filp_count > 0);
320433d6423SLionel Sambuc   vp = filp->filp_vno;
321433d6423SLionel Sambuc   assert(vp != NULL);
322433d6423SLionel Sambuc 
323433d6423SLionel Sambuc   /* Lock vnode only if we haven't already locked it. If already locked by us,
324433d6423SLionel Sambuc    * we're allowed to have one additional 'soft' lock. */
325433d6423SLionel Sambuc   if (tll_locked_by_me(&vp->v_lock)) {
326433d6423SLionel Sambuc 	assert(filp->filp_softlock == NULL);
327433d6423SLionel Sambuc 	filp->filp_softlock = fp;
328433d6423SLionel Sambuc   } else {
329433d6423SLionel Sambuc 	/* We have to make an exception for vnodes belonging to pipes. Even
330433d6423SLionel Sambuc 	 * read(2) operations on pipes change the vnode and therefore require
331433d6423SLionel Sambuc 	 * exclusive access.
332433d6423SLionel Sambuc 	 */
333433d6423SLionel Sambuc 	if (S_ISFIFO(vp->v_mode) && locktype == VNODE_READ)
334433d6423SLionel Sambuc 		locktype = VNODE_WRITE;
335433d6423SLionel Sambuc 	lock_vnode(vp, locktype);
336433d6423SLionel Sambuc   }
337433d6423SLionel Sambuc 
338433d6423SLionel Sambuc   assert(vp->v_ref_count > 0);	/* vnode still in use? */
339433d6423SLionel Sambuc   assert(filp->filp_vno == vp);	/* vnode still what we think it is? */
340433d6423SLionel Sambuc 
341433d6423SLionel Sambuc   /* First try to get filp lock right off the bat */
342433d6423SLionel Sambuc   if (mutex_trylock(&filp->filp_lock) != 0) {
343433d6423SLionel Sambuc 
344433d6423SLionel Sambuc 	/* Already in use, let's wait for our turn */
345433d6423SLionel Sambuc 	org_self = worker_suspend();
346433d6423SLionel Sambuc 
347433d6423SLionel Sambuc 	if (mutex_lock(&filp->filp_lock) != 0)
348433d6423SLionel Sambuc 		panic("unable to obtain lock on filp");
349433d6423SLionel Sambuc 
350433d6423SLionel Sambuc 	worker_resume(org_self);
351433d6423SLionel Sambuc   }
352433d6423SLionel Sambuc }
353433d6423SLionel Sambuc 
354433d6423SLionel Sambuc /*===========================================================================*
355433d6423SLionel Sambuc  *				unlock_filp				     *
356433d6423SLionel Sambuc  *===========================================================================*/
357a0814afbSRichard Sailer void
unlock_filp(struct filp * filp)358a0814afbSRichard Sailer unlock_filp(struct filp *filp)
359433d6423SLionel Sambuc {
360433d6423SLionel Sambuc   /* If this filp holds a soft lock on the vnode, we must be the owner */
361433d6423SLionel Sambuc   if (filp->filp_softlock != NULL)
362433d6423SLionel Sambuc 	assert(filp->filp_softlock == fp);
363433d6423SLionel Sambuc 
364433d6423SLionel Sambuc   if (filp->filp_count > 0) {
365433d6423SLionel Sambuc 	/* Only unlock vnode if filp is still in use */
366433d6423SLionel Sambuc 
367433d6423SLionel Sambuc 	/* and if we don't hold a soft lock */
368433d6423SLionel Sambuc 	if (filp->filp_softlock == NULL) {
369433d6423SLionel Sambuc 		assert(tll_islocked(&(filp->filp_vno->v_lock)));
370433d6423SLionel Sambuc 		unlock_vnode(filp->filp_vno);
371433d6423SLionel Sambuc 	}
372433d6423SLionel Sambuc   }
373433d6423SLionel Sambuc 
374433d6423SLionel Sambuc   filp->filp_softlock = NULL;
375433d6423SLionel Sambuc   if (mutex_unlock(&filp->filp_lock) != 0)
376433d6423SLionel Sambuc 	panic("unable to release lock on filp");
377433d6423SLionel Sambuc }
378433d6423SLionel Sambuc 
379433d6423SLionel Sambuc /*===========================================================================*
380433d6423SLionel Sambuc  *				unlock_filps				     *
381433d6423SLionel Sambuc  *===========================================================================*/
382a0814afbSRichard Sailer void
unlock_filps(struct filp * filp1,struct filp * filp2)383a0814afbSRichard Sailer unlock_filps(struct filp *filp1, struct filp *filp2)
384433d6423SLionel Sambuc {
385433d6423SLionel Sambuc /* Unlock two filps that are tied to the same vnode. As a thread can lock a
386433d6423SLionel Sambuc  * vnode only once, unlocking the vnode twice would result in an error. */
387433d6423SLionel Sambuc 
388433d6423SLionel Sambuc   /* No NULL pointers and not equal */
389433d6423SLionel Sambuc   assert(filp1);
390433d6423SLionel Sambuc   assert(filp2);
391433d6423SLionel Sambuc   assert(filp1 != filp2);
392433d6423SLionel Sambuc 
393433d6423SLionel Sambuc   /* Must be tied to the same vnode and not NULL */
394433d6423SLionel Sambuc   assert(filp1->filp_vno == filp2->filp_vno);
395433d6423SLionel Sambuc   assert(filp1->filp_vno != NULL);
396433d6423SLionel Sambuc 
397433d6423SLionel Sambuc   if (filp1->filp_count > 0 && filp2->filp_count > 0) {
398433d6423SLionel Sambuc 	/* Only unlock vnode if filps are still in use */
399433d6423SLionel Sambuc 	unlock_vnode(filp1->filp_vno);
400433d6423SLionel Sambuc   }
401433d6423SLionel Sambuc 
402433d6423SLionel Sambuc   filp1->filp_softlock = NULL;
403433d6423SLionel Sambuc   filp2->filp_softlock = NULL;
404433d6423SLionel Sambuc   if (mutex_unlock(&filp2->filp_lock) != 0)
405433d6423SLionel Sambuc 	panic("unable to release filp lock on filp2");
406433d6423SLionel Sambuc   if (mutex_unlock(&filp1->filp_lock) != 0)
407433d6423SLionel Sambuc 	panic("unable to release filp lock on filp1");
408433d6423SLionel Sambuc }
409433d6423SLionel Sambuc 
410433d6423SLionel Sambuc /*===========================================================================*
411433d6423SLionel Sambuc  *				close_filp				     *
412433d6423SLionel Sambuc  *===========================================================================*/
413491d647aSDavid van Moolenbroek int
close_filp(struct filp * f,int may_suspend)414491d647aSDavid van Moolenbroek close_filp(struct filp * f, int may_suspend)
415433d6423SLionel Sambuc {
416491d647aSDavid van Moolenbroek /* Close a file.  Will also unlock filp when done.  The 'may_suspend' flag
417491d647aSDavid van Moolenbroek  * indicates whether the current process may be suspended closing a socket.
418491d647aSDavid van Moolenbroek  * That is currently supported only when the user issued a close(2), and (only)
419491d647aSDavid van Moolenbroek  * in that case may this function return SUSPEND instead of OK.  In all other
420491d647aSDavid van Moolenbroek  * cases, this function will always return OK.  It will never return another
421491d647aSDavid van Moolenbroek  * error code, for reasons explained below.
422491d647aSDavid van Moolenbroek  */
423491d647aSDavid van Moolenbroek   int r, rw;
424433d6423SLionel Sambuc   dev_t dev;
425433d6423SLionel Sambuc   struct vnode *vp;
426433d6423SLionel Sambuc 
427433d6423SLionel Sambuc   /* Must be locked */
428433d6423SLionel Sambuc   assert(mutex_trylock(&f->filp_lock) == -EDEADLK);
429433d6423SLionel Sambuc   assert(tll_islocked(&f->filp_vno->v_lock));
430433d6423SLionel Sambuc 
431433d6423SLionel Sambuc   vp = f->filp_vno;
432433d6423SLionel Sambuc 
433491d647aSDavid van Moolenbroek   r = OK;
434491d647aSDavid van Moolenbroek 
435433d6423SLionel Sambuc   if (f->filp_count - 1 == 0 && f->filp_mode != FILP_CLOSED) {
436433d6423SLionel Sambuc 	/* Check to see if the file is special. */
437e3b8d4bbSDavid van Moolenbroek 	if (S_ISCHR(vp->v_mode) || S_ISBLK(vp->v_mode) ||
438e3b8d4bbSDavid van Moolenbroek 	    S_ISSOCK(vp->v_mode)) {
439433d6423SLionel Sambuc 		dev = vp->v_sdev;
440433d6423SLionel Sambuc 		if (S_ISBLK(vp->v_mode))  {
441433d6423SLionel Sambuc 			lock_bsf();
44271cd1dd4SDavid van Moolenbroek 			if (vp->v_bfs_e == ROOT_FS_E && dev != ROOT_DEV) {
443433d6423SLionel Sambuc 				/* Invalidate the cache unless the special is
44471cd1dd4SDavid van Moolenbroek 				 * mounted. Be careful not to flush the root
44571cd1dd4SDavid van Moolenbroek 				 * file system either.
446433d6423SLionel Sambuc 				 */
44771cd1dd4SDavid van Moolenbroek 				(void) req_flush(vp->v_bfs_e, dev);
448433d6423SLionel Sambuc 			}
449433d6423SLionel Sambuc 			unlock_bsf();
450433d6423SLionel Sambuc 
451433d6423SLionel Sambuc 			(void) bdev_close(dev);	/* Ignore errors */
452e3b8d4bbSDavid van Moolenbroek 		} else if (S_ISCHR(vp->v_mode)) {
453433d6423SLionel Sambuc 			(void) cdev_close(dev);	/* Ignore errors */
454e3b8d4bbSDavid van Moolenbroek 		} else {
455e3b8d4bbSDavid van Moolenbroek 			/*
456491d647aSDavid van Moolenbroek 			 * Sockets may take a while to be closed (SO_LINGER),
457491d647aSDavid van Moolenbroek 			 * and thus, we may issue a suspending close to a
458e3b8d4bbSDavid van Moolenbroek 			 * socket driver.  Getting this working for close(2) is
459491d647aSDavid van Moolenbroek 			 * the easy case, and that is all we support for now.
460491d647aSDavid van Moolenbroek 			 * However, there is also eg dup2(2), which if
461491d647aSDavid van Moolenbroek 			 * interrupted by a signal should technically fail
462491d647aSDavid van Moolenbroek 			 * without closing the file descriptor.  Then there are
463491d647aSDavid van Moolenbroek 			 * cases where the close should never block: process
464491d647aSDavid van Moolenbroek 			 * exit and close-on-exec for example.  Getting all
465491d647aSDavid van Moolenbroek 			 * such cases right is left to future work; currently
466491d647aSDavid van Moolenbroek 			 * they all perform thread-blocking socket closes and
467491d647aSDavid van Moolenbroek 			 * thus cause the socket to perform lingering in the
468491d647aSDavid van Moolenbroek 			 * background if at all.
469e3b8d4bbSDavid van Moolenbroek 			 */
470491d647aSDavid van Moolenbroek 			assert(!may_suspend || job_call_nr == VFS_CLOSE);
471491d647aSDavid van Moolenbroek 
472491d647aSDavid van Moolenbroek 			if (f->filp_flags & O_NONBLOCK)
473491d647aSDavid van Moolenbroek 				may_suspend = FALSE;
474491d647aSDavid van Moolenbroek 
475491d647aSDavid van Moolenbroek 			r = sdev_close(dev, may_suspend);
476491d647aSDavid van Moolenbroek 
477491d647aSDavid van Moolenbroek 			/*
478491d647aSDavid van Moolenbroek 			 * Returning a non-OK error is a bad idea, because it
479491d647aSDavid van Moolenbroek 			 * will leave the application wondering whether closing
480491d647aSDavid van Moolenbroek 			 * the file descriptor actually succeeded.
481491d647aSDavid van Moolenbroek 			 */
482491d647aSDavid van Moolenbroek 			if (r != SUSPEND)
483491d647aSDavid van Moolenbroek 				r = OK;
484433d6423SLionel Sambuc 		}
485433d6423SLionel Sambuc 
486433d6423SLionel Sambuc 		f->filp_mode = FILP_CLOSED;
487433d6423SLionel Sambuc 	}
488433d6423SLionel Sambuc   }
489433d6423SLionel Sambuc 
490433d6423SLionel Sambuc   /* If the inode being closed is a pipe, release everyone hanging on it. */
491433d6423SLionel Sambuc   if (S_ISFIFO(vp->v_mode)) {
492433d6423SLionel Sambuc 	rw = (f->filp_mode & R_BIT ? VFS_WRITE : VFS_READ);
493433d6423SLionel Sambuc 	release(vp, rw, susp_count);
494433d6423SLionel Sambuc   }
495433d6423SLionel Sambuc 
496433d6423SLionel Sambuc   if (--f->filp_count == 0) {
497433d6423SLionel Sambuc 	if (S_ISFIFO(vp->v_mode)) {
498433d6423SLionel Sambuc 		/* Last reader or writer is going. Tell PFS about latest
499433d6423SLionel Sambuc 		 * pipe size.
500433d6423SLionel Sambuc 		 */
501433d6423SLionel Sambuc 		truncate_vnode(vp, vp->v_size);
502433d6423SLionel Sambuc 	}
503433d6423SLionel Sambuc 
504433d6423SLionel Sambuc 	unlock_vnode(f->filp_vno);
505433d6423SLionel Sambuc 	put_vnode(f->filp_vno);
506433d6423SLionel Sambuc 	f->filp_vno = NULL;
507433d6423SLionel Sambuc 	f->filp_mode = FILP_CLOSED;
508433d6423SLionel Sambuc 	f->filp_count = 0;
509433d6423SLionel Sambuc   } else if (f->filp_count < 0) {
510433d6423SLionel Sambuc 	panic("VFS: invalid filp count: %d ino %llx/%llu", f->filp_count,
511433d6423SLionel Sambuc 	      vp->v_dev, vp->v_inode_nr);
512433d6423SLionel Sambuc   } else {
513433d6423SLionel Sambuc 	unlock_vnode(f->filp_vno);
514433d6423SLionel Sambuc   }
515433d6423SLionel Sambuc 
516433d6423SLionel Sambuc   mutex_unlock(&f->filp_lock);
517491d647aSDavid van Moolenbroek 
518491d647aSDavid van Moolenbroek   return r;
519433d6423SLionel Sambuc }
520433d6423SLionel Sambuc 
521433d6423SLionel Sambuc /*===========================================================================*
522433d6423SLionel Sambuc  *				do_copyfd				     *
523433d6423SLionel Sambuc  *===========================================================================*/
do_copyfd(void)524433d6423SLionel Sambuc int do_copyfd(void)
525433d6423SLionel Sambuc {
526433d6423SLionel Sambuc /* Copy a file descriptor between processes, or close a remote file descriptor.
527433d6423SLionel Sambuc  * This call is used as back-call by device drivers (UDS, VND), and is expected
528*27852ebeSDavid van Moolenbroek  * to be used in response to either an IOCTL to VND or a SEND or RECV socket
529*27852ebeSDavid van Moolenbroek  * request to UDS.
530433d6423SLionel Sambuc  */
531433d6423SLionel Sambuc   struct fproc *rfp;
532433d6423SLionel Sambuc   struct filp *rfilp;
533c344203eSDavid van Moolenbroek   struct vnode *vp;
534c344203eSDavid van Moolenbroek   struct smap *sp;
535433d6423SLionel Sambuc   endpoint_t endpt;
53645443f35SDavid van Moolenbroek   int r, fd, what, flags, slot;
537433d6423SLionel Sambuc 
538433d6423SLionel Sambuc   /* This should be replaced with an ACL check. */
539433d6423SLionel Sambuc   if (!super_user) return(EPERM);
540433d6423SLionel Sambuc 
541433d6423SLionel Sambuc   endpt = job_m_in.m_lsys_vfs_copyfd.endpt;
542433d6423SLionel Sambuc   fd = job_m_in.m_lsys_vfs_copyfd.fd;
543433d6423SLionel Sambuc   what = job_m_in.m_lsys_vfs_copyfd.what;
544433d6423SLionel Sambuc 
54545443f35SDavid van Moolenbroek   flags = what & COPYFD_FLAGS;
54645443f35SDavid van Moolenbroek   what &= ~COPYFD_FLAGS;
54745443f35SDavid van Moolenbroek 
548433d6423SLionel Sambuc   if (isokendpt(endpt, &slot) != OK) return(EINVAL);
549433d6423SLionel Sambuc   rfp = &fproc[slot];
550433d6423SLionel Sambuc 
551433d6423SLionel Sambuc   /* FIXME: we should now check that the user process is indeed blocked on an
552*27852ebeSDavid van Moolenbroek    * IOCTL or socket call, so that we can safely mess with its file
553*27852ebeSDavid van Moolenbroek    * descriptors.  We currently do not have the necessary state to verify this,
554*27852ebeSDavid van Moolenbroek    * so we assume that the call is always used in the right way.
555433d6423SLionel Sambuc    */
556433d6423SLionel Sambuc 
557433d6423SLionel Sambuc   /* Depending on the operation, get the file descriptor from the caller or the
558433d6423SLionel Sambuc    * user process.  Do not lock the filp yet: we first need to make sure that
559433d6423SLionel Sambuc    * locking it will not result in a deadlock.
560433d6423SLionel Sambuc    */
561433d6423SLionel Sambuc   rfilp = get_filp2((what == COPYFD_TO) ? fp : rfp, fd, VNODE_NONE);
562433d6423SLionel Sambuc   if (rfilp == NULL)
563433d6423SLionel Sambuc 	return(err_code);
564433d6423SLionel Sambuc 
565433d6423SLionel Sambuc   /* If the filp is involved in an IOCTL by the user process, locking the filp
566433d6423SLionel Sambuc    * here would result in a deadlock.  This would happen if a user process
567433d6423SLionel Sambuc    * passes in the file descriptor to the device node on which it is performing
568433d6423SLionel Sambuc    * the IOCTL.  We do not allow manipulation of such device nodes.  In
569433d6423SLionel Sambuc    * practice, this only applies to block-special files (and thus VND), because
570*27852ebeSDavid van Moolenbroek    * socket files (as used by UDS) are unlocked during the socket operation.
571433d6423SLionel Sambuc    */
572433d6423SLionel Sambuc   if (rfilp->filp_ioctl_fp == rfp)
573433d6423SLionel Sambuc 	return(EBADF);
574433d6423SLionel Sambuc 
575433d6423SLionel Sambuc   /* Now we can safely lock the filp, copy or close it, and unlock it again. */
576433d6423SLionel Sambuc   lock_filp(rfilp, VNODE_READ);
577433d6423SLionel Sambuc 
578433d6423SLionel Sambuc   switch (what) {
579433d6423SLionel Sambuc   case COPYFD_FROM:
580c344203eSDavid van Moolenbroek 	/*
581c344203eSDavid van Moolenbroek 	 * If the caller is a socket driver (namely, UDS) and the file
582c344203eSDavid van Moolenbroek 	 * descriptor being copied in is a socket for that socket driver, then
583c344203eSDavid van Moolenbroek 	 * deny the call, because of at least two known issues.  Both issues
584c344203eSDavid van Moolenbroek 	 * are related to UDS having an in-flight file descriptor that is the
585c344203eSDavid van Moolenbroek 	 * last reference to a UDS socket:
586c344203eSDavid van Moolenbroek 	 *
587c344203eSDavid van Moolenbroek 	 * 1) if UDS tries to close the file descriptor, this will prompt VFS
588c344203eSDavid van Moolenbroek 	 *    to close the underlying object, which is a UDS socket.  As a
589c344203eSDavid van Moolenbroek 	 *    result, while UDS is blocked in the close(2), VFS will try to
590c344203eSDavid van Moolenbroek 	 *    send a request to UDS to close the socket.  This results in a
591c344203eSDavid van Moolenbroek 	 *    deadlock of the UDS service.
592c344203eSDavid van Moolenbroek 	 *
593c344203eSDavid van Moolenbroek 	 * 2) if a file descriptor for a UDS socket is sent across that same
594c344203eSDavid van Moolenbroek 	 *    UDS socket, the socket will remain referenced by UDS, thus open
595c344203eSDavid van Moolenbroek 	 *    in VFS, and therefore also open in UDS.  The socket and file
596c344203eSDavid van Moolenbroek 	 *    descriptor will both remain in use for the rest of UDS' lifetime.
597c344203eSDavid van Moolenbroek 	 *    This can easily result in denial-of-service in the UDS service.
598c344203eSDavid van Moolenbroek 	 *    The same problem can be triggered using multiple sockets that
599c344203eSDavid van Moolenbroek 	 *    have in-flight file descriptors referencing each other.
600c344203eSDavid van Moolenbroek 	 *
601c344203eSDavid van Moolenbroek 	 * A proper solution for these problems may consist of some form of
602c344203eSDavid van Moolenbroek 	 * "soft reference counting" where VFS does not count UDS having a
603c344203eSDavid van Moolenbroek 	 * filp open as a real reference.  That is tricky business, so for now
604c344203eSDavid van Moolenbroek 	 * we prevent any such problems with the check here.
605c344203eSDavid van Moolenbroek 	 */
606c344203eSDavid van Moolenbroek 	if ((vp = rfilp->filp_vno) != NULL && S_ISSOCK(vp->v_mode) &&
607c344203eSDavid van Moolenbroek 	    (sp = get_smap_by_dev(vp->v_sdev, NULL)) != NULL &&
608c344203eSDavid van Moolenbroek 	    sp->smap_endpt == who_e) {
609c344203eSDavid van Moolenbroek 		r = EDEADLK;
610c344203eSDavid van Moolenbroek 
611c344203eSDavid van Moolenbroek 		break;
612c344203eSDavid van Moolenbroek 	}
613c344203eSDavid van Moolenbroek 
614433d6423SLionel Sambuc 	rfp = fp;
61545443f35SDavid van Moolenbroek 	flags &= ~COPYFD_CLOEXEC;
616433d6423SLionel Sambuc 
617433d6423SLionel Sambuc 	/* FALLTHROUGH */
618433d6423SLionel Sambuc   case COPYFD_TO:
619433d6423SLionel Sambuc 	/* Find a free file descriptor slot in the local or remote process. */
620433d6423SLionel Sambuc 	for (fd = 0; fd < OPEN_MAX; fd++)
621433d6423SLionel Sambuc 		if (rfp->fp_filp[fd] == NULL)
622433d6423SLionel Sambuc 			break;
623433d6423SLionel Sambuc 
624433d6423SLionel Sambuc 	/* If found, fill the slot and return the slot number. */
625433d6423SLionel Sambuc 	if (fd < OPEN_MAX) {
626433d6423SLionel Sambuc 		rfp->fp_filp[fd] = rfilp;
62745443f35SDavid van Moolenbroek 		if (flags & COPYFD_CLOEXEC)
62845443f35SDavid van Moolenbroek 			FD_SET(fd, &rfp->fp_cloexec_set);
629433d6423SLionel Sambuc 		rfilp->filp_count++;
630433d6423SLionel Sambuc 		r = fd;
631433d6423SLionel Sambuc 	} else
632433d6423SLionel Sambuc 		r = EMFILE;
633433d6423SLionel Sambuc 
634433d6423SLionel Sambuc 	break;
635433d6423SLionel Sambuc 
636433d6423SLionel Sambuc   case COPYFD_CLOSE:
637433d6423SLionel Sambuc 	/* This should be used ONLY to revert a successful copy-to operation,
638433d6423SLionel Sambuc 	 * and assumes that the filp is still in use by the caller as well.
639433d6423SLionel Sambuc 	 */
640433d6423SLionel Sambuc 	if (rfilp->filp_count > 1) {
641433d6423SLionel Sambuc 		rfilp->filp_count--;
642433d6423SLionel Sambuc 		rfp->fp_filp[fd] = NULL;
643433d6423SLionel Sambuc 		r = OK;
644433d6423SLionel Sambuc 	} else
645433d6423SLionel Sambuc 		r = EBADF;
646433d6423SLionel Sambuc 
647433d6423SLionel Sambuc 	break;
648433d6423SLionel Sambuc 
649433d6423SLionel Sambuc   default:
650433d6423SLionel Sambuc 	r = EINVAL;
651433d6423SLionel Sambuc   }
652433d6423SLionel Sambuc 
653433d6423SLionel Sambuc   unlock_filp(rfilp);
654433d6423SLionel Sambuc 
655433d6423SLionel Sambuc   return(r);
656433d6423SLionel Sambuc }
657