Example #1
0
// Create a new FileSystem from a given file on the filesystem
func NewFileSystem(dev common.BlockDevice) (*FileSystem, *Process, error) {
	// Check to make sure we have a valid device
	devinfo, err := common.GetDeviceInfo(dev)
	if err != nil {
		return nil, nil, err
	}

	fs := new(FileSystem)

	fs.devices = make([]common.BlockDevice, common.NR_DEVICES)
	fs.devinfo = make([]*common.DeviceInfo, common.NR_DEVICES)

	fs.bcache = bcache.NewLRUCache(common.NR_DEVICES, common.NR_BUFS, common.NR_BUF_HASH)
	fs.itable = inode.NewCache(fs.bcache, common.NR_DEVICES, common.NR_INODES)

	devinfo.Devnum = common.ROOT_DEVICE

	if err := fs.bcache.MountDevice(common.ROOT_DEVICE, dev, devinfo); err != nil {
		log.Printf("Could not mount root device: %s", err)
		return nil, nil, err
	}
	fs.itable.MountDevice(common.ROOT_DEVICE, devinfo)

	devinfo.AllocTbl = alloctbl.NewAllocTbl(devinfo, fs.bcache, common.ROOT_DEVICE)

	fs.devices[common.ROOT_DEVICE] = dev
	fs.devinfo[common.ROOT_DEVICE] = devinfo

	fs.procs = make(map[int]*Process, common.NR_PROCS)

	fs.in = make(chan reqFS)
	fs.out = make(chan resFS)

	// Fetch the root inode
	rip, err := fs.itable.GetInode(common.ROOT_DEVICE, common.ROOT_INODE)
	if err != nil {
		log.Printf("Failed to fetch root inode: %s", err)
		return nil, nil, err
	}

	// Create the root process
	fs.procs[common.ROOT_PROCESS] = &Process{
		common.ROOT_PROCESS,
		022,
		rip,
		rip,
		make([]*filp, common.OPEN_MAX),
		fs,
	}

	// Initialite the pidcounter
	fs.pidcounter = common.ROOT_PROCESS + 1

	go fs.loop()

	return fs, fs.procs[common.ROOT_PROCESS], nil
}
Example #2
0
func (fs *FileSystem) do_mount(proc *Process, dev common.BlockDevice, path string) error {
	if dev == nil {
		return common.EINVAL
	}

	// scan bitmap block table to see if 'dev' is already mounted
	found := false
	freeIndex := -1
	for i := 0; i < common.NR_DEVICES; i++ {
		if fs.devices[i] == dev {
			found = true
		} else if fs.devices[i] == nil {
			freeIndex = i
		}
	}

	if found {
		return common.EBUSY // already mounted
	}

	if freeIndex == -1 {
		return common.ENFILE // no device slot available
	}

	// Invalidate the cache for this index to be sure
	fs.bcache.Invalidate(freeIndex)

	// Fill in the device info
	devinfo, err := common.GetDeviceInfo(dev)

	// If it a recognized Minix filesystem
	if err != nil {
		return err
	}

	// Create a new allocation table for this device
	alloc := alloctbl.NewAllocTbl(devinfo, fs.bcache, freeIndex)

	// Update the device number/alloc table
	devinfo.Devnum = freeIndex
	devinfo.AllocTbl = alloc

	// Add the device to the block cache/inode table
	fs.bcache.MountDevice(freeIndex, dev, devinfo)
	fs.itable.MountDevice(freeIndex, devinfo)
	fs.devices[freeIndex] = dev
	fs.devinfo[freeIndex] = devinfo

	// Get the inode of the file to be mounted on
	rip, err := fs.eatPath(fs.procs[common.ROOT_PROCESS], path)

	if err != nil {
		// Perform lots of cleanup
		fs.devices[freeIndex] = nil
		fs.devinfo[freeIndex] = nil
		fs.bcache.UnmountDevice(freeIndex)
		fs.itable.UnmountDevice(freeIndex)
		return err
	}

	var r error = nil

	// It may not be busy
	if rip.Count > 1 {
		r = common.EBUSY
	}

	// It may not be spacial
	bits := rip.Type()
	if bits == common.I_BLOCK_SPECIAL || bits == common.I_CHAR_SPECIAL {
		r = common.ENOTDIR
	}

	// Get the root inode of the mounted file system
	var root_ip *common.Inode
	if r == nil {
		root_ip, err = fs.itable.GetInode(freeIndex, common.ROOT_INODE)
		if err != nil {
			r = err
		}
	}

	if root_ip != nil && root_ip.Mode == 0 {
		r = common.EINVAL
	}

	// File types of 'rip' and 'root_ip' may not conflict
	if r == nil {
		if !rip.IsDirectory() && root_ip.IsDirectory() {
			r = common.EISDIR
		}
	}

	// If error, return the bitmap and both inodes; release the maps
	if r != nil {
		// TODO: Refactor this error handling code?
		// Perform lots of cleanup
		fs.devices[freeIndex] = nil
		fs.devinfo[freeIndex] = nil
		fs.bcache.UnmountDevice(freeIndex)
		fs.itable.UnmountDevice(freeIndex)
		return r
	}

	// Nothing else can go wrong, so perform the mount
	minfo := &common.MountInfo{
		MountPoint:  rip,
		MountTarget: root_ip,
	}
	rip.Mounted = minfo     // so we can find the root inode during lookup
	root_ip.Mounted = minfo // so we can easily resolve from a mount target to the mount point

	// Store the mountinfo in the device info table for easy mapping
	devinfo.MountInfo = minfo
	return nil
}