Ejemplo n.º 1
0
// Write at most 'n' bytes from 'buf' to 'fd' at the current seek position.
// Advance 'fd->f_offset' by the number of bytes written.
//
// Returns:
//	 The number of bytes successfully written.
//	 < 0 on error.
static ssize_t
devfile_write(struct Fd *fd, const void *buf, size_t n)
{
	// Use inode_open, inode_close, maybe inode_set_size, and inode_data.
	// Be careful of block boundaries!
	// Flush any blocks you change using BCREQ_FLUSH.
	//
	// LAB 5: Your code here.
    int r;
    size_t orig_offset = fd->fd_offset;
    struct Inode *ino;
    if((r = inode_open(fd->fd_file.inum, &ino)) < 0)
        return r;
    void *data;
    size_t n2 = ROUNDUP(fd->fd_offset, PGSIZE) - fd->fd_offset;
    if (n2 > n)
        n2 = n;
    if(n2)
    {
        n -= n2;
        if(fd->fd_offset + n2 > (size_t)ino->i_size && 
           inode_set_size(ino, fd->fd_offset + n2) < 0)
            goto wrapup;
        data = inode_data(ino, fd->fd_offset);
        memcpy(data, buf, n2);
        fd->fd_offset += n2;
        bcache_ipc(data, BCREQ_FLUSH);
        buf = (void *)((char *)buf + n2);
    }
    while (n / PGSIZE)
    {
        if(fd->fd_offset + PGSIZE > (size_t)ino->i_size && 
           inode_set_size(ino, fd->fd_offset + PGSIZE) < 0)
            goto wrapup;
        data = inode_data(ino, fd->fd_offset);
        memcpy(data, buf, PGSIZE);
        bcache_ipc(data, BCREQ_FLUSH);
        n -= PGSIZE;
        buf = (void *)((char *)buf + PGSIZE);
        fd->fd_offset += PGSIZE;
    }
    if (n > 0)
    {
        if(fd->fd_offset + n > (size_t)ino->i_size && 
           inode_set_size(ino, fd->fd_offset + n) < 0)
            goto wrapup;
        data = inode_data(ino, fd->fd_offset);
        memcpy(data, buf, n);
        bcache_ipc(data, BCREQ_FLUSH);
        fd->fd_offset += n;
    }

wrapup:
    inode_close(ino);
    return fd->fd_offset - orig_offset;
}
Ejemplo n.º 2
0
/*!
 * \ingroup lowlevel-api
 *
 * Allocates an inode.
 *
 * \param  fs  a pointer to the FS filesystem handle
 * \return     the index of the allocated inode
 *
 * \throws fs_error               thrown if an error occurs
 * \throws std::invalid_argument  thrown if \a fs is null
 *
 */
uint32_t fs_alloc_inode(FS* fs)
{
	if (!fs)
		throw std::invalid_argument("fs_alloc_inode  invalid arg: fs");

	fs_guard lock(fs->lock);

	debug::tracer DT;
	DT << "allocating inode";

	if (0 == FS_FREE_ITABLE_INODES(fs))
		fs_add_itable_group(fs);

	uint32_t ino = 0;
	if (!fs_find_next_free_ino(fs, ino))
		throw fs_error(ERROR_NOSPACE, "fs_alloc_inode  out of space");

	fs_write_inode(fs, ino, inode_data());
	fs_mark_inode(fs, ino, true);

	fs->super.f_inode_alloc += 1;
	mark_super_dirty(fs);

	DT << "allocated inode " << ino;

	return ino;
}
Ejemplo n.º 3
0
// Read at most 'n' bytes from 'fd' at the current position into 'buf'.
// Advance 'fd->f_offset' by the number of bytes read.
//
// Returns:
// 	The number of bytes successfully read.
// 	< 0 on error.
static ssize_t
devfile_read(struct Fd *fd, void *buf, size_t n)
{
	// Use inode_open, inode_close, and inode_data.
	// Be careful of block boundaries!
	//
	// LAB 5: Your code here.
    int r;
    ssize_t orig_offset = fd->fd_offset;
    struct Inode *ino;
    if((r = inode_open(fd->fd_file.inum, &ino)) < 0)
        return r;

    void *data;
    if (n + fd->fd_offset > (size_t)ino->i_size)
        n = ino->i_size - fd->fd_offset;
    size_t n2 = ROUNDUP(fd->fd_offset, PGSIZE) - fd->fd_offset;
    if (n2 > n)
        n2 = n;
    n -= n2;
    if((data = inode_data(ino, fd->fd_offset)) == 0)
        goto wrapup;
    fd->fd_offset += n2;
    memcpy(buf, data, n2);
    buf = (void *)((char *)buf + n2);
    while (n / PGSIZE)
    {
        if((data = inode_data(ino, fd->fd_offset)) == 0)
            goto wrapup;
        memcpy(buf, data, PGSIZE);
        n -= PGSIZE;
        buf = (void *)((char *)buf + PGSIZE);
        fd->fd_offset += PGSIZE;
    }
    if (n > 0)
    {
        if((data = inode_data(ino, fd->fd_offset)) == 0)
            goto wrapup;
        memcpy(buf, data, n);
        fd->fd_offset += n;
    }

wrapup:
    inode_close(ino);
    return fd->fd_offset - orig_offset;
}
Ejemplo n.º 4
0
// Find a directory entry in the 'ino' directory.
// Looks for name 'name' with length 'namelen'.
// If 'create != 0', such an entry is created if none is found.
//   A newly created entry will have de_inum == 0.
// Returns 0 on success (storing a pointer to the struct Direntry in
//   *de_store), and < 0 on error.
// Error codes:
//	-E_BAD_PATH if 'ino' is not a directory.
//	-E_NO_DISK if out of space.
//	(possibly others)
//
static int
dir_find(struct Inode *ino, const char *name, int namelen,
	 struct Direntry **de_store, int create)
{
	off_t off;
	struct Direntry *empty = 0;

	*de_store = 0;

	if (ino->i_ftype != FTYPE_DIR)
		return -E_BAD_PATH;

	for (off = 0; off < ino->i_size; off += sizeof(struct Direntry)) {
		struct Direntry *de = (struct Direntry *) inode_data(ino, off);

		if (de->de_inum != 0
		    && de->de_namelen == namelen
		    && memcmp(de->de_name, name, namelen) == 0) {
			*de_store = de;
			return 0;
		}

		if (de->de_inum == 0 && !empty)
			empty = de;
	}

	if (!create)
		return -E_NOT_FOUND;

	if (!empty) {
		int r = inode_set_size(ino, ino->i_size + sizeof(struct Direntry));
		if (r < 0)
			return r;
		empty = (struct Direntry *) inode_data(ino, ino->i_size - sizeof(struct Direntry));
	}

	memset(empty, 0, sizeof(struct Direntry));
	empty->de_namelen = namelen;
	memcpy(empty->de_name, name, namelen);
	*de_store = empty;
	return 0;
}
Ejemplo n.º 5
0
/*!
 * \ingroup lowlevel-api
 *
 * Read an inode.
 *
 * \param  fs   a pointer to the filesystem handle
 * \param  ino  the number of the inode to read
 * \return      the inode data
 *
 */
inode_data fs_read_inode(FS* fs, uint32_t ino)
{
	if (!fs)
		throw std::invalid_argument("fs_read_inode  invalid arg: fs");

	fs_guard lock(fs->lock);

	debug::tracer DT;
	DT.trace() << "reading inode " << ino;

	if (0 == ino)
		return fs->super.f_itable_data;

	if (ino > FS_ITABLE_INODE_CAPACITY(fs))
		throw std::invalid_argument("fs_read_inode  invalid arg: ino");

	uint32_t logical = fs_get_inode_blockno(fs, ino);
	uint32_t physical = translate_itable_blockno(fs->itable, logical);

	if (0 == physical)
		return inode_data();

	std::vector< char > buf(fs->blocksize, 0);
	fs_read_block(fs, physical, buf.data(), buf.size());

	// The arithmetic below requires ino to be 0-based!
	--ino;

	// Calculate the byte-offset in the block at which we can find
	// the requested inode.
	uint32_t inodes_per_block = fs->blocksize / INODE_SIZE;
	uint32_t offset = INODE_SIZE * (ino % inodes_per_block);

	inode_data data;
	deserialize_inode(buf.data() + offset, data);
	return data;
}
Ejemplo n.º 6
0
// Checks file system structures.
// Checks all file system invariants hold and prints out any errors it finds.
// Does no locking, so if run in parallel with other environments, it can
// get confused and report transient "errors."
// Returns 0 if the file system is OK, -E_INVAL if any errors were found.
//
int
fsck(void)
{
	blocknum_t min_nblocks;
	int i, j, k;
	int errors = 0;

	add_pgfault_handler(bcache_pgfault_handler);

	// superblock checks
	if (super->s_magic != FS_MAGIC)
		panic("fsck: file system magic number %08x should be %08x", super->s_magic, FS_MAGIC);
	if (super->s_nblocks < 4)
		panic("fsck: file system must have at least 4 blocks");
	if (super->s_ninodes < 1)
		panic("fsck: file system must have at least 1 inode");
	min_nblocks = 2 /* boot sector, superblock */
		+ ROUNDUP(super->s_nblocks, BLKSIZE) / BLKSIZE /* freemap */
		+ (super->s_ninodes - 1); /* inodes */
	if (super->s_nblocks < min_nblocks)
		panic("fsck: file system with %d inodes has %d blocks, needs at least %d", super->s_ninodes, super->s_nblocks, min_nblocks);

	// basic freemap checks: initial blocks not free, free blocks marked
	// with 1 (later checks will overwrite freemap)
	for (i = 0; i < super->s_nblocks; ++i)
		if (i < min_nblocks && freemap[i] != 0) {
			cprintf("fsck: freemap[%d]: should be 0 (allocated), is %d\n", i, freemap[i]);
			++errors;
		} else if (freemap[i] != 0 && freemap[i] != 1) {
			cprintf("fsck: freemap[%d]: should be 0 or 1, is %d\n", i, freemap[i]);
			++errors;
			freemap[i] = (freemap[i] > 0 ? 1 : 0);
		}

	// inode checks: inode 1 is referenced, unreferenced inodes
	// have no data pointers, ftype makes sense, no data pointer overlap
	for (i = 1; i < super->s_ninodes; ++i) {
		struct Inode *ino = get_inode(i);
		off_t true_size;
		// check for open-but-unreferenced inode; be careful of
		// uninitialized inodes (use bcache_ipc to check)
		bool active = ino->i_refcount != 0;
		if (!active && ino->i_opencount != 0
		    && bcache_ipc(ino, BCREQ_MAP) != 0)
			active = true;
		if (active && ino->i_ftype != FTYPE_REG && ino->i_ftype != FTYPE_DIR) {
			cprintf("fsck: inode[%d]: odd i_ftype %d\n", i, ino->i_ftype);
			++errors;
		}
		if (i == 1 && ino->i_refcount == 0) {
			cprintf("fsck: inode[1]: root inode should be referenced\n");
			++errors;
		} else if (i == 1 && ino->i_ftype != FTYPE_DIR) {
			cprintf("fsck: inode[1]: root inode should be directory\n");
			++errors;
		}
		if (active && ino->i_size > MAXFILESIZE) {
			cprintf("fsck: inode[%d]: size %d too large\n", i, ino->i_size);
			++errors;
		}
		if (active && ino->i_inum != i) {
			cprintf("fsck: inode[%d]: wrong inumber %d\n", i, ino->i_inum);
			++errors;
		}
		true_size = active ? ino->i_size : 0;
		for (j = 0; j < NDIRECT; ++j) {
			blocknum_t b = ino->i_direct[j];
			if (j * BLKSIZE < true_size && !b) {
				cprintf("fsck: inode[%d]: direct block %d is null, though file size is %d\n", i, j, true_size);
				++errors;
			} else if (j * BLKSIZE >= true_size && b && active) {
				cprintf("fsck: inode[%d]: direct block %d exists, though file size is %d\n", i, j, true_size);
				++errors;
			}
			if (b && active) {
				if (b < min_nblocks) {
					cprintf("fsck: inode[%d]: direct block %d == %d is in special block range\n", i, j, b);
					++errors;
				} else if (freemap[b] == 1) {
					cprintf("fsck: inode[%d]: direct block %d == %d is marked as free\n", i, j, b);
					++errors;
				} else if (freemap[b] == -1) {
					cprintf("fsck: inode[%d]: direct block %d == %d used more than once\n", i, j, b);
					++errors;
				} else
					freemap[b] = -1;
			}
		}
		ino->i_fsck_refcount = (i == 1 ? 1 : 0);
		ino->i_fsck_checked = 0;
	}

	// directory checks
	while (1) {
		struct Inode *ino;
		for (i = 1; i < super->s_ninodes; ++i) {
			ino = get_inode(i);
			if (ino->i_fsck_refcount > 0
			    && !ino->i_fsck_checked
			    && ino->i_ftype == FTYPE_DIR)
				goto check_directory_inode;
		}
		break;

	check_directory_inode:
		ino->i_fsck_checked = 1;
		if (ino->i_size % sizeof(struct Direntry) != 0) {
			cprintf("inode[%d]: directory size %d not multiple of %d\n", i, ino->i_size, sizeof(struct Direntry));
			++errors;
		}
		for (j = 0; (off_t) (j + sizeof(struct Direntry)) <= ino->i_size; j += sizeof(struct Direntry)) {
			struct Direntry *de = (struct Direntry *) inode_data(ino, j);
			char name[MAXNAMELEN];
			int namelen;

			if (de->de_inum == 0)
				continue;

			if (de->de_namelen <= 0 || de->de_namelen >= MAXNAMELEN) {
				cprintf("inode[%d] de@%d: bad filename length %d\n", i, j, de->de_namelen);
				++errors;
			} else if (de->de_name[de->de_namelen] != 0) {
				cprintf("inode[%d] de@%d: filename is not null terminated\n", i, j);
				++errors;
			}
			memcpy(name, de->de_name, MAXNAMELEN);
			namelen = MAX(MIN(de->de_namelen, MAXNAMELEN - 1), 0);
			name[namelen] = 0;

			if (de->de_inum >= super->s_ninodes) {
				cprintf("inode[%d] de@%d (%s): inode %d out of range\n", i, j, name, de->de_inum);
				++errors;
			} else {
				struct Inode *refed = get_inode(de->de_inum);
				++refed->i_fsck_refcount;
				if (refed->i_refcount == 0) {
					cprintf("inode[%d] de@%d (%s): refers to free inode %d\n", i, j, name, de->de_inum);
					++errors;
				}
			}
			for (k = 0; k < j && de->de_namelen < MAXNAMELEN; k += sizeof(struct Direntry)) {
				struct Direntry *xde = (struct Direntry *) inode_data(ino, k);
				if (xde->de_inum != 0
				    && xde->de_namelen == namelen
				    && memcmp(xde->de_name, name, namelen) == 0) {
					cprintf("inode[%d] de@%d (%s): same filename as de@%d\n", i, j, name, k);
					++errors;
				}
			}
		}
	}

	// refcount consistency
	for (i = 1; i < super->s_ninodes; ++i) {
		struct Inode *ino = get_inode(i);
		if (ino->i_refcount != ino->i_fsck_refcount) {
			cprintf("fsck: inode[%d]: refcount %d should be %d\n", i, ino->i_refcount, ino->i_fsck_refcount);
			++errors;
		}
	}

	// clean up freemap
	for (i = 0; i < super->s_nblocks; ++i)
		if (freemap[i] == -1)
			freemap[i] = 0;
		else if (freemap[i] == 0 && i >= min_nblocks) {
			cprintf("fsck: freemap[%d]: unreferenced block is not free\n", i);
			++errors;
		}

	return errors ? -E_INVAL : 0;
}