Пример #1
0
/*===========================================================================*
 *				check_bsf				     *
 *===========================================================================*/
void check_bsf_lock(void)
{
	int r = mutex_trylock(&bsf_lock);

	if (r == -EBUSY)
		panic("bsf_lock locked");
	else if (r != 0)
		panic("bsf_lock weird state");

	/* r == 0 */
	unlock_bsf();
}
Пример #2
0
/*===========================================================================*
 *				common_open				     *
 *===========================================================================*/
int common_open(char path[PATH_MAX], int oflags, mode_t omode)
{
/* Common code from do_creat and do_open. */
  int b, r, exist = TRUE, major_dev;
  dev_t dev;
  mode_t bits;
  struct filp *filp, *filp2;
  struct vnode *vp;
  struct vmnt *vmp;
  struct dmap *dp;
  struct lookup resolve;

  /* Remap the bottom two bits of oflags. */
  bits = (mode_t) mode_map[oflags & O_ACCMODE];
  if (!bits) return(EINVAL);

  /* See if file descriptor and filp slots are available. */
  if ((r = get_fd(0, bits, &(scratch(fp).file.fd_nr), &filp)) != OK) return(r);

  lookup_init(&resolve, path, PATH_NOFLAGS, &vmp, &vp);

  /* If O_CREATE is set, try to make the file. */
  if (oflags & O_CREAT) {
        omode = I_REGULAR | (omode & ALLPERMS & fp->fp_umask);
	vp = new_node(&resolve, oflags, omode);
	r = err_code;
	if (r == OK) exist = FALSE;	/* We just created the file */
	else if (r != EEXIST) {		/* other error */
		if (vp) unlock_vnode(vp);
		unlock_filp(filp);
		return(r);
	}
	else exist = !(oflags & O_EXCL);/* file exists, if the O_EXCL
					   flag is set this is an error */
  } else {
	/* Scan path name */
	resolve.l_vmnt_lock = VMNT_READ;
	resolve.l_vnode_lock = VNODE_OPCL;
	if ((vp = eat_path(&resolve, fp)) == NULL) {
		unlock_filp(filp);
		return(err_code);
	}

	if (vmp != NULL) unlock_vmnt(vmp);
  }

  /* Claim the file descriptor and filp slot and fill them in. */
  fp->fp_filp[scratch(fp).file.fd_nr] = filp;
  FD_SET(scratch(fp).file.fd_nr, &fp->fp_filp_inuse);
  filp->filp_count = 1;
  filp->filp_vno = vp;
  filp->filp_flags = oflags;

  /* Only do the normal open code if we didn't just create the file. */
  if (exist) {
	/* Check protections. */
	if ((r = forbidden(fp, vp, bits)) == OK) {
		/* Opening reg. files, directories, and special files differ */
		switch (vp->v_mode & S_IFMT) {
		   case S_IFREG:
			/* Truncate regular file if O_TRUNC. */
			if (oflags & O_TRUNC) {
				if ((r = forbidden(fp, vp, W_BIT)) != OK)
					break;
				truncate_vnode(vp, 0);
			}
			break;
		   case S_IFDIR:
			/* Directories may be read but not written. */
			r = (bits & W_BIT ? EISDIR : OK);
			break;
		   case S_IFCHR:
			/* Invoke the driver for special processing. */
			dev = (dev_t) vp->v_sdev;
			/* TTY needs to know about the O_NOCTTY flag. */
			r = dev_open(dev, who_e, bits | (oflags & O_NOCTTY));
			if (r == SUSPEND) suspend(FP_BLOCKED_ON_DOPEN);
			else vp = filp->filp_vno; /* Might be updated by
						   * dev_open/clone_opcl */
			break;
		   case S_IFBLK:

			lock_bsf();

			/* Invoke the driver for special processing. */
			dev = (dev_t) vp->v_sdev;
			r = bdev_open(dev, bits);
			if (r != OK) {
				unlock_bsf();
				break;
			}

			major_dev = major(vp->v_sdev);
			dp = &dmap[major_dev];
			if (dp->dmap_driver == NONE) {
				printf("VFS: block driver disappeared!\n");
				unlock_bsf();
				r = ENXIO;
				break;
			}

			/* Check whether the device is mounted or not. If so,
			 * then that FS is responsible for this device.
			 * Otherwise we default to ROOT_FS.
			 */
			vp->v_bfs_e = ROOT_FS_E; /* By default */
			for (vmp = &vmnt[0]; vmp < &vmnt[NR_MNTS]; ++vmp)
				if (vmp->m_dev == vp->v_sdev &&
				    !(vmp->m_flags & VMNT_FORCEROOTBSF)) {
					vp->v_bfs_e = vmp->m_fs_e;
				}

			/* Send the driver label to the file system that will
			 * handle the block I/O requests (even when its label
			 * and endpoint are known already), but only when it is
			 * the root file system. Other file systems will
			 * already have it anyway.
			 */
			if (vp->v_bfs_e != ROOT_FS_E) {
				unlock_bsf();
				break;
			}

			if (req_newdriver(vp->v_bfs_e, vp->v_sdev,
					dp->dmap_label) != OK) {
				printf("VFS: error sending driver label\n");
				bdev_close(dev);
				r = ENXIO;
			}
			unlock_bsf();
			break;

		   case S_IFIFO:
			/* Create a mapped inode on PFS which handles reads
			   and writes to this named pipe. */
			tll_upgrade(&vp->v_lock);
			r = map_vnode(vp, PFS_PROC_NR);
			if (r == OK) {
				if (vp->v_ref_count == 1) {
					vp->v_pipe_rd_pos = 0;
					vp->v_pipe_wr_pos = 0;
					if (vp->v_size != 0)
						r = truncate_vnode(vp, 0);
				}
				oflags |= O_APPEND;	/* force append mode */
				filp->filp_flags = oflags;
			}
			if (r == OK) {
				r = pipe_open(vp, bits, oflags);
			}
			if (r != ENXIO) {
				/* See if someone else is doing a rd or wt on
				 * the FIFO.  If so, use its filp entry so the
				 * file position will be automatically shared.
				 */
				b = (bits & R_BIT ? R_BIT : W_BIT);
				filp->filp_count = 0; /* don't find self */
				if ((filp2 = find_filp(vp, b)) != NULL) {
				    /* Co-reader or writer found. Use it.*/
				    fp->fp_filp[scratch(fp).file.fd_nr] = filp2;
				    filp2->filp_count++;
				    filp2->filp_vno = vp;
				    filp2->filp_flags = oflags;

				    /* v_count was incremented after the vnode
				     * has been found. i_count was incremented
				     * incorrectly in FS, not knowing that we
				     * were going to use an existing filp
				     * entry.  Correct this error.
				     */
				    unlock_vnode(vp);
				    put_vnode(vp);
				} else {
				    /* Nobody else found. Restore filp. */
				    filp->filp_count = 1;
				}
			}
			break;
		}
	}
  }

  unlock_filp(filp);

  /* If error, release inode. */
  if (r != OK) {
	if (r != SUSPEND) {
		fp->fp_filp[scratch(fp).file.fd_nr] = NULL;
		FD_CLR(scratch(fp).file.fd_nr, &fp->fp_filp_inuse);
		filp->filp_count = 0;
		filp->filp_vno = NULL;
		put_vnode(vp);
	}
  } else {
	r = scratch(fp).file.fd_nr;
  }

  return(r);
}
Пример #3
0
/*===========================================================================*
 *                              mount_fs				     *
 *===========================================================================*/
int mount_fs(
dev_t dev,
char mountpoint[PATH_MAX],
endpoint_t fs_e,
int rdonly,
char mount_label[LABEL_MAX] )
{
  int i, r = OK, found, isroot, mount_root, con_reqs, slot;
  struct fproc *tfp, *rfp;
  struct dmap *dp;
  struct vnode *root_node, *vp = NULL;
  struct vmnt *new_vmp, *parent_vmp;
  char *label;
  struct node_details res;
  struct lookup resolve;

  /* Look up block device driver label when dev is not a pseudo-device */
  label = "";
  if (!is_nonedev(dev)) {
	/* Get driver process' endpoint */
	dp = &dmap[major(dev)];
	if (dp->dmap_driver == NONE) {
		printf("VFS: no driver for dev %d\n", dev);
		return(EINVAL);
	}

	label = dp->dmap_label;
	assert(strlen(label) > 0);
  }

  /* Scan vmnt table to see if dev already mounted. If not, find a free slot.*/
  found = FALSE;
  for (i = 0; i < NR_MNTS; ++i) {
	if (vmnt[i].m_dev == dev) found = TRUE;
  }
  if (found) {
	return(EBUSY);
  } else if ((new_vmp = get_free_vmnt()) == NULL) {
	return(ENOMEM);
  }

  if ((r = lock_vmnt(new_vmp, VMNT_EXCL)) != OK) return(r);

  isroot = (strcmp(mountpoint, "/") == 0);
  mount_root = (isroot && have_root < 2); /* Root can be mounted twice:
					   * 1: ramdisk
					   * 2: boot disk (e.g., harddisk)
					   */

  if (!mount_root) {
	/* Get vnode of mountpoint */
	lookup_init(&resolve, mountpoint, PATH_NOFLAGS, &parent_vmp, &vp);
	resolve.l_vmnt_lock = VMNT_EXCL;
	resolve.l_vnode_lock = VNODE_WRITE;
	if ((vp = eat_path(&resolve, fp)) == NULL)
		r = err_code;
	else if (vp->v_ref_count == 1) {
		/*Tell FS on which vnode it is mounted (glue into mount tree)*/
		r = req_mountpoint(vp->v_fs_e, vp->v_inode_nr);
	} else
		r = EBUSY;

	if (vp != NULL)	{
		/* Quickly unlock to allow back calls (from e.g. FUSE) to
		 * relock */
		unlock_vmnt(parent_vmp);
	}

	if (r != OK) {
		if (vp != NULL) {
			unlock_vnode(vp);
			put_vnode(vp);
		}
		unlock_vmnt(new_vmp);
		return(r);
	}
  }

  /* We'll need a vnode for the root inode */
  if ((root_node = get_free_vnode()) == NULL) {
	if (vp != NULL) {
		unlock_vnode(vp);
		put_vnode(vp);
	}
	unlock_vmnt(new_vmp);
	return(err_code);
  }
  lock_vnode(root_node, VNODE_OPCL);

  /* Record process as a system process */
  if (isokendpt(fs_e, &slot) != OK) {
	if (vp != NULL) {
		unlock_vnode(vp);
		put_vnode(vp);
	}
	unlock_vnode(root_node);
	unlock_vmnt(new_vmp);
	return(EINVAL);
  }
  rfp = &fproc[slot];
  rfp->fp_flags |= FP_SRV_PROC;	/* File Servers are also services */

  /* Store some essential vmnt data first */
  new_vmp->m_fs_e = fs_e;
  new_vmp->m_dev = dev;
  if (rdonly) new_vmp->m_flags |= VMNT_READONLY;
  else new_vmp->m_flags &= ~VMNT_READONLY;

  /* Tell FS which device to mount */
  new_vmp->m_flags |= VMNT_MOUNTING;
  r = req_readsuper(fs_e, label, dev, rdonly, isroot, &res, &con_reqs);
  new_vmp->m_flags &= ~VMNT_MOUNTING;

  if (r != OK) {
	mark_vmnt_free(new_vmp);
	unlock_vnode(root_node);
	if (vp != NULL) {
		unlock_vnode(vp);
		put_vnode(vp);
	}
	unlock_vmnt(new_vmp);
	return(r);
  }

  lock_bsf();

  /* Fill in root node's fields */
  root_node->v_fs_e = res.fs_e;
  root_node->v_inode_nr = res.inode_nr;
  root_node->v_mode = res.fmode;
  root_node->v_uid = res.uid;
  root_node->v_gid = res.gid;
  root_node->v_size = res.fsize;
  root_node->v_sdev = NO_DEV;
  root_node->v_fs_count = 1;
  root_node->v_ref_count = 1;

  /* Root node is indeed on the partition */
  root_node->v_vmnt = new_vmp;
  root_node->v_dev = new_vmp->m_dev;
  if (con_reqs == 0)
	new_vmp->m_comm.c_max_reqs = 1;	/* Default if FS doesn't tell us */
  else
	new_vmp->m_comm.c_max_reqs = con_reqs;
  new_vmp->m_comm.c_cur_reqs = 0;

  if (mount_root) {
	/* Superblock and root node already read.
	 * Nothing else can go wrong. Perform the mount. */
	new_vmp->m_root_node = root_node;
	new_vmp->m_mounted_on = NULL;
	strlcpy(new_vmp->m_label, mount_label, LABEL_MAX);
	if (is_nonedev(dev)) alloc_nonedev(dev);
	update_bspec(dev, fs_e, 0 /* Don't send new driver endpoint */);

	ROOT_DEV = dev;
	ROOT_FS_E = fs_e;

	/* Replace all root and working directories */
	for (i = 0, tfp = fproc; i < NR_PROCS; i++, tfp++) {
		if (tfp->fp_pid == PID_FREE)
			continue;

#define		MAKEROOT(what) { 			\
			if (what) put_vnode(what);	\
			dup_vnode(root_node);		\
			what = root_node;		\
		}

		MAKEROOT(tfp->fp_rd);
		MAKEROOT(tfp->fp_wd);
	}

	unlock_vnode(root_node);
	unlock_vmnt(new_vmp);
	have_root++; /* We have a (new) root */
	unlock_bsf();
	return(OK);
  }

  /* File types may not conflict. */
  if (!S_ISDIR(vp->v_mode) && S_ISDIR(root_node->v_mode)) r = EISDIR;

  /* If error, return the super block and both inodes; release the vmnt. */
  if (r != OK) {
	unlock_vnode(vp);
	unlock_vnode(root_node);
	mark_vmnt_free(new_vmp);
	unlock_vmnt(new_vmp);
	put_vnode(vp);
	put_vnode(root_node);
	unlock_bsf();
	return(r);
  }

  /* Nothing else can go wrong.  Perform the mount. */
  new_vmp->m_mounted_on = vp;
  new_vmp->m_root_node = root_node;
  strlcpy(new_vmp->m_label, mount_label, LABEL_MAX);

  /* Allocate the pseudo device that was found, if not using a real device. */
  if (is_nonedev(dev)) alloc_nonedev(dev);

  /* The new FS will handle block I/O requests for its device now. */
  if (!(new_vmp->m_flags & VMNT_FORCEROOTBSF))
	update_bspec(dev, fs_e, 0 /* Don't send new driver endpoint */);

  unlock_vnode(vp);
  unlock_vnode(root_node);
  unlock_vmnt(new_vmp);
  unlock_bsf();

  return(OK);
}
Пример #4
0
/*===========================================================================*
 *                              unmount					     *
 *===========================================================================*/
int unmount(
  dev_t dev,			/* block-special device */
  char label[LABEL_MAX]		/* buffer to retrieve label, or NULL */
)
{
  struct vnode *vp;
  struct vmnt *vmp_i = NULL, *vmp = NULL;
  int count, locks, r;

  /* Find vmnt that is to be unmounted */
  for (vmp_i = &vmnt[0]; vmp_i < &vmnt[NR_MNTS]; ++vmp_i) {
	  if (vmp_i->m_dev == dev) {
		  if(vmp) panic("device mounted more than once: %d", dev);
		  vmp = vmp_i;
	  }
  }

  /* Did we find the vmnt (i.e., was dev a mounted device)? */
  if(!vmp) return(EINVAL);

  if ((r = lock_vmnt(vmp, VMNT_EXCL)) != OK) return(r);

  /* See if the mounted device is busy.  Only 1 vnode using it should be
   * open -- the root vnode -- and that inode only 1 time. */
  locks = count = 0;
  for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++)
	  if (vp->v_ref_count > 0 && vp->v_dev == dev) {
		count += vp->v_ref_count;
		if (is_vnode_locked(vp)) locks++;
	  }

  if (count > 1 || locks > 1 || tll_haspendinglock(&vmp->m_lock)) {
	unlock_vmnt(vmp);
	return(EBUSY);    /* can't umount a busy file system */
  }

  /* Tell FS to drop all inode references for root inode except 1. */
  vnode_clean_refs(vmp->m_root_node);

  if (vmp->m_mounted_on) {
	put_vnode(vmp->m_mounted_on);
	vmp->m_mounted_on = NULL;
  }

  vmp->m_comm.c_max_reqs = 1;	/* Force max concurrent reqs to just one, so
				 * we won't send any messages after the
				 * unmount request */

  /* Tell FS to unmount */
  if ((r = req_unmount(vmp->m_fs_e)) != OK)              /* Not recoverable. */
	printf("VFS: ignoring failed umount attempt FS endpoint: %d (%d)\n",
	       vmp->m_fs_e, r);

  if (is_nonedev(vmp->m_dev)) free_nonedev(vmp->m_dev);

  if (label != NULL) strlcpy(label, vmp->m_label, LABEL_MAX);

  if (vmp->m_root_node) {	/* PFS lacks a root node */
	vmp->m_root_node->v_ref_count = 0;
	vmp->m_root_node->v_fs_count = 0;
	vmp->m_root_node->v_sdev = NO_DEV;
	vmp->m_root_node = NULL;
  }
  mark_vmnt_free(vmp);

  unlock_vmnt(vmp);

  /* The root FS will handle block I/O requests for this device now. */
  lock_bsf();
  update_bspec(dev, ROOT_FS_E, 1 /* send new driver endpoint */);
  unlock_bsf();

  return(OK);
}
Пример #5
0
/*===========================================================================*
 *				read_write				     *
 *===========================================================================*/
int read_write(struct fproc *rfp, int rw_flag, struct filp *f,
	vir_bytes buf, size_t size, endpoint_t for_e)
{
  register struct vnode *vp;
  off_t position, res_pos;
  unsigned int cum_io, cum_io_incr, res_cum_io;
  int op, r;
  dev_t dev;

  position = f->filp_pos;
  vp = f->filp_vno;
  r = OK;
  cum_io = 0;

  assert(rw_flag == READING || rw_flag == WRITING || rw_flag == PEEKING);

  if (size > SSIZE_MAX) return(EINVAL);

  op = (rw_flag == READING ? CDEV_READ : CDEV_WRITE);

  if (S_ISFIFO(vp->v_mode)) {		/* Pipes */
	if (rfp->fp_cum_io_partial != 0) {
		panic("VFS: read_write: fp_cum_io_partial not clear");
	}
	if(rw_flag == PEEKING) {
	  	printf("read_write: peek on pipe makes no sense\n");
		return EINVAL;
	}
	r = rw_pipe(rw_flag, for_e, f, buf, size);
  } else if (S_ISCHR(vp->v_mode)) {	/* Character special files. */
	if(rw_flag == PEEKING) {
	  	printf("read_write: peek on char device makes no sense\n");
		return EINVAL;
	}

	if (vp->v_sdev == NO_DEV)
		panic("VFS: read_write tries to access char dev NO_DEV");

	dev = vp->v_sdev;

	r = cdev_io(op, dev, for_e, buf, position, size, f->filp_flags);
	if (r >= 0) {
		/* This should no longer happen: all calls are asynchronous. */
		printf("VFS: I/O to device %llx succeeded immediately!?\n", dev);
		cum_io = r;
		position += r;
		r = OK;
	} else if (r == SUSPEND) {
		/* FIXME: multiple read/write operations on a single filp
		 * should be serialized. They currently aren't; in order to
		 * achieve a similar effect, we optimistically advance the file
		 * position here. This works under the following assumptions:
		 * - character drivers that use the seek position at all,
		 *   expose a view of a statically-sized range of bytes, i.e.,
		 *   they are basically byte-granular block devices;
		 * - if short I/O or an error is returned, all subsequent calls
		 *   will return (respectively) EOF and an error;
		 * - the application never checks its own file seek position,
		 *   or does not care that it may end up having seeked beyond
		 *   the number of bytes it has actually read;
		 * - communication to the character driver is FIFO (this one
		 *   is actually true! whew).
		 * Many improvements are possible here, but in the end,
		 * anything short of queuing concurrent operations will be
		 * suboptimal - so we settle for this hack for now.
		 */
		position += size;
	}
  } else if (S_ISBLK(vp->v_mode)) {	/* Block special files. */
	if (vp->v_sdev == NO_DEV)
		panic("VFS: read_write tries to access block dev NO_DEV");

	lock_bsf();

	if(rw_flag == PEEKING) {
		r = req_bpeek(vp->v_bfs_e, vp->v_sdev, position, size);
	} else {
		r = req_breadwrite(vp->v_bfs_e, for_e, vp->v_sdev, position,
		       size, buf, rw_flag, &res_pos, &res_cum_io);
		if (r == OK) {
			position = res_pos;
			cum_io += res_cum_io;
		}
	}

	unlock_bsf();
  } else {				/* Regular files */
	if (rw_flag == WRITING) {
		/* Check for O_APPEND flag. */
		if (f->filp_flags & O_APPEND) position = vp->v_size;
	}

	/* Issue request */
	if(rw_flag == PEEKING) {
		r = req_peek(vp->v_fs_e, vp->v_inode_nr, position, size);
	} else {
		off_t new_pos;
		r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, position,
			rw_flag, for_e, buf, size, &new_pos,
			&cum_io_incr);

		if (r >= 0) {
			position = new_pos;
			cum_io += cum_io_incr;
		}
        }
  }

  /* On write, update file size and access time. */
  if (rw_flag == WRITING) {
	if (S_ISREG(vp->v_mode) || S_ISDIR(vp->v_mode)) {
		if (position > vp->v_size) {
			vp->v_size = position;
		}
	}
  }

  f->filp_pos = position;

  if (r == EPIPE && rw_flag == WRITING) {
	/* Process is writing, but there is no reader. Tell the kernel to
	 * generate s SIGPIPE signal.
	 */
	if (!(f->filp_flags & O_NOSIGPIPE)) {
		sys_kill(rfp->fp_endpoint, SIGPIPE);
	}
  }

  if (r == OK) {
	return(cum_io);
  }
  return(r);
}