xref: /minix/minix/servers/vfs/open.c (revision 27852ebe)
1 /* This file contains the procedures for creating, opening, closing, and
2  * seeking on files.
3  *
4  * The entry points into this file are
5  *   do_open:	perform the OPEN system call
6  *   do_mknod:	perform the MKNOD system call
7  *   do_mkdir:	perform the MKDIR system call
8  *   do_close:	perform the CLOSE system call
9  *   do_lseek:  perform the LSEEK system call
10  */
11 
12 #include "fs.h"
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <minix/callnr.h>
18 #include <minix/com.h>
19 #include <minix/u64.h>
20 #include "file.h"
21 #include "lock.h"
22 #include <sys/dirent.h>
23 #include <assert.h>
24 #include <minix/vfsif.h>
25 #include "vnode.h"
26 #include "vmnt.h"
27 #include "path.h"
28 
29 static char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
30 
31 static struct vnode *new_node(struct lookup *resolve, int oflags,
32 	mode_t bits);
33 static int pipe_open(int fd, struct vnode *vp, mode_t bits, int oflags);
34 
35 /*===========================================================================*
36  *				do_open					     *
37  *===========================================================================*/
do_open(void)38 int do_open(void)
39 {
40 /* Perform the open(name, flags) system call with O_CREAT *not* set. */
41   int open_flags;
42   char fullpath[PATH_MAX];
43 
44   open_flags = job_m_in.m_lc_vfs_path.flags;
45 
46   if (open_flags & O_CREAT)
47 	return EINVAL;
48 
49   if (copy_path(fullpath, sizeof(fullpath)) != OK)
50 	return(err_code);
51 
52   return common_open(fullpath, open_flags, 0 /*omode*/, FALSE /*for_exec*/);
53 }
54 
55 /*===========================================================================*
56  *				do_creat				     *
57  *===========================================================================*/
do_creat(void)58 int do_creat(void)
59 {
60 /* Perform the open(name, flags, mode) system call with O_CREAT set. */
61   int open_flags, create_mode;
62   char fullpath[PATH_MAX];
63   vir_bytes vname;
64   size_t vname_length;
65 
66   vname = job_m_in.m_lc_vfs_creat.name;
67   vname_length = job_m_in.m_lc_vfs_creat.len;
68   open_flags = job_m_in.m_lc_vfs_creat.flags;
69   create_mode = job_m_in.m_lc_vfs_creat.mode;
70 
71   if (!(open_flags & O_CREAT))
72 	return(EINVAL);
73 
74   if (fetch_name(vname, vname_length, fullpath) != OK)
75 	return(err_code);
76 
77   return common_open(fullpath, open_flags, create_mode, FALSE /*for_exec*/);
78 }
79 
80 /*===========================================================================*
81  *				common_open				     *
82  *===========================================================================*/
common_open(char path[PATH_MAX],int oflags,mode_t omode,int for_exec)83 int common_open(char path[PATH_MAX], int oflags, mode_t omode, int for_exec)
84 {
85 /* Common code from do_creat and do_open. */
86   int b, r, exist = TRUE;
87   devmajor_t major_dev;
88   dev_t dev;
89   mode_t bits;
90   struct filp *filp, *filp2;
91   struct vnode *vp;
92   struct vmnt *vmp;
93   struct dmap *dp;
94   struct lookup resolve;
95   int fd, start = 0;
96 
97   /* Remap the bottom two bits of oflags. */
98   bits = (mode_t) mode_map[oflags & O_ACCMODE];
99   if (!bits) return(EINVAL);
100 
101   /* See if file descriptor and filp slots are available. */
102   if ((r = get_fd(fp, start, bits, &fd, &filp)) != OK)
103 	return(r);
104 
105   lookup_init(&resolve, path, PATH_NOFLAGS, &vmp, &vp);
106 
107   /* If O_CREATE is set, try to make the file. */
108   if (oflags & O_CREAT) {
109         omode = I_REGULAR | (omode & ALLPERMS & fp->fp_umask);
110 	vp = new_node(&resolve, oflags, omode);
111 	r = err_code;
112 	if (r == OK) exist = FALSE;	/* We just created the file */
113 	else if (r != EEXIST) {		/* other error */
114 		if (vp) unlock_vnode(vp);
115 		unlock_filp(filp);
116 		return(r);
117 	}
118 	else exist = !(oflags & O_EXCL);/* file exists, if the O_EXCL
119 					   flag is set this is an error */
120   } else {
121 	/* Scan path name */
122 	resolve.l_vmnt_lock = VMNT_READ;
123 	resolve.l_vnode_lock = VNODE_OPCL;
124 	if ((vp = eat_path(&resolve, fp)) == NULL) {
125 		unlock_filp(filp);
126 		return(err_code);
127 	}
128 
129 	if (vmp != NULL) unlock_vmnt(vmp);
130   }
131 
132   /* Claim the file descriptor and filp slot and fill them in. */
133   fp->fp_filp[fd] = filp;
134   filp->filp_count = 1;
135   filp->filp_vno = vp;
136   filp->filp_flags = oflags;
137   if (oflags & O_CLOEXEC)
138 	FD_SET(fd, &fp->fp_cloexec_set);
139 
140   /* Only do the normal open code if we didn't just create the file. */
141   if (exist) {
142 	/* Check permissions based on the given open flags, except when we are
143 	 * opening an executable for the purpose of passing a file descriptor
144 	 * to its interpreter for execution, in which case we check the X bit.
145 	 */
146 	if ((r = forbidden(fp, vp, for_exec ? X_BIT : bits)) == OK) {
147 		/* Opening reg. files, directories, and special files differ */
148 		switch (vp->v_mode & S_IFMT) {
149 		   case S_IFREG:
150 			/* Truncate regular file if O_TRUNC. */
151 			if (oflags & O_TRUNC) {
152 				if ((r = forbidden(fp, vp, W_BIT)) != OK)
153 					break;
154 				upgrade_vnode_lock(vp);
155 				truncate_vnode(vp, 0);
156 			}
157 			break;
158 		   case S_IFDIR:
159 			/* Directories may be read but not written. */
160 			r = (bits & W_BIT ? EISDIR : OK);
161 			break;
162 		   case S_IFCHR:
163 			/* Invoke the driver for special processing. */
164 			dev = vp->v_sdev;
165 			/* TTY needs to know about the O_NOCTTY flag. */
166 			r = cdev_open(fd, dev, bits | (oflags & O_NOCTTY));
167 			vp = filp->filp_vno;	/* Might be updated by
168 						 * cdev_open after cloning */
169 			break;
170 		   case S_IFBLK:
171 
172 			lock_bsf();
173 
174 			/* Invoke the driver for special processing. */
175 			dev = vp->v_sdev;
176 			r = bdev_open(dev, bits);
177 			if (r != OK) {
178 				unlock_bsf();
179 				break;
180 			}
181 
182 			major_dev = major(vp->v_sdev);
183 			dp = &dmap[major_dev];
184 			if (dp->dmap_driver == NONE) {
185 				printf("VFS: block driver disappeared!\n");
186 				unlock_bsf();
187 				r = ENXIO;
188 				break;
189 			}
190 
191 			/* Check whether the device is mounted or not. If so,
192 			 * then that FS is responsible for this device.
193 			 * Otherwise we default to ROOT_FS.
194 			 */
195 			vp->v_bfs_e = ROOT_FS_E; /* By default */
196 			for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp)
197 				if (vmp->m_dev == vp->v_sdev &&
198 				    !(vmp->m_flags & VMNT_FORCEROOTBSF)) {
199 					vp->v_bfs_e = vmp->m_fs_e;
200 				}
201 
202 			/* Send the driver label to the file system that will
203 			 * handle the block I/O requests (even when its label
204 			 * and endpoint are known already), but only when it is
205 			 * the root file system. Other file systems will
206 			 * already have it anyway.
207 			 */
208 			if (vp->v_bfs_e != ROOT_FS_E) {
209 				unlock_bsf();
210 				break;
211 			}
212 
213 			if (req_newdriver(vp->v_bfs_e, vp->v_sdev,
214 					dp->dmap_label) != OK) {
215 				printf("VFS: error sending driver label\n");
216 				bdev_close(dev);
217 				r = ENXIO;
218 			}
219 			unlock_bsf();
220 			break;
221 
222 		   case S_IFIFO:
223 			/* Create a mapped inode on PFS which handles reads
224 			   and writes to this named pipe. */
225 			upgrade_vnode_lock(vp);
226 			r = map_vnode(vp, PFS_PROC_NR);
227 			if (r == OK) {
228 				if (vp->v_ref_count == 1) {
229 					if (vp->v_size != 0)
230 						r = truncate_vnode(vp, 0);
231 				}
232 				oflags |= O_APPEND;	/* force append mode */
233 				filp->filp_flags = oflags;
234 			}
235 			if (r == OK) {
236 				r = pipe_open(fd, vp, bits, oflags);
237 			}
238 			if (r != ENXIO) {
239 				/* See if someone else is doing a rd or wt on
240 				 * the FIFO.  If so, use its filp entry so the
241 				 * file position will be automatically shared.
242 				 */
243 				b = (bits & R_BIT ? R_BIT : W_BIT);
244 				filp->filp_count = 0; /* don't find self */
245 				if ((filp2 = find_filp(vp, b)) != NULL) {
246 				    /* Co-reader or writer found. Use it.*/
247 				    fp->fp_filp[fd] = filp2;
248 				    filp2->filp_count++;
249 				    filp2->filp_vno = vp;
250 				    filp2->filp_flags = oflags;
251 
252 				    /* v_count was incremented after the vnode
253 				     * has been found. i_count was incremented
254 				     * incorrectly in FS, not knowing that we
255 				     * were going to use an existing filp
256 				     * entry.  Correct this error.
257 				     */
258 				    unlock_vnode(vp);
259 				    put_vnode(vp);
260 				} else {
261 				    /* Nobody else found. Restore filp. */
262 				    filp->filp_count = 1;
263 				}
264 			}
265 			break;
266 		   case S_IFSOCK:
267 			r = EOPNOTSUPP;
268 			break;
269 		   default:
270 			printf("VFS: attempt to open file <%llu,%llu> of "
271 			    "type 0%o\n", vp->v_dev, vp->v_inode_nr,
272 			    vp->v_mode & S_IFMT);
273 			r = EIO;
274 		}
275 	}
276   }
277 
278   unlock_filp(filp);
279 
280   /* If error, release inode. */
281   if (r != OK) {
282 	if (r != SUSPEND) {
283 		fp->fp_filp[fd] = NULL;
284 		filp->filp_count = 0;
285 		filp->filp_vno = NULL;
286 		put_vnode(vp);
287 	}
288   } else {
289 	r = fd;
290   }
291 
292   return(r);
293 }
294 
295 
296 /*===========================================================================*
297  *				new_node				     *
298  *===========================================================================*/
new_node(struct lookup * resolve,int oflags,mode_t bits)299 static struct vnode *new_node(struct lookup *resolve, int oflags, mode_t bits)
300 {
301 /* Try to create a new inode and return a pointer to it. If the inode already
302    exists, return a pointer to it as well, but set err_code accordingly.
303    NULL is returned if the path cannot be resolved up to the last
304    directory, or when the inode cannot be created due to permissions or
305    otherwise. */
306   struct vnode *dirp, *vp;
307   struct vmnt *dir_vmp, *vp_vmp;
308   int r;
309   struct node_details res;
310   struct lookup findnode;
311   char *path;
312 
313   path = resolve->l_path;	/* For easy access */
314 
315   lookup_init(&findnode, path, resolve->l_flags, &dir_vmp, &dirp);
316   findnode.l_vmnt_lock = VMNT_WRITE;
317   findnode.l_vnode_lock = VNODE_WRITE; /* dir node */
318 
319   /* When O_CREAT and O_EXCL flags are set, the path may not be named by a
320    * symbolic link. */
321   if (oflags & O_EXCL) findnode.l_flags |= PATH_RET_SYMLINK;
322 
323   /* See if the path can be opened down to the last directory. */
324   if ((dirp = last_dir(&findnode, fp)) == NULL) return(NULL);
325 
326   /* The final directory is accessible. Get final component of the path. */
327   lookup_init(&findnode, findnode.l_path, findnode.l_flags, &vp_vmp, &vp);
328   findnode.l_vmnt_lock = VMNT_WRITE;
329   findnode.l_vnode_lock = (oflags & O_TRUNC) ? VNODE_WRITE : VNODE_OPCL;
330   vp = advance(dirp, &findnode, fp);
331   assert(vp_vmp == NULL);	/* Lookup to last dir should have yielded lock
332 				 * on vmp or final component does not exist.
333 				 * Either way, vp_vmp ought to be not set.
334 				 */
335 
336   /* The combination of a symlink with absolute path followed by a danglink
337    * symlink results in a new path that needs to be re-resolved entirely. */
338   if (path[0] == '/') {
339 	unlock_vnode(dirp);
340 	unlock_vmnt(dir_vmp);
341 	put_vnode(dirp);
342 	if (vp != NULL) {
343 		unlock_vnode(vp);
344 		put_vnode(vp);
345 	}
346 	return new_node(resolve, oflags, bits);
347   }
348 
349   if (vp == NULL && err_code == ENOENT) {
350 	/* Last path component does not exist. Make a new directory entry. */
351 	if ((vp = get_free_vnode()) == NULL) {
352 		/* Can't create new entry: out of vnodes. */
353 		unlock_vnode(dirp);
354 		unlock_vmnt(dir_vmp);
355 		put_vnode(dirp);
356 		return(NULL);
357 	}
358 
359 	lock_vnode(vp, VNODE_OPCL);
360 	upgrade_vmnt_lock(dir_vmp); /* Creating file, need exclusive access */
361 
362 	if ((r = forbidden(fp, dirp, W_BIT|X_BIT)) != OK ||
363 	    (r = req_create(dirp->v_fs_e, dirp->v_inode_nr,bits, fp->fp_effuid,
364 			    fp->fp_effgid, path, &res)) != OK ) {
365 		/* Can't create inode either due to permissions or some other
366 		 * problem. In case r is EEXIST, we might be dealing with a
367 		 * dangling symlink.*/
368 
369 		/* Downgrade lock to prevent deadlock during symlink resolving*/
370 		downgrade_vmnt_lock(dir_vmp);
371 
372 		if (r == EEXIST) {
373 			struct vnode *slp, *old_wd;
374 
375 
376 			/* Resolve path up to symlink */
377 			findnode.l_flags = PATH_RET_SYMLINK;
378 			findnode.l_vnode_lock = VNODE_READ;
379 			findnode.l_vnode = &slp;
380 			slp = advance(dirp, &findnode, fp);
381 			if (slp != NULL) {
382 				if (S_ISLNK(slp->v_mode)) {
383 					/* Get contents of link */
384 
385 					r = req_rdlink(slp->v_fs_e,
386 						       slp->v_inode_nr,
387 						       VFS_PROC_NR,
388 						       (vir_bytes) path,
389 						       PATH_MAX - 1, 0);
390 					if (r < 0) {
391 						/* Failed to read link */
392 						unlock_vnode(slp);
393 						unlock_vnode(dirp);
394 						unlock_vmnt(dir_vmp);
395 						put_vnode(slp);
396 						put_vnode(dirp);
397 						err_code = r;
398 						return(NULL);
399 					}
400 					path[r] = '\0'; /* Terminate path */
401 				}
402 				unlock_vnode(slp);
403 				put_vnode(slp);
404 			}
405 
406 			/* Try to create the inode the dangling symlink was
407 			 * pointing to. We have to use dirp as starting point
408 			 * as there might be multiple successive symlinks
409 			 * crossing multiple mountpoints.
410 			 * Unlock vnodes and vmnts as we're going to recurse.
411 			 */
412 			unlock_vnode(dirp);
413 			unlock_vnode(vp);
414 			unlock_vmnt(dir_vmp);
415 
416 			old_wd = fp->fp_wd; /* Save orig. working dirp */
417 			fp->fp_wd = dirp;
418 			vp = new_node(resolve, oflags, bits);
419 			fp->fp_wd = old_wd; /* Restore */
420 
421 			if (vp != NULL) {
422 				put_vnode(dirp);
423 				*(resolve->l_vnode) = vp;
424 				return(vp);
425 			}
426 			r = err_code;
427 		}
428 
429 		if (r == EEXIST)
430 			err_code = EIO; /* Impossible, we have verified that
431 					 * the last component doesn't exist and
432 					 * is not a dangling symlink. */
433 		else
434 			err_code = r;
435 
436 		unlock_vmnt(dir_vmp);
437 		unlock_vnode(dirp);
438 		unlock_vnode(vp);
439 		put_vnode(dirp);
440 		return(NULL);
441 	}
442 
443 	/* Store results and mark vnode in use */
444 
445 	vp->v_fs_e = res.fs_e;
446 	vp->v_inode_nr = res.inode_nr;
447 	vp->v_mode = res.fmode;
448 	vp->v_size = res.fsize;
449 	vp->v_uid = res.uid;
450 	vp->v_gid = res.gid;
451 	vp->v_sdev = res.dev;
452 	vp->v_vmnt = dirp->v_vmnt;
453 	vp->v_dev = vp->v_vmnt->m_dev;
454 	vp->v_fs_count = 1;
455 	vp->v_ref_count = 1;
456   } else {
457 	/* Either last component exists, or there is some other problem. */
458 	if (vp != NULL) {
459 		r = EEXIST;	/* File exists or a symlink names a file while
460 				 * O_EXCL is set. */
461 	} else
462 		r = err_code;	/* Other problem. */
463   }
464 
465   err_code = r;
466   /* When dirp equals vp, we shouldn't release the lock as a vp is locked only
467    * once. Releasing the lock would cause the resulting vp not be locked and
468    * cause mayhem later on. */
469   if (dirp != vp) {
470 	unlock_vnode(dirp);
471   }
472   unlock_vmnt(dir_vmp);
473   put_vnode(dirp);
474 
475   *(resolve->l_vnode) = vp;
476   return(vp);
477 }
478 
479 
480 /*===========================================================================*
481  *				pipe_open				     *
482  *===========================================================================*/
pipe_open(int fd,struct vnode * vp,mode_t bits,int oflags)483 static int pipe_open(int fd, struct vnode *vp, mode_t bits, int oflags)
484 {
485 /*  This function is called from common_open. It checks if
486  *  there is at least one reader/writer pair for the pipe, if not
487  *  it suspends the caller, otherwise it revives all other blocked
488  *  processes hanging on the pipe.
489  */
490 
491   if ((bits & (R_BIT|W_BIT)) == (R_BIT|W_BIT)) return(ENXIO);
492 
493   /* Find the reader/writer at the other end of the pipe */
494   if (find_filp(vp, bits & W_BIT ? R_BIT : W_BIT) == NULL) {
495 	/* Not found */
496 	if (oflags & O_NONBLOCK) {
497 		if (bits & W_BIT) return(ENXIO);
498 	} else {
499 		/* Let's wait for the other side to show up */
500 		fp->fp_popen.fd = fd;
501 		suspend(FP_BLOCKED_ON_POPEN);
502 		return(SUSPEND);
503 	}
504   } else if (susp_count > 0) { /* revive blocked processes */
505 	release(vp, VFS_OPEN, susp_count);
506   }
507   return(OK);
508 }
509 
510 
511 /*===========================================================================*
512  *				do_mknod				     *
513  *===========================================================================*/
do_mknod(void)514 int do_mknod(void)
515 {
516 /* Perform the mknod(name, mode, addr) system call. */
517   register mode_t bits, mode_bits;
518   int r;
519   struct vnode *vp;
520   struct vmnt *vmp;
521   char fullpath[PATH_MAX];
522   struct lookup resolve;
523   vir_bytes vname1;
524   size_t vname1_length;
525   dev_t dev;
526 
527   vname1 = job_m_in.m_lc_vfs_mknod.name;
528   vname1_length = job_m_in.m_lc_vfs_mknod.len;
529   mode_bits = job_m_in.m_lc_vfs_mknod.mode;
530   dev = job_m_in.m_lc_vfs_mknod.device;
531 
532   /* If the path names a symbolic link, mknod() shall fail with EEXIST. */
533   lookup_init(&resolve, fullpath, PATH_RET_SYMLINK, &vmp, &vp);
534   resolve.l_vmnt_lock = VMNT_WRITE;
535   resolve.l_vnode_lock = VNODE_WRITE;
536 
537   /* Only the super_user may make nodes other than fifos. */
538   if (!super_user && !S_ISFIFO(mode_bits))
539 	return(EPERM);
540 
541   bits = (mode_bits & S_IFMT) | (mode_bits & ACCESSPERMS & fp->fp_umask);
542 
543   /* Open directory that's going to hold the new node. */
544   if (fetch_name(vname1, vname1_length, fullpath) != OK) return(err_code);
545   if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code);
546 
547   /* Make sure that the object is a directory */
548   if (!S_ISDIR(vp->v_mode)) {
549 	r = ENOTDIR;
550   } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) {
551 	r = req_mknod(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid,
552 		      fp->fp_effgid, bits, dev);
553   }
554 
555   unlock_vnode(vp);
556   unlock_vmnt(vmp);
557   put_vnode(vp);
558   return(r);
559 }
560 
561 /*===========================================================================*
562  *				do_mkdir				     *
563  *===========================================================================*/
do_mkdir(void)564 int do_mkdir(void)
565 {
566 /* Perform the mkdir(name, mode) system call. */
567   mode_t bits;			/* mode bits for the new inode */
568   int r;
569   struct vnode *vp;
570   struct vmnt *vmp;
571   char fullpath[PATH_MAX];
572   struct lookup resolve;
573   mode_t dirmode;
574 
575   if (copy_path(fullpath, sizeof(fullpath)) != OK)
576 	return(err_code);
577   dirmode = job_m_in.m_lc_vfs_path.mode;
578 
579   lookup_init(&resolve, fullpath, PATH_NOFLAGS, &vmp, &vp);
580   resolve.l_vmnt_lock = VMNT_WRITE;
581   resolve.l_vnode_lock = VNODE_WRITE;
582 
583   bits = I_DIRECTORY | (dirmode & RWX_MODES & fp->fp_umask);
584   if ((vp = last_dir(&resolve, fp)) == NULL) return(err_code);
585 
586   /* Make sure that the object is a directory */
587   if (!S_ISDIR(vp->v_mode)) {
588 	r = ENOTDIR;
589   } else if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) {
590 	r = req_mkdir(vp->v_fs_e, vp->v_inode_nr, fullpath, fp->fp_effuid,
591 		      fp->fp_effgid, bits);
592   }
593 
594   unlock_vnode(vp);
595   unlock_vmnt(vmp);
596   put_vnode(vp);
597   return(r);
598 }
599 
600 /*===========================================================================*
601  *				actual_lseek				     *
602  *===========================================================================*/
actual_lseek(struct fproc * rfp,int seekfd,int seekwhence,off_t offset,off_t * newposp)603 int actual_lseek(struct fproc *rfp, int seekfd, int seekwhence, off_t offset,
604 	off_t *newposp)
605 {
606   register struct filp *rfilp;
607   int r = OK;
608   off_t pos, newpos;
609 
610   /* Check to see if the file descriptor is valid. */
611   if ( (rfilp = get_filp2(rfp, seekfd, VNODE_READ)) == NULL) {
612 	return(err_code);
613   }
614 
615   /* No lseek on pipes. */
616   if (S_ISFIFO(rfilp->filp_vno->v_mode)) {
617 	unlock_filp(rfilp);
618 	return(ESPIPE);
619   }
620 
621   /* The value of 'whence' determines the start position to use. */
622   switch(seekwhence) {
623     case SEEK_SET: pos = 0; break;
624     case SEEK_CUR: pos = rfilp->filp_pos; break;
625     case SEEK_END: pos = rfilp->filp_vno->v_size; break;
626     default: unlock_filp(rfilp); return(EINVAL);
627   }
628 
629   newpos = pos + offset;
630 
631   /* Check for overflow. */
632   if ((offset > 0) && (newpos <= pos)) {
633 	r = EOVERFLOW;
634   } else if ((offset < 0) && (newpos >= pos)) {
635 	r = EOVERFLOW;
636   } else {
637 	if (newposp != NULL) *newposp = newpos;
638 
639 	if (newpos != rfilp->filp_pos) {
640 		rfilp->filp_pos = newpos;
641 
642 		/* Inhibit read ahead request */
643 		r = req_inhibread(rfilp->filp_vno->v_fs_e,
644 				  rfilp->filp_vno->v_inode_nr);
645 	}
646   }
647 
648   unlock_filp(rfilp);
649   return(r);
650 }
651 
652 /*===========================================================================*
653  *				do_lseek				     *
654  *===========================================================================*/
do_lseek(void)655 int do_lseek(void)
656 {
657   /* Perform the lseek(2) system call. */
658   off_t newpos = 0;
659   int r;
660 
661   if ((r = actual_lseek(fp, job_m_in.m_lc_vfs_lseek.fd,
662 		job_m_in.m_lc_vfs_lseek.whence, job_m_in.m_lc_vfs_lseek.offset,
663 		&newpos)) != OK)
664 	return r;
665 
666   /* insert the new position into the output message */
667   job_m_out.m_vfs_lc_lseek.offset = newpos;
668   return OK;
669 }
670 
671 /*===========================================================================*
672  *				do_close				     *
673  *===========================================================================*/
do_close(void)674 int do_close(void)
675 {
676 /* Perform the close(fd) or closenb(fd) system call. */
677   int fd, nblock;
678 
679   fd = job_m_in.m_lc_vfs_close.fd;
680   nblock = job_m_in.m_lc_vfs_close.nblock;
681 
682   return close_fd(fp, fd, !nblock /*may_suspend*/);
683 }
684 
685 
686 /*===========================================================================*
687  *				close_fd				     *
688  *===========================================================================*/
689 int
close_fd(struct fproc * rfp,int fd_nr,int may_suspend)690 close_fd(struct fproc * rfp, int fd_nr, int may_suspend)
691 {
692 /* Perform the close(fd) system call. */
693   register struct filp *rfilp;
694   register struct vnode *vp;
695   struct file_lock *flp;
696   int r, lock_count;
697 
698   /* First locate the vnode that belongs to the file descriptor. */
699   if ( (rfilp = get_filp2(rfp, fd_nr, VNODE_OPCL)) == NULL) return(err_code);
700 
701   vp = rfilp->filp_vno;
702 
703   /* first, make all future get_filp2()'s fail; otherwise
704    * we might try to close the same fd in different threads
705    */
706   rfp->fp_filp[fd_nr] = NULL;
707 
708   r = close_filp(rfilp, may_suspend);
709 
710   FD_CLR(fd_nr, &rfp->fp_cloexec_set);
711 
712   /* Check to see if the file is locked.  If so, release all locks. */
713   if (nr_locks > 0) {
714 	lock_count = nr_locks;	/* save count of locks */
715 	for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) {
716 		if (flp->lock_type == 0) continue;	/* slot not in use */
717 		if (flp->lock_vnode == vp && flp->lock_pid == rfp->fp_pid) {
718 			flp->lock_type = 0;
719 			nr_locks--;
720 		}
721 	}
722 	if (nr_locks < lock_count)
723 		lock_revive();	/* one or more locks released */
724   }
725 
726   return(r);
727 }
728