// 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 }
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 }