Пример #1
0
func (file *server_File) loop() {
	alive := true
	for alive {
		req := <-file.in
		switch req := req.(type) {
		case req_File_Read:
			// Indicate we have another outstanding reader
			file.wg.Add(1)
			callback := make(chan resFile)
			file.out <- res_File_Async{callback}

			// Launch a new goroutine to perform the read, using the callback
			// channel to return the result.
			go func() {
				n, err := common.Read(file.rip, req.buf, req.pos)
				callback <- res_File_Read{n, err}
				file.wg.Done() // signal completion
			}()
		case req_File_Write:
			file.wg.Wait() // wait for any outstanding reads to complete before proceeding
			n, err := common.Write(file.rip, req.buf, req.pos)
			file.out <- res_File_Write{n, err}
		case req_File_Truncate:
			file.wg.Wait() // wait for any outstanding reads to complete before proceeding
			common.Truncate(file.rip, req.size, file.rip.Bcache)
			file.out <- res_File_Truncate{}
		case req_File_Fstat:
			// Code here
		case req_File_Sync:
			// Code here
		case req_File_Dup:
			file.count++
			file.out <- res_File_Dup{}
		case req_File_Close:
			file.wg.Wait() // wait for any outstanding reads to complete before proeceding
			file.count--

			// Let's push our changes to the inode cache
			file.rip.Icache.FlushInode(file.rip)
			file.rip.Icache.PutInode(file.rip)

			if file.count == 0 {
				alive = false
			}

			file.out <- res_File_Close{}
		}
	}
}
Пример #2
0
func (fs *FileSystem) do_open(proc *Process, path string, oflags int, omode uint16) (common.Fd, error) {
	// Remap the bottom two bits of oflags
	bits := mode_map[oflags&common.O_ACCMODE]

	var err error
	var rip *common.Inode
	var exist bool = false

	// If O_CREATE is set, try to make the file
	if oflags&common.O_CREAT > 0 {
		// Create a new node by calling new_node()
		omode := common.I_REGULAR | (omode & common.ALL_MODES & proc.umask)
		dirp, newrip, _, err := fs.new_node(proc, path, omode, common.NO_ZONE)
		if err == nil {
			exist = false
		} else if err != common.EEXIST {
			return nil, err
		} else {
			exist = (oflags&common.O_EXCL == 0)
		}

		// we don't need the parent directory
		fs.itable.PutInode(dirp)
		rip = newrip
	} else {
		// grab the inode at the given path
		rip, err = fs.eatPath(proc, path)
		if err != nil {
			return nil, err
		}
	}

	// Find an available filp entry for the file descriptor
	fdindex := -1
	for i := 0; i < len(proc.files); i++ {
		if proc.files[i] == nil {
			fdindex = i
			break
		}
	}

	if fdindex == -1 {
		return nil, common.EMFILE
	}

	err = nil // we'll use this to set error codes

	if exist { // if the file existed already
		// TODO: Check permissions here
		switch rip.Type() {
		case common.I_REGULAR:
			if oflags&common.O_TRUNC > 0 {
				common.Truncate(rip, 0, fs.bcache)
				// Flush the inode so it gets written on next block cache
				fs.itable.FlushInode(rip)
			}
		case common.I_DIRECTORY:
			// Directories cannot be opened in this system
			err = common.EISDIR
		default:
			panic("NYI: Process.Open with non regular/directory")
		}
	}

	if err != nil {
		// Something went wrong, so release the inode
		fs.itable.PutInode(rip)
		return nil, err
	}

	// Make sure there is a 'File' server running
	if rip.File == nil {
		// Spawn a file process to handle reading/writing
		rip.File = file.NewFile(rip)
	}

	// Create a new 'filp' object to expose to the user
	filp := &filp{1, 0, rip.File, rip, bits, new(sync.Mutex)}
	proc.files[fdindex] = filp

	return filp, nil
}
Пример #3
0
func (itable *server_InodeTbl) loop() {
	alive := true
	for alive {
		req := <-itable.in
		switch req := req.(type) {
		case req_InodeTbl_MountDevice:
			itable.devices[req.devnum] = req.info
			itable.out <- res_InodeTbl_MountDevice{}
		case req_InodeTbl_UnmountDevice:
			itable.devices[req.devnum] = nil
			itable.out <- res_InodeTbl_UnmountDevice{}
		case req_InodeTbl_GetInode:
			// Create an channel on which the inode result will be delivered
			callback := make(chan resInodeTbl)

			// Find the cache slot for an inode, or a candidate slot in which
			// the inode can be loaded.`
			slotIndex := itable.findSlot(req.devnum, req.inum)
			if slotIndex == common.NO_INODE || slotIndex >= len(itable.slots) {
				// Inode table is completely full!
				itable.out <- res_InodeTbl_Async{callback}
				callback <- res_InodeTbl_GetInode{nil, common.ENFILE}
			} else {
				xp := itable.slots[slotIndex].inode
				if xp.Count > 0 {
					// We found the inode, so return it
					slot := itable.slots[slotIndex]
					xp.Count++
					itable.out <- res_InodeTbl_Async{callback}
					slot.ReturnOrQueue(callback)
				} else {
					// Need to load the inode asynchronously, so make sure the
					// cache slot isn't claimed by someone else in the meantime
					slot := itable.slots[slotIndex]
					xp.Devinfo = itable.devices[req.devnum]
					xp.Inum = req.inum
					xp.Count++

					slot.Queue(callback)

					go func() {
						// Load the inode into the Inode
						itable.loadInode(xp)
						// Notify anyone waiting for this slot
						slot.FinishedLoading(xp)
					}()

					itable.out <- res_InodeTbl_Async{callback}
				}
			}
		case req_InodeTbl_DupInode:
			// Given an inode, duplicate it by incrementing its count
			rip := req.inode
			rip.Count++
			itable.out <- res_InodeTbl_DupInode{rip}
		case req_InodeTbl_PutInode:
			rip := req.inode

			if rip == nil {
				itable.out <- res_InodeTbl_PutInode{}
				continue
			}

			rip.Count--
			if rip.Count == 0 { // means no one is using it now
				if rip.Nlinks == 0 { // free the inode
					common.Truncate(rip, 0, itable.bcache) // return all the disk blocks
					rip.Mode = common.I_NOT_ALLOC
					rip.Dirty = true
					rip.Devinfo.AllocTbl.FreeInode(rip.Inum)
				} else {
					// TODO: Handle the pipe case here
					// if rip.pipe == true {
					//   truncate(rip)
					// }
				}
				// rip.pipe = false

				if rip.Dirty {
					// Write this inode out to disk
					// TODO: Should this be performed asynchronously?
					itable.writeInode(rip)
				}
			}

			itable.out <- res_InodeTbl_PutInode{}
		case req_InodeTbl_FlushInode:
			rip := req.inode

			if rip == nil {
				itable.out <- res_InodeTbl_FlushInode{}
			} else {
				itable.writeInode(rip)
			}
			itable.out <- res_InodeTbl_FlushInode{}
		case req_InodeTbl_IsDeviceBusy:
			count := 0
			for i := 0; i < len(itable.slots); i++ {
				rip := itable.slots[i].inode
				if rip.Count > 0 && rip.Devinfo.Devnum == req.devnum {
					count += rip.Count
				}
			}
			itable.out <- res_InodeTbl_IsDeviceBusy{count > 1}
		case req_InodeTbl_Shutdown:
			for i := 0; i < len(itable.devices); i++ {
				if itable.devices[i] != nil {
					itable.out <- res_InodeTbl_Shutdown{common.EBUSY}
					continue
				}
			}
			itable.out <- res_InodeTbl_Shutdown{nil}
			alive = false
		}
	}
}