xref: /minix3/minix/servers/vfs/open.c (revision 27852ebe53d5bf221cf5058cb7e858fa8fa8895e)
1433d6423SLionel Sambuc /* This file contains the procedures for creating, opening, closing, and
2433d6423SLionel Sambuc  * seeking on files.
3433d6423SLionel Sambuc  *
4433d6423SLionel Sambuc  * The entry points into this file are
5433d6423SLionel Sambuc  *   do_open:	perform the OPEN system call
6433d6423SLionel Sambuc  *   do_mknod:	perform the MKNOD system call
7433d6423SLionel Sambuc  *   do_mkdir:	perform the MKDIR system call
8433d6423SLionel Sambuc  *   do_close:	perform the CLOSE system call
9433d6423SLionel Sambuc  *   do_lseek:  perform the LSEEK system call
10433d6423SLionel Sambuc  */
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc #include "fs.h"
13433d6423SLionel Sambuc #include <sys/stat.h>
14433d6423SLionel Sambuc #include <fcntl.h>
15433d6423SLionel Sambuc #include <string.h>
16433d6423SLionel Sambuc #include <unistd.h>
17433d6423SLionel Sambuc #include <minix/callnr.h>
18433d6423SLionel Sambuc #include <minix/com.h>
19433d6423SLionel Sambuc #include <minix/u64.h>
20433d6423SLionel Sambuc #include "file.h"
21433d6423SLionel Sambuc #include "lock.h"
22433d6423SLionel Sambuc #include <sys/dirent.h>
23433d6423SLionel Sambuc #include <assert.h>
24433d6423SLionel Sambuc #include <minix/vfsif.h>
25433d6423SLionel Sambuc #include "vnode.h"
26433d6423SLionel Sambuc #include "vmnt.h"
27433d6423SLionel Sambuc #include "path.h"
28433d6423SLionel Sambuc 
29433d6423SLionel Sambuc static char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc static struct vnode *new_node(struct lookup *resolve, int oflags,
32433d6423SLionel Sambuc 	mode_t bits);
33232819ddSDavid van Moolenbroek static int pipe_open(int fd, struct vnode *vp, mode_t bits, int oflags);
34433d6423SLionel Sambuc 
35433d6423SLionel Sambuc /*===========================================================================*
36433d6423SLionel Sambuc  *				do_open					     *
37433d6423SLionel Sambuc  *===========================================================================*/
do_open(void)38433d6423SLionel Sambuc int do_open(void)
39433d6423SLionel Sambuc {
40433d6423SLionel Sambuc /* Perform the open(name, flags) system call with O_CREAT *not* set. */
41433d6423SLionel Sambuc   int open_flags;
42433d6423SLionel Sambuc   char fullpath[PATH_MAX];
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc   open_flags = job_m_in.m_lc_vfs_path.flags;
45433d6423SLionel Sambuc 
46433d6423SLionel Sambuc   if (open_flags & O_CREAT)
47433d6423SLionel Sambuc 	return EINVAL;
48433d6423SLionel Sambuc 
49433d6423SLionel Sambuc   if (copy_path(fullpath, sizeof(fullpath)) != OK)
50433d6423SLionel Sambuc 	return(err_code);
51433d6423SLionel Sambuc 
5256ac45c1SDavid van Moolenbroek   return common_open(fullpath, open_flags, 0 /*omode*/, FALSE /*for_exec*/);
53433d6423SLionel Sambuc }
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc /*===========================================================================*
56433d6423SLionel Sambuc  *				do_creat				     *
57433d6423SLionel Sambuc  *===========================================================================*/
do_creat(void)58433d6423SLionel Sambuc int do_creat(void)
59433d6423SLionel Sambuc {
60433d6423SLionel Sambuc /* Perform the open(name, flags, mode) system call with O_CREAT set. */
61433d6423SLionel Sambuc   int open_flags, create_mode;
62433d6423SLionel Sambuc   char fullpath[PATH_MAX];
63433d6423SLionel Sambuc   vir_bytes vname;
64433d6423SLionel Sambuc   size_t vname_length;
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc   vname = job_m_in.m_lc_vfs_creat.name;
67433d6423SLionel Sambuc   vname_length = job_m_in.m_lc_vfs_creat.len;
68433d6423SLionel Sambuc   open_flags = job_m_in.m_lc_vfs_creat.flags;
69433d6423SLionel Sambuc   create_mode = job_m_in.m_lc_vfs_creat.mode;
70433d6423SLionel Sambuc 
71433d6423SLionel Sambuc   if (!(open_flags & O_CREAT))
72433d6423SLionel Sambuc 	return(EINVAL);
73433d6423SLionel Sambuc 
74433d6423SLionel Sambuc   if (fetch_name(vname, vname_length, fullpath) != OK)
75433d6423SLionel Sambuc 	return(err_code);
76433d6423SLionel Sambuc 
7756ac45c1SDavid van Moolenbroek   return common_open(fullpath, open_flags, create_mode, FALSE /*for_exec*/);
78433d6423SLionel Sambuc }
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc /*===========================================================================*
81433d6423SLionel Sambuc  *				common_open				     *
82433d6423SLionel Sambuc  *===========================================================================*/
common_open(char path[PATH_MAX],int oflags,mode_t omode,int for_exec)8356ac45c1SDavid van Moolenbroek int common_open(char path[PATH_MAX], int oflags, mode_t omode, int for_exec)
84433d6423SLionel Sambuc {
85433d6423SLionel Sambuc /* Common code from do_creat and do_open. */
863b468884SDavid van Moolenbroek   int b, r, exist = TRUE;
873b468884SDavid van Moolenbroek   devmajor_t major_dev;
88433d6423SLionel Sambuc   dev_t dev;
89433d6423SLionel Sambuc   mode_t bits;
90433d6423SLionel Sambuc   struct filp *filp, *filp2;
91433d6423SLionel Sambuc   struct vnode *vp;
92433d6423SLionel Sambuc   struct vmnt *vmp;
93433d6423SLionel Sambuc   struct dmap *dp;
94433d6423SLionel Sambuc   struct lookup resolve;
95232819ddSDavid van Moolenbroek   int fd, start = 0;
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc   /* Remap the bottom two bits of oflags. */
98433d6423SLionel Sambuc   bits = (mode_t) mode_map[oflags & O_ACCMODE];
99433d6423SLionel Sambuc   if (!bits) return(EINVAL);
100433d6423SLionel Sambuc 
101433d6423SLionel Sambuc   /* See if file descriptor and filp slots are available. */
102232819ddSDavid van Moolenbroek   if ((r = get_fd(fp, start, bits, &fd, &filp)) != OK)
103433d6423SLionel Sambuc 	return(r);
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc   lookup_init(&resolve, path, PATH_NOFLAGS, &vmp, &vp);
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc   /* If O_CREATE is set, try to make the file. */
108433d6423SLionel Sambuc   if (oflags & O_CREAT) {
109433d6423SLionel Sambuc         omode = I_REGULAR | (omode & ALLPERMS & fp->fp_umask);
110433d6423SLionel Sambuc 	vp = new_node(&resolve, oflags, omode);
111433d6423SLionel Sambuc 	r = err_code;
112433d6423SLionel Sambuc 	if (r == OK) exist = FALSE;	/* We just created the file */
113433d6423SLionel Sambuc 	else if (r != EEXIST) {		/* other error */
114433d6423SLionel Sambuc 		if (vp) unlock_vnode(vp);
115433d6423SLionel Sambuc 		unlock_filp(filp);
116433d6423SLionel Sambuc 		return(r);
117433d6423SLionel Sambuc 	}
118433d6423SLionel Sambuc 	else exist = !(oflags & O_EXCL);/* file exists, if the O_EXCL
119433d6423SLionel Sambuc 					   flag is set this is an error */
120433d6423SLionel Sambuc   } else {
121433d6423SLionel Sambuc 	/* Scan path name */
122433d6423SLionel Sambuc 	resolve.l_vmnt_lock = VMNT_READ;
123433d6423SLionel Sambuc 	resolve.l_vnode_lock = VNODE_OPCL;
124433d6423SLionel Sambuc 	if ((vp = eat_path(&resolve, fp)) == NULL) {
125433d6423SLionel Sambuc 		unlock_filp(filp);
126433d6423SLionel Sambuc 		return(err_code);
127433d6423SLionel Sambuc 	}
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc 	if (vmp != NULL) unlock_vmnt(vmp);
130433d6423SLionel Sambuc   }
131433d6423SLionel Sambuc 
132433d6423SLionel Sambuc   /* Claim the file descriptor and filp slot and fill them in. */
133232819ddSDavid van Moolenbroek   fp->fp_filp[fd] = filp;
134433d6423SLionel Sambuc   filp->filp_count = 1;
135433d6423SLionel Sambuc   filp->filp_vno = vp;
136433d6423SLionel Sambuc   filp->filp_flags = oflags;
137433d6423SLionel Sambuc   if (oflags & O_CLOEXEC)
138232819ddSDavid van Moolenbroek 	FD_SET(fd, &fp->fp_cloexec_set);
139433d6423SLionel Sambuc 
140433d6423SLionel Sambuc   /* Only do the normal open code if we didn't just create the file. */
141433d6423SLionel Sambuc   if (exist) {
14256ac45c1SDavid van Moolenbroek 	/* Check permissions based on the given open flags, except when we are
14356ac45c1SDavid van Moolenbroek 	 * opening an executable for the purpose of passing a file descriptor
14456ac45c1SDavid van Moolenbroek 	 * to its interpreter for execution, in which case we check the X bit.
14556ac45c1SDavid van Moolenbroek 	 */
14656ac45c1SDavid van Moolenbroek 	if ((r = forbidden(fp, vp, for_exec ? X_BIT : bits)) == OK) {
147433d6423SLionel Sambuc 		/* Opening reg. files, directories, and special files differ */
148433d6423SLionel Sambuc 		switch (vp->v_mode & S_IFMT) {
149433d6423SLionel Sambuc 		   case S_IFREG:
150433d6423SLionel Sambuc 			/* Truncate regular file if O_TRUNC. */
151433d6423SLionel Sambuc 			if (oflags & O_TRUNC) {
152433d6423SLionel Sambuc 				if ((r = forbidden(fp, vp, W_BIT)) != OK)
153433d6423SLionel Sambuc 					break;
154433d6423SLionel Sambuc 				upgrade_vnode_lock(vp);
155433d6423SLionel Sambuc 				truncate_vnode(vp, 0);
156433d6423SLionel Sambuc 			}
157433d6423SLionel Sambuc 			break;
158433d6423SLionel Sambuc 		   case S_IFDIR:
159433d6423SLionel Sambuc 			/* Directories may be read but not written. */
160433d6423SLionel Sambuc 			r = (bits & W_BIT ? EISDIR : OK);
161433d6423SLionel Sambuc 			break;
162433d6423SLionel Sambuc 		   case S_IFCHR:
163433d6423SLionel Sambuc 			/* Invoke the driver for special processing. */
164433d6423SLionel Sambuc 			dev = vp->v_sdev;
165433d6423SLionel Sambuc 			/* TTY needs to know about the O_NOCTTY flag. */
166232819ddSDavid van Moolenbroek 			r = cdev_open(fd, dev, bits | (oflags & O_NOCTTY));
167433d6423SLionel Sambuc 			vp = filp->filp_vno;	/* Might be updated by
168433d6423SLionel Sambuc 						 * cdev_open after cloning */
169433d6423SLionel Sambuc 			break;
170433d6423SLionel Sambuc 		   case S_IFBLK:
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc 			lock_bsf();
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc 			/* Invoke the driver for special processing. */
175433d6423SLionel Sambuc 			dev = vp->v_sdev;
176433d6423SLionel Sambuc 			r = bdev_open(dev, bits);
177433d6423SLionel Sambuc 			if (r != OK) {
178433d6423SLionel Sambuc 				unlock_bsf();
179433d6423SLionel Sambuc 				break;
180433d6423SLionel Sambuc 			}
181433d6423SLionel Sambuc 
182433d6423SLionel Sambuc 			major_dev = major(vp->v_sdev);
183433d6423SLionel Sambuc 			dp = &dmap[major_dev];
184433d6423SLionel Sambuc 			if (dp->dmap_driver == NONE) {
185433d6423SLionel Sambuc 				printf("VFS: block driver disappeared!\n");
186433d6423SLionel Sambuc 				unlock_bsf();
187433d6423SLionel Sambuc 				r = ENXIO;
188433d6423SLionel Sambuc 				break;
189433d6423SLionel Sambuc 			}
190433d6423SLionel Sambuc 
191433d6423SLionel Sambuc 			/* Check whether the device is mounted or not. If so,
192433d6423SLionel Sambuc 			 * then that FS is responsible for this device.
193433d6423SLionel Sambuc 			 * Otherwise we default to ROOT_FS.
194433d6423SLionel Sambuc 			 */
195433d6423SLionel Sambuc 			vp->v_bfs_e = ROOT_FS_E; /* By default */
196433d6423SLionel Sambuc 			for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp)
197433d6423SLionel Sambuc 				if (vmp->m_dev == vp->v_sdev &&
198433d6423SLionel Sambuc 				    !(vmp->m_flags & VMNT_FORCEROOTBSF)) {
199433d6423SLionel Sambuc 					vp->v_bfs_e = vmp->m_fs_e;
200433d6423SLionel Sambuc 				}
201433d6423SLionel Sambuc 
202433d6423SLionel Sambuc 			/* Send the driver label to the file system that will
203433d6423SLionel Sambuc 			 * handle the block I/O requests (even when its label
204433d6423SLionel Sambuc 			 * and endpoint are known already), but only when it is
205433d6423SLionel Sambuc 			 * the root file system. Other file systems will
206433d6423SLionel Sambuc 			 * already have it anyway.
207433d6423SLionel Sambuc 			 */
208433d6423SLionel Sambuc 			if (vp->v_bfs_e != ROOT_FS_E) {
209433d6423SLionel Sambuc 				unlock_bsf();
210433d6423SLionel Sambuc 				break;
211433d6423SLionel Sambuc 			}
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc 			if (req_newdriver(vp->v_bfs_e, vp->v_sdev,
214433d6423SLionel Sambuc 					dp->dmap_label) != OK) {
215433d6423SLionel Sambuc 				printf("VFS: error sending driver label\n");
216433d6423SLionel Sambuc 				bdev_close(dev);
217433d6423SLionel Sambuc 				r = ENXIO;
218433d6423SLionel Sambuc 			}
219433d6423SLionel Sambuc 			unlock_bsf();
220433d6423SLionel Sambuc 			break;
221433d6423SLionel Sambuc 
222433d6423SLionel Sambuc 		   case S_IFIFO:
223433d6423SLionel Sambuc 			/* Create a mapped inode on PFS which handles reads
224433d6423SLionel Sambuc 			   and writes to this named pipe. */
225433d6423SLionel Sambuc 			upgrade_vnode_lock(vp);
226433d6423SLionel Sambuc 			r = map_vnode(vp, PFS_PROC_NR);
227433d6423SLionel Sambuc 			if (r == OK) {
228433d6423SLionel Sambuc 				if (vp->v_ref_count == 1) {
229433d6423SLionel Sambuc 					if (vp->v_size != 0)
230433d6423SLionel Sambuc 						r = truncate_vnode(vp, 0);
231433d6423SLionel Sambuc 				}
232433d6423SLionel Sambuc 				oflags |= O_APPEND;	/* force append mode */
233433d6423SLionel Sambuc 				filp->filp_flags = oflags;
234433d6423SLionel Sambuc 			}
235433d6423SLionel Sambuc 			if (r == OK) {
236232819ddSDavid van Moolenbroek 				r = pipe_open(fd, vp, bits, oflags);
237433d6423SLionel Sambuc 			}
238433d6423SLionel Sambuc 			if (r != ENXIO) {
239433d6423SLionel Sambuc 				/* See if someone else is doing a rd or wt on
240433d6423SLionel Sambuc 				 * the FIFO.  If so, use its filp entry so the
241433d6423SLionel Sambuc 				 * file position will be automatically shared.
242433d6423SLionel Sambuc 				 */
243433d6423SLionel Sambuc 				b = (bits & R_BIT ? R_BIT : W_BIT);
244433d6423SLionel Sambuc 				filp->filp_count = 0; /* don't find self */
245433d6423SLionel Sambuc 				if ((filp2 = find_filp(vp, b)) != NULL) {
246433d6423SLionel Sambuc 				    /* Co-reader or writer found. Use it.*/
247232819ddSDavid van Moolenbroek 				    fp->fp_filp[fd] = filp2;
248433d6423SLionel Sambuc 				    filp2->filp_count++;
249433d6423SLionel Sambuc 				    filp2->filp_vno = vp;
250433d6423SLionel Sambuc 				    filp2->filp_flags = oflags;
251433d6423SLionel Sambuc 
252433d6423SLionel Sambuc 				    /* v_count was incremented after the vnode
253433d6423SLionel Sambuc 				     * has been found. i_count was incremented
254433d6423SLionel Sambuc 				     * incorrectly in FS, not knowing that we
255433d6423SLionel Sambuc 				     * were going to use an existing filp
256433d6423SLionel Sambuc 				     * entry.  Correct this error.
257433d6423SLionel Sambuc 				     */
258433d6423SLionel Sambuc 				    unlock_vnode(vp);
259433d6423SLionel Sambuc 				    put_vnode(vp);
260433d6423SLionel Sambuc 				} else {
261433d6423SLionel Sambuc 				    /* Nobody else found. Restore filp. */
262433d6423SLionel Sambuc 				    filp->filp_count = 1;
263433d6423SLionel Sambuc 				}
264433d6423SLionel Sambuc 			}
265433d6423SLionel Sambuc 			break;
2660eb6caa0SDavid van Moolenbroek 		   case S_IFSOCK:
2670eb6caa0SDavid van Moolenbroek 			r = EOPNOTSUPP;
2680eb6caa0SDavid van Moolenbroek 			break;
2690eb6caa0SDavid van Moolenbroek 		   default:
2700eb6caa0SDavid van Moolenbroek 			printf("VFS: attempt to open file <%llu,%llu> of "
2710eb6caa0SDavid van Moolenbroek 			    "type 0%o\n", vp->v_dev, vp->v_inode_nr,
2720eb6caa0SDavid van Moolenbroek 			    vp->v_mode & S_IFMT);
2730eb6caa0SDavid van Moolenbroek 			r = EIO;
274433d6423SLionel Sambuc 		}
275433d6423SLionel Sambuc 	}
276433d6423SLionel Sambuc   }
277433d6423SLionel Sambuc 
278433d6423SLionel Sambuc   unlock_filp(filp);
279433d6423SLionel Sambuc 
280433d6423SLionel Sambuc   /* If error, release inode. */
281433d6423SLionel Sambuc   if (r != OK) {
282433d6423SLionel Sambuc 	if (r != SUSPEND) {
283232819ddSDavid van Moolenbroek 		fp->fp_filp[fd] = NULL;
284433d6423SLionel Sambuc 		filp->filp_count = 0;
285433d6423SLionel Sambuc 		filp->filp_vno = NULL;
286433d6423SLionel Sambuc 		put_vnode(vp);
287433d6423SLionel Sambuc 	}
288433d6423SLionel Sambuc   } else {
289232819ddSDavid van Moolenbroek 	r = fd;
290433d6423SLionel Sambuc   }
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc   return(r);
293433d6423SLionel Sambuc }
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc 
296433d6423SLionel Sambuc /*===========================================================================*
297433d6423SLionel Sambuc  *				new_node				     *
298433d6423SLionel Sambuc  *===========================================================================*/
new_node(struct lookup * resolve,int oflags,mode_t bits)299433d6423SLionel Sambuc static struct vnode *new_node(struct lookup *resolve, int oflags, mode_t bits)
300433d6423SLionel Sambuc {
301433d6423SLionel Sambuc /* Try to create a new inode and return a pointer to it. If the inode already
302433d6423SLionel Sambuc    exists, return a pointer to it as well, but set err_code accordingly.
303433d6423SLionel Sambuc    NULL is returned if the path cannot be resolved up to the last
304433d6423SLionel Sambuc    directory, or when the inode cannot be created due to permissions or
305433d6423SLionel Sambuc    otherwise. */
306433d6423SLionel Sambuc   struct vnode *dirp, *vp;
307433d6423SLionel Sambuc   struct vmnt *dir_vmp, *vp_vmp;
308433d6423SLionel Sambuc   int r;
309433d6423SLionel Sambuc   struct node_details res;
310433d6423SLionel Sambuc   struct lookup findnode;
311433d6423SLionel Sambuc   char *path;
312433d6423SLionel Sambuc 
313433d6423SLionel Sambuc   path = resolve->l_path;	/* For easy access */
314433d6423SLionel Sambuc 
315433d6423SLionel Sambuc   lookup_init(&findnode, path, resolve->l_flags, &dir_vmp, &dirp);
316433d6423SLionel Sambuc   findnode.l_vmnt_lock = VMNT_WRITE;
317433d6423SLionel Sambuc   findnode.l_vnode_lock = VNODE_WRITE; /* dir node */
318433d6423SLionel Sambuc 
319433d6423SLionel Sambuc   /* When O_CREAT and O_EXCL flags are set, the path may not be named by a
320433d6423SLionel Sambuc    * symbolic link. */
321433d6423SLionel Sambuc   if (oflags & O_EXCL) findnode.l_flags |= PATH_RET_SYMLINK;
322433d6423SLionel Sambuc 
323433d6423SLionel Sambuc   /* See if the path can be opened down to the last directory. */
324433d6423SLionel Sambuc   if ((dirp = last_dir(&findnode, fp)) == NULL) return(NULL);
325433d6423SLionel Sambuc 
326433d6423SLionel Sambuc   /* The final directory is accessible. Get final component of the path. */
327433d6423SLionel Sambuc   lookup_init(&findnode, findnode.l_path, findnode.l_flags, &vp_vmp, &vp);
328433d6423SLionel Sambuc   findnode.l_vmnt_lock = VMNT_WRITE;
329433d6423SLionel Sambuc   findnode.l_vnode_lock = (oflags & O_TRUNC) ? VNODE_WRITE : VNODE_OPCL;
330433d6423SLionel Sambuc   vp = advance(dirp, &findnode, fp);
331433d6423SLionel Sambuc   assert(vp_vmp == NULL);	/* Lookup to last dir should have yielded lock
332433d6423SLionel Sambuc 				 * on vmp or final component does not exist.
333433d6423SLionel Sambuc 				 * Either way, vp_vmp ought to be not set.
334433d6423SLionel Sambuc 				 */
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc   /* The combination of a symlink with absolute path followed by a danglink
337433d6423SLionel Sambuc    * symlink results in a new path that needs to be re-resolved entirely. */
338433d6423SLionel Sambuc   if (path[0] == '/') {
339433d6423SLionel Sambuc 	unlock_vnode(dirp);
340433d6423SLionel Sambuc 	unlock_vmnt(dir_vmp);
341433d6423SLionel Sambuc 	put_vnode(dirp);
342433d6423SLionel Sambuc 	if (vp != NULL) {
343433d6423SLionel Sambuc 		unlock_vnode(vp);
344433d6423SLionel Sambuc 		put_vnode(vp);
345433d6423SLionel Sambuc 	}
346433d6423SLionel Sambuc 	return new_node(resolve, oflags, bits);
347433d6423SLionel Sambuc   }
348433d6423SLionel Sambuc 
349433d6423SLionel Sambuc   if (vp == NULL && err_code == ENOENT) {
350433d6423SLionel Sambuc 	/* Last path component does not exist. Make a new directory entry. */
351433d6423SLionel Sambuc 	if ((vp = get_free_vnode()) == NULL) {
352433d6423SLionel Sambuc 		/* Can't create new entry: out of vnodes. */
353433d6423SLionel Sambuc 		unlock_vnode(dirp);
354433d6423SLionel Sambuc 		unlock_vmnt(dir_vmp);
355433d6423SLionel Sambuc 		put_vnode(dirp);
356433d6423SLionel Sambuc 		return(NULL);
357433d6423SLionel Sambuc 	}
358433d6423SLionel Sambuc 
359433d6423SLionel Sambuc 	lock_vnode(vp, VNODE_OPCL);
360433d6423SLionel Sambuc 	upgrade_vmnt_lock(dir_vmp); /* Creating file, need exclusive access */
361433d6423SLionel Sambuc 
362433d6423SLionel Sambuc 	if ((r = forbidden(fp, dirp, W_BIT|X_BIT)) != OK ||
363433d6423SLionel Sambuc 	    (r = req_create(dirp->v_fs_e, dirp->v_inode_nr,bits, fp->fp_effuid,
364433d6423SLionel Sambuc 			    fp->fp_effgid, path, &res)) != OK ) {
365433d6423SLionel Sambuc 		/* Can't create inode either due to permissions or some other
366433d6423SLionel Sambuc 		 * problem. In case r is EEXIST, we might be dealing with a
367433d6423SLionel Sambuc 		 * dangling symlink.*/
368433d6423SLionel Sambuc 
369433d6423SLionel Sambuc 		/* Downgrade lock to prevent deadlock during symlink resolving*/
370433d6423SLionel Sambuc 		downgrade_vmnt_lock(dir_vmp);
371433d6423SLionel Sambuc 
372433d6423SLionel Sambuc 		if (r == EEXIST) {
373433d6423SLionel Sambuc 			struct vnode *slp, *old_wd;
374433d6423SLionel Sambuc 
375433d6423SLionel Sambuc 
376433d6423SLionel Sambuc 			/* Resolve path up to symlink */
377433d6423SLionel Sambuc 			findnode.l_flags = PATH_RET_SYMLINK;
378433d6423SLionel Sambuc 			findnode.l_vnode_lock = VNODE_READ;
379433d6423SLionel Sambuc 			findnode.l_vnode = &slp;
380433d6423SLionel Sambuc 			slp = advance(dirp, &findnode, fp);
381433d6423SLionel Sambuc 			if (slp != NULL) {
382433d6423SLionel Sambuc 				if (S_ISLNK(slp->v_mode)) {
383433d6423SLionel Sambuc 					/* Get contents of link */
384433d6423SLionel Sambuc 
385433d6423SLionel Sambuc 					r = req_rdlink(slp->v_fs_e,
386433d6423SLionel Sambuc 						       slp->v_inode_nr,
387433d6423SLionel Sambuc 						       VFS_PROC_NR,
388433d6423SLionel Sambuc 						       (vir_bytes) path,
389433d6423SLionel Sambuc 						       PATH_MAX - 1, 0);
390433d6423SLionel Sambuc 					if (r < 0) {
391433d6423SLionel Sambuc 						/* Failed to read link */
392433d6423SLionel Sambuc 						unlock_vnode(slp);
393433d6423SLionel Sambuc 						unlock_vnode(dirp);
394433d6423SLionel Sambuc 						unlock_vmnt(dir_vmp);
395433d6423SLionel Sambuc 						put_vnode(slp);
396433d6423SLionel Sambuc 						put_vnode(dirp);
397433d6423SLionel Sambuc 						err_code = r;
398433d6423SLionel Sambuc 						return(NULL);
399433d6423SLionel Sambuc 					}
400433d6423SLionel Sambuc 					path[r] = '\0'; /* Terminate path */
401433d6423SLionel Sambuc 				}
402433d6423SLionel Sambuc 				unlock_vnode(slp);
403433d6423SLionel Sambuc 				put_vnode(slp);
404433d6423SLionel Sambuc 			}
405433d6423SLionel Sambuc 
406433d6423SLionel Sambuc 			/* Try to create the inode the dangling symlink was
407433d6423SLionel Sambuc 			 * pointing to. We have to use dirp as starting point
408433d6423SLionel Sambuc 			 * as there might be multiple successive symlinks
409433d6423SLionel Sambuc 			 * crossing multiple mountpoints.
410433d6423SLionel Sambuc 			 * Unlock vnodes and vmnts as we're going to recurse.
411433d6423SLionel Sambuc 			 */
412433d6423SLionel Sambuc 			unlock_vnode(dirp);
413433d6423SLionel Sambuc 			unlock_vnode(vp);
414433d6423SLionel Sambuc 			unlock_vmnt(dir_vmp);
415433d6423SLionel Sambuc 
416433d6423SLionel Sambuc 			old_wd = fp->fp_wd; /* Save orig. working dirp */
417433d6423SLionel Sambuc 			fp->fp_wd = dirp;
418433d6423SLionel Sambuc 			vp = new_node(resolve, oflags, bits);
419433d6423SLionel Sambuc 			fp->fp_wd = old_wd; /* Restore */
420433d6423SLionel Sambuc 
421433d6423SLionel Sambuc 			if (vp != NULL) {
422433d6423SLionel Sambuc 				put_vnode(dirp);
423433d6423SLionel Sambuc 				*(resolve->l_vnode) = vp;
424433d6423SLionel Sambuc 				return(vp);
425433d6423SLionel Sambuc 			}
426433d6423SLionel Sambuc 			r = err_code;
427433d6423SLionel Sambuc 		}
428433d6423SLionel Sambuc 
429433d6423SLionel Sambuc 		if (r == EEXIST)
430433d6423SLionel Sambuc 			err_code = EIO; /* Impossible, we have verified that
431433d6423SLionel Sambuc 					 * the last component doesn't exist and
432433d6423SLionel Sambuc 					 * is not a dangling symlink. */
433433d6423SLionel Sambuc 		else
434433d6423SLionel Sambuc 			err_code = r;
435433d6423SLionel Sambuc 
436433d6423SLionel Sambuc 		unlock_vmnt(dir_vmp);
437433d6423SLionel Sambuc 		unlock_vnode(dirp);
438433d6423SLionel Sambuc 		unlock_vnode(vp);
439433d6423SLionel Sambuc 		put_vnode(dirp);
440433d6423SLionel Sambuc 		return(NULL);
441433d6423SLionel Sambuc 	}
442433d6423SLionel Sambuc 
443433d6423SLionel Sambuc 	/* Store results and mark vnode in use */
444433d6423SLionel Sambuc 
445433d6423SLionel Sambuc 	vp->v_fs_e = res.fs_e;
446433d6423SLionel Sambuc 	vp->v_inode_nr = res.inode_nr;
447433d6423SLionel Sambuc 	vp->v_mode = res.fmode;
448433d6423SLionel Sambuc 	vp->v_size = res.fsize;
449433d6423SLionel Sambuc 	vp->v_uid = res.uid;
450433d6423SLionel Sambuc 	vp->v_gid = res.gid;
451433d6423SLionel Sambuc 	vp->v_sdev = res.dev;
452433d6423SLionel Sambuc 	vp->v_vmnt = dirp->v_vmnt;
453433d6423SLionel Sambuc 	vp->v_dev = vp->v_vmnt->m_dev;
454433d6423SLionel Sambuc 	vp->v_fs_count = 1;
455433d6423SLionel Sambuc 	vp->v_ref_count = 1;
456433d6423SLionel Sambuc   } else {
457433d6423SLionel Sambuc 	/* Either last component exists, or there is some other problem. */
458433d6423SLionel Sambuc 	if (vp != NULL) {
459433d6423SLionel Sambuc 		r = EEXIST;	/* File exists or a symlink names a file while
460433d6423SLionel Sambuc 				 * O_EXCL is set. */
461433d6423SLionel Sambuc 	} else
462433d6423SLionel Sambuc 		r = err_code;	/* Other problem. */
463433d6423SLionel Sambuc   }
464433d6423SLionel Sambuc 
465433d6423SLionel Sambuc   err_code = r;
466433d6423SLionel Sambuc   /* When dirp equals vp, we shouldn't release the lock as a vp is locked only
467433d6423SLionel Sambuc    * once. Releasing the lock would cause the resulting vp not be locked and
468433d6423SLionel Sambuc    * cause mayhem later on. */
469433d6423SLionel Sambuc   if (dirp != vp) {
470433d6423SLionel Sambuc 	unlock_vnode(dirp);
471433d6423SLionel Sambuc   }
472433d6423SLionel Sambuc   unlock_vmnt(dir_vmp);
473433d6423SLionel Sambuc   put_vnode(dirp);
474433d6423SLionel Sambuc 
475433d6423SLionel Sambuc   *(resolve->l_vnode) = vp;
476433d6423SLionel Sambuc   return(vp);
477433d6423SLionel Sambuc }
478433d6423SLionel Sambuc 
479433d6423SLionel Sambuc 
480433d6423SLionel Sambuc /*===========================================================================*
481433d6423SLionel Sambuc  *				pipe_open				     *
482433d6423SLionel Sambuc  *===========================================================================*/
pipe_open(int fd,struct vnode * vp,mode_t bits,int oflags)483232819ddSDavid van Moolenbroek static int pipe_open(int fd, struct vnode *vp, mode_t bits, int oflags)
484433d6423SLionel Sambuc {
485433d6423SLionel Sambuc /*  This function is called from common_open. It checks if
486433d6423SLionel Sambuc  *  there is at least one reader/writer pair for the pipe, if not
487433d6423SLionel Sambuc  *  it suspends the caller, otherwise it revives all other blocked
488433d6423SLionel Sambuc  *  processes hanging on the pipe.
489433d6423SLionel Sambuc  */
490433d6423SLionel Sambuc 
491433d6423SLionel Sambuc   if ((bits & (R_BIT|W_BIT)) == (R_BIT|W_BIT)) return(ENXIO);
492433d6423SLionel Sambuc 
493433d6423SLionel Sambuc   /* Find the reader/writer at the other end of the pipe */
494433d6423SLionel Sambuc   if (find_filp(vp, bits & W_BIT ? R_BIT : W_BIT) == NULL) {
495433d6423SLionel Sambuc 	/* Not found */
496433d6423SLionel Sambuc 	if (oflags & O_NONBLOCK) {
497433d6423SLionel Sambuc 		if (bits & W_BIT) return(ENXIO);
498433d6423SLionel Sambuc 	} else {
499433d6423SLionel Sambuc 		/* Let's wait for the other side to show up */
500232819ddSDavid van Moolenbroek 		fp->fp_popen.fd = fd;
501433d6423SLionel Sambuc 		suspend(FP_BLOCKED_ON_POPEN);
502433d6423SLionel Sambuc 		return(SUSPEND);
503433d6423SLionel Sambuc 	}
504433d6423SLionel Sambuc   } else if (susp_count > 0) { /* revive blocked processes */
505433d6423SLionel Sambuc 	release(vp, VFS_OPEN, susp_count);
506433d6423SLionel Sambuc   }
507433d6423SLionel Sambuc   return(OK);
508433d6423SLionel Sambuc }
509433d6423SLionel Sambuc 
510433d6423SLionel Sambuc 
511433d6423SLionel Sambuc /*===========================================================================*
512433d6423SLionel Sambuc  *				do_mknod				     *
513433d6423SLionel Sambuc  *===========================================================================*/
do_mknod(void)514433d6423SLionel Sambuc int do_mknod(void)
515433d6423SLionel Sambuc {
516433d6423SLionel Sambuc /* Perform the mknod(name, mode, addr) system call. */
517433d6423SLionel Sambuc   register mode_t bits, mode_bits;
518433d6423SLionel Sambuc   int r;
519433d6423SLionel Sambuc   struct vnode *vp;
520433d6423SLionel Sambuc   struct vmnt *vmp;
521433d6423SLionel Sambuc   char fullpath[PATH_MAX];
522433d6423SLionel Sambuc   struct lookup resolve;
523433d6423SLionel Sambuc   vir_bytes vname1;
524433d6423SLionel Sambuc   size_t vname1_length;
525433d6423SLionel Sambuc   dev_t dev;
526433d6423SLionel Sambuc 
527433d6423SLionel Sambuc   vname1 = job_m_in.m_lc_vfs_mknod.name;
528433d6423SLionel Sambuc   vname1_length = job_m_in.m_lc_vfs_mknod.len;
529433d6423SLionel Sambuc   mode_bits = job_m_in.m_lc_vfs_mknod.mode;
530433d6423SLionel Sambuc   dev = job_m_in.m_lc_vfs_mknod.device;
531433d6423SLionel Sambuc 
532a758ec67SDavid van Moolenbroek   /* If the path names a symbolic link, mknod() shall fail with EEXIST. */
533a758ec67SDavid van Moolenbroek   lookup_init(&resolve, fullpath, PATH_RET_SYMLINK, &vmp, &vp);
534433d6423SLionel Sambuc   resolve.l_vmnt_lock = VMNT_WRITE;
535433d6423SLionel Sambuc   resolve.l_vnode_lock = VNODE_WRITE;
536433d6423SLionel Sambuc 
537433d6423SLionel Sambuc   /* Only the super_user may make nodes other than fifos. */
538*27852ebeSDavid van Moolenbroek   if (!super_user && !S_ISFIFO(mode_bits))
539433d6423SLionel Sambuc 	return(EPERM);
540*27852ebeSDavid van Moolenbroek 
541433d6423SLionel Sambuc   bits = (mode_bits & S_IFMT) | (mode_bits & ACCESSPERMS & fp->fp_umask);
542433d6423SLionel Sambuc 
543433d6423SLionel Sambuc   /* Open directory that's going to hold the new node. */
544433d6423SLionel Sambuc   if (fetch_name(vname1, vname1_length, fullpath) != OK) return(err_code);
545433d6423SLionel Sambuc   if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code);
546433d6423SLionel Sambuc 
547433d6423SLionel Sambuc   /* Make sure that the object is a directory */
548433d6423SLionel Sambuc   if (!S_ISDIR(vp->v_mode)) {
549433d6423SLionel Sambuc 	r = ENOTDIR;
550433d6423SLionel Sambuc   } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) {
551433d6423SLionel Sambuc 	r = req_mknod(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid,
552433d6423SLionel Sambuc 		      fp->fp_effgid, bits, dev);
553433d6423SLionel Sambuc   }
554433d6423SLionel Sambuc 
555433d6423SLionel Sambuc   unlock_vnode(vp);
556433d6423SLionel Sambuc   unlock_vmnt(vmp);
557433d6423SLionel Sambuc   put_vnode(vp);
558433d6423SLionel Sambuc   return(r);
559433d6423SLionel Sambuc }
560433d6423SLionel Sambuc 
561433d6423SLionel Sambuc /*===========================================================================*
562433d6423SLionel Sambuc  *				do_mkdir				     *
563433d6423SLionel Sambuc  *===========================================================================*/
do_mkdir(void)564433d6423SLionel Sambuc int do_mkdir(void)
565433d6423SLionel Sambuc {
566433d6423SLionel Sambuc /* Perform the mkdir(name, mode) system call. */
567433d6423SLionel Sambuc   mode_t bits;			/* mode bits for the new inode */
568433d6423SLionel Sambuc   int r;
569433d6423SLionel Sambuc   struct vnode *vp;
570433d6423SLionel Sambuc   struct vmnt *vmp;
571433d6423SLionel Sambuc   char fullpath[PATH_MAX];
572433d6423SLionel Sambuc   struct lookup resolve;
573433d6423SLionel Sambuc   mode_t dirmode;
574433d6423SLionel Sambuc 
575433d6423SLionel Sambuc   if (copy_path(fullpath, sizeof(fullpath)) != OK)
576433d6423SLionel Sambuc 	return(err_code);
577433d6423SLionel Sambuc   dirmode = job_m_in.m_lc_vfs_path.mode;
578433d6423SLionel Sambuc 
579433d6423SLionel Sambuc   lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp);
580433d6423SLionel Sambuc   resolve.l_vmnt_lock = VMNT_WRITE;
581433d6423SLionel Sambuc   resolve.l_vnode_lock = VNODE_WRITE;
582433d6423SLionel Sambuc 
583433d6423SLionel Sambuc   bits = I_DIRECTORY | (dirmode & RWX_MODES & fp->fp_umask);
584433d6423SLionel Sambuc   if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code);
585433d6423SLionel Sambuc 
586433d6423SLionel Sambuc   /* Make sure that the object is a directory */
587433d6423SLionel Sambuc   if (!S_ISDIR(vp->v_mode)) {
588433d6423SLionel Sambuc 	r = ENOTDIR;
589433d6423SLionel Sambuc   } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) {
590433d6423SLionel Sambuc 	r = req_mkdir(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid,
591433d6423SLionel Sambuc 		      fp->fp_effgid, bits);
592433d6423SLionel Sambuc   }
593433d6423SLionel Sambuc 
594433d6423SLionel Sambuc   unlock_vnode(vp);
595433d6423SLionel Sambuc   unlock_vmnt(vmp);
596433d6423SLionel Sambuc   put_vnode(vp);
597433d6423SLionel Sambuc   return(r);
598433d6423SLionel Sambuc }
599433d6423SLionel Sambuc 
600433d6423SLionel Sambuc /*===========================================================================*
601433d6423SLionel Sambuc  *				actual_lseek				     *
602433d6423SLionel Sambuc  *===========================================================================*/
actual_lseek(struct fproc * rfp,int seekfd,int seekwhence,off_t offset,off_t * newposp)603433d6423SLionel Sambuc int actual_lseek(struct fproc *rfp, int seekfd, int seekwhence, off_t offset,
604433d6423SLionel Sambuc 	off_t *newposp)
605433d6423SLionel Sambuc {
606433d6423SLionel Sambuc   register struct filp *rfilp;
607433d6423SLionel Sambuc   int r = OK;
608433d6423SLionel Sambuc   off_t pos, newpos;
609433d6423SLionel Sambuc 
610433d6423SLionel Sambuc   /* Check to see if the file descriptor is valid. */
611433d6423SLionel Sambuc   if ( (rfilp = get_filp2(rfp, seekfd, VNODE_READ)) == NULL) {
612433d6423SLionel Sambuc 	return(err_code);
613433d6423SLionel Sambuc   }
614433d6423SLionel Sambuc 
615433d6423SLionel Sambuc   /* No lseek on pipes. */
616433d6423SLionel Sambuc   if (S_ISFIFO(rfilp->filp_vno->v_mode)) {
617433d6423SLionel Sambuc 	unlock_filp(rfilp);
618433d6423SLionel Sambuc 	return(ESPIPE);
619433d6423SLionel Sambuc   }
620433d6423SLionel Sambuc 
621433d6423SLionel Sambuc   /* The value of 'whence' determines the start position to use. */
622433d6423SLionel Sambuc   switch(seekwhence) {
623433d6423SLionel Sambuc     case SEEK_SET: pos = 0; break;
624433d6423SLionel Sambuc     case SEEK_CUR: pos = rfilp->filp_pos; break;
625433d6423SLionel Sambuc     case SEEK_END: pos = rfilp->filp_vno->v_size; break;
626433d6423SLionel Sambuc     default: unlock_filp(rfilp); return(EINVAL);
627433d6423SLionel Sambuc   }
628433d6423SLionel Sambuc 
629433d6423SLionel Sambuc   newpos = pos + offset;
630433d6423SLionel Sambuc 
631433d6423SLionel Sambuc   /* Check for overflow. */
632433d6423SLionel Sambuc   if ((offset > 0) && (newpos <= pos)) {
633433d6423SLionel Sambuc 	r = EOVERFLOW;
634433d6423SLionel Sambuc   } else if ((offset < 0) && (newpos >= pos)) {
635433d6423SLionel Sambuc 	r = EOVERFLOW;
636433d6423SLionel Sambuc   } else {
637433d6423SLionel Sambuc 	if (newposp != NULL) *newposp = newpos;
638433d6423SLionel Sambuc 
639433d6423SLionel Sambuc 	if (newpos != rfilp->filp_pos) {
640433d6423SLionel Sambuc 		rfilp->filp_pos = newpos;
641433d6423SLionel Sambuc 
642433d6423SLionel Sambuc 		/* Inhibit read ahead request */
643433d6423SLionel Sambuc 		r = req_inhibread(rfilp->filp_vno->v_fs_e,
644433d6423SLionel Sambuc 				  rfilp->filp_vno->v_inode_nr);
645433d6423SLionel Sambuc 	}
646433d6423SLionel Sambuc   }
647433d6423SLionel Sambuc 
648433d6423SLionel Sambuc   unlock_filp(rfilp);
649433d6423SLionel Sambuc   return(r);
650433d6423SLionel Sambuc }
651433d6423SLionel Sambuc 
652433d6423SLionel Sambuc /*===========================================================================*
653433d6423SLionel Sambuc  *				do_lseek				     *
654433d6423SLionel Sambuc  *===========================================================================*/
do_lseek(void)655433d6423SLionel Sambuc int do_lseek(void)
656433d6423SLionel Sambuc {
657433d6423SLionel Sambuc   /* Perform the lseek(2) system call. */
658e1cdaee1SLionel Sambuc   off_t newpos = 0;
659433d6423SLionel Sambuc   int r;
660433d6423SLionel Sambuc 
661433d6423SLionel Sambuc   if ((r = actual_lseek(fp, job_m_in.m_lc_vfs_lseek.fd,
662433d6423SLionel Sambuc 		job_m_in.m_lc_vfs_lseek.whence, job_m_in.m_lc_vfs_lseek.offset,
663433d6423SLionel Sambuc 		&newpos)) != OK)
664433d6423SLionel Sambuc 	return r;
665433d6423SLionel Sambuc 
666433d6423SLionel Sambuc   /* insert the new position into the output message */
667433d6423SLionel Sambuc   job_m_out.m_vfs_lc_lseek.offset = newpos;
668433d6423SLionel Sambuc   return OK;
669433d6423SLionel Sambuc }
670433d6423SLionel Sambuc 
671433d6423SLionel Sambuc /*===========================================================================*
672433d6423SLionel Sambuc  *				do_close				     *
673433d6423SLionel Sambuc  *===========================================================================*/
do_close(void)674433d6423SLionel Sambuc int do_close(void)
675433d6423SLionel Sambuc {
676491d647aSDavid van Moolenbroek /* Perform the close(fd) or closenb(fd) system call. */
677491d647aSDavid van Moolenbroek   int fd, nblock;
678491d647aSDavid van Moolenbroek 
679491d647aSDavid van Moolenbroek   fd = job_m_in.m_lc_vfs_close.fd;
680491d647aSDavid van Moolenbroek   nblock = job_m_in.m_lc_vfs_close.nblock;
681491d647aSDavid van Moolenbroek 
682491d647aSDavid van Moolenbroek   return close_fd(fp, fd, !nblock /*may_suspend*/);
683433d6423SLionel Sambuc }
684433d6423SLionel Sambuc 
685433d6423SLionel Sambuc 
686433d6423SLionel Sambuc /*===========================================================================*
687433d6423SLionel Sambuc  *				close_fd				     *
688433d6423SLionel Sambuc  *===========================================================================*/
689a0814afbSRichard Sailer int
close_fd(struct fproc * rfp,int fd_nr,int may_suspend)690491d647aSDavid van Moolenbroek close_fd(struct fproc * rfp, int fd_nr, int may_suspend)
691433d6423SLionel Sambuc {
692433d6423SLionel Sambuc /* Perform the close(fd) system call. */
693433d6423SLionel Sambuc   register struct filp *rfilp;
694433d6423SLionel Sambuc   register struct vnode *vp;
695433d6423SLionel Sambuc   struct file_lock *flp;
696491d647aSDavid van Moolenbroek   int r, lock_count;
697433d6423SLionel Sambuc 
698433d6423SLionel Sambuc   /* First locate the vnode that belongs to the file descriptor. */
699433d6423SLionel Sambuc   if ( (rfilp = get_filp2(rfp, fd_nr, VNODE_OPCL)) == NULL) return(err_code);
700433d6423SLionel Sambuc 
701433d6423SLionel Sambuc   vp = rfilp->filp_vno;
702433d6423SLionel Sambuc 
703433d6423SLionel Sambuc   /* first, make all future get_filp2()'s fail; otherwise
704433d6423SLionel Sambuc    * we might try to close the same fd in different threads
705433d6423SLionel Sambuc    */
706433d6423SLionel Sambuc   rfp->fp_filp[fd_nr] = NULL;
707433d6423SLionel Sambuc 
708491d647aSDavid van Moolenbroek   r = close_filp(rfilp, may_suspend);
709433d6423SLionel Sambuc 
710433d6423SLionel Sambuc   FD_CLR(fd_nr, &rfp->fp_cloexec_set);
711433d6423SLionel Sambuc 
712433d6423SLionel Sambuc   /* Check to see if the file is locked.  If so, release all locks. */
713433d6423SLionel Sambuc   if (nr_locks > 0) {
714433d6423SLionel Sambuc 	lock_count = nr_locks;	/* save count of locks */
715433d6423SLionel Sambuc 	for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) {
716433d6423SLionel Sambuc 		if (flp->lock_type == 0) continue;	/* slot not in use */
717433d6423SLionel Sambuc 		if (flp->lock_vnode == vp && flp->lock_pid == rfp->fp_pid) {
718433d6423SLionel Sambuc 			flp->lock_type = 0;
719433d6423SLionel Sambuc 			nr_locks--;
720433d6423SLionel Sambuc 		}
721433d6423SLionel Sambuc 	}
722433d6423SLionel Sambuc 	if (nr_locks < lock_count)
723433d6423SLionel Sambuc 		lock_revive();	/* one or more locks released */
724433d6423SLionel Sambuc   }
725433d6423SLionel Sambuc 
726491d647aSDavid van Moolenbroek   return(r);
727433d6423SLionel Sambuc }
728