Example #1
0
static int lfs_readpage(struct file *file, struct page *page)
{	
	struct inode *inode = page->mapping->host;
	sector_t iblock, block;
	unsigned int blocksize;
	struct buffer_head *bh, *head;

	blocksize = 1 << inode->i_blkbits;
	if (!page_has_buffers(page))
		create_empty_buffers(page, blocksize, 0);
	head = page_buffers(page);
	bh = head;

	iblock = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
	do {
		struct buffer_head *bh_temp;
		block = lfs_disk_block(inode, iblock);

		dprintk("searching for block %Lu in segments: ", (long long unsigned int)block);
		bh_temp = lfs_read_block(inode, iblock);
		if(bh_temp) {
			dprintk("FOUND\n");

			memcpy(bh->b_data, bh_temp->b_data, LFS_BSIZE);
			set_buffer_uptodate(bh);
			brelse(bh_temp);
		}
		else
			dprintk("NOT FOUND\n");
	} while (iblock++, (bh = bh->b_this_page) != head);
	return block_read_full_page(page, lfs_map_block);
}
Example #2
0
File: seguse.c Project: ppadala/lfs
/* Reads the seguse entry for the corresponding segment and returns the 
 * buffer head containing it. Note that *pseguse points to the segusage within 
 * the returned buffer head data
 */
static struct buffer_head *segusetbl_read_entry(
	struct super_block *sb, int segnum, struct segusage **pseguse)
{
	int offset, iblock;
	struct buffer_head *bh;
	struct inode *inode = SEGUSETBL_INODE(sb);

	if(segnum > nseguse(inode) - 1) /* new entry */
		return NULL;

	/* read the block from the disk */
	iblock = get_iblock_nr(segnum);
	//dprintk("iblock for segusetable = %d\n", iblock);
	bh = lfs_read_block(inode, iblock);
	if(!bh)
		return NULL;

	offset = LFS_CI_SIZE + LFS_SEGUSE_SIZE * segnum;
	offset -= iblock * LFS_BSIZE;
	*pseguse = (struct segusage *)((char *)bh->b_data + offset);

	return bh; /* caller has to release the bh, after done with *pseguse */
}
Example #3
0
static int lfs_readdir (struct file * f, void * dirent, filldir_t filldir)
{
	lfs_dirent *de;
	int block;
	int reclen = LFS_DIRENT_RECLEN;
	unsigned int offset;
	struct buffer_head * bh;
	struct inode * dir = f->f_dentry->d_inode;

	while (f->f_pos < dir->i_size) {
		offset = f->f_pos & (LFS_BSIZE-1);
		block = f->f_pos >> LFS_BSIZE_BITS;
		bh = lfs_read_block(dir, block);
		if (!bh)
			goto err_eio;
		do {
			//dprintk("block = %d, offset = %d\n", block, offset);
			de = (lfs_dirent *)(bh->b_data + offset);
			if (de->inode) {
				//dprintk("Filling entries for %d %s %d\n", de->inode, de->name, de->name_len);
				if (filldir(dirent, de->name, de->name_len, f->f_pos, de->inode, DT_UNKNOWN) < 0) {
					brelse(bh);
					goto done;
				}
			}
			offset += reclen;
			f->f_pos += reclen;
		} while (offset < LFS_BSIZE && f->f_pos < dir->i_size);
		brelse(bh);
	}

done:
	return 0;
err_eio:
	return -EIO;
}
Example #4
0
/* FIXME: Ugliest function of all in LFS, need I say more? */
static ssize_t lfs_file_write( 	struct file *file, const char __user *buf, 	
				size_t count, loff_t *ppos)
{	
	loff_t pos;
	struct page *page;
	ssize_t res, written, bytes;
	struct inode *inode = file->f_dentry->d_inode;
	struct super_block *sb = inode->i_sb;
	struct segment *segp = LFS_SBI(sb)->s_curr;

	//dprintk("lfs_file_write called for %lu at pos %Lu\n", inode->i_ino, *ppos);
	if(file->f_flags & O_DIRECT) {
		dprintk("The file is requesting direct IO\n");
		return -EINVAL;
	}

	if (unlikely(count < 0 ))
		return -EINVAL;
	if (unlikely(!access_ok(VERIFY_READ, buf, count)))
		return -EFAULT;

	//down(&inode->i_sem);	/* lock the file */
	mutex_lock(&inode->i_mutex); //BrechREiZ: We need this for Kernel 2.6.17
	lfs_lock(sb);
		
	pos = *ppos;
	res = generic_write_checks(file, &pos, &count, 0);
	if (res)
		goto out;
	if(count == 0)
		goto out;
	
	res = remove_suid(file->f_dentry);
	if(res)
		goto out;
	//inode_update_time(inode, 1);	/* update mtime and ctime */
	file_update_time(inode); //BrechREiZ: We need this for Kernel 2.6.17

	written = 0;
	do {
		long offset;
		size_t copied;
		int i, siblock, eiblock, boffset;
		sector_t block;
				
		offset = (segp->offset % BUF_IN_PAGE) * LFS_BSIZE; 
		offset += pos & (LFS_BSIZE - 1); /* within block */
		bytes = PAGE_CACHE_SIZE - offset; /* number of bytes written
						     in this iteration */
		invalidate_old_page(inode, pos);

		if (bytes > count) 
			bytes = count;
		
		//dprintk("1:segp->start=%Lu,segp->offset=%d,segp->end=%Lu,offset=%lu,bytes=%d\n", segp->start, segp->offset, segp->end,offset,bytes);
		
		siblock = pos >> LFS_BSIZE_BITS;
		eiblock = (pos + bytes - 1) >> LFS_BSIZE_BITS;

		//dprintk("writing %d bytes at offset %ld (pos = %Lu)\n", bytes, offset, pos);
		//dprintk("siblock = %d, eiblock = %d\n", siblock, eiblock);
		

		/*
		 * Bring in the user page that we will copy from _first_.
		 * Otherwise there's a nasty deadlock on copying from the
		 * same page as we're writing to, without it being marked
		 * up-to-date.
		 */
		fault_in_pages_readable(buf, bytes);
		page = get_seg_page(segp);
		if (!page) {
			res = -ENOMEM;
			break;
		}

		/* fill the page with current inode blocks if any */
		boffset = offset / LFS_BSIZE;;
		for(i = siblock; i <= eiblock; ++i, ++boffset) {
			struct buffer_head *bh;
			//dprintk("Asking for block %d\n", i);
			bh = lfs_read_block(inode, i);
			if(!bh) /* new block */
				break;
			//dprintk("boffset = %d\n", boffset);
			memcpy(page_address(page) + LFS_BSIZE * boffset, bh->b_data, LFS_BSIZE);
			brelse(bh);
		}

		copied = __copy_from_user(page_address(page) + offset, buf, bytes);
		flush_dcache_page(page);

		block = segp->start + segp->offset;
		for(i = siblock;i <= eiblock; ++i, ++block)
			segsum_update_finfo(segp, inode->i_ino, i, block);

		block = segp->start + segp->offset;
		segp->offset += (bytes  - 1)/LFS_BSIZE + 1;
		//dprintk("2:segp->start=%Lu,segp->offset=%d,segp->end=%Lu,offset=%lu,bytes=%d\n",
		//segp->start, segp->offset, segp->end,offset,bytes);
		BUG_ON(segp->start + segp->offset > segp->end);
		if(segp->start + segp->offset == segp->end) {
			dprintk("allocating new segment\n");
			/* This also is going to write the previous segment */
			segment_allocate_new(inode->i_sb, segp, segp->start + segp->offset);
			segp = LFS_SBI(sb)->s_curr;
		}

		/* update the inode */
		for(i = siblock;i <= eiblock; ++i, ++block)
			update_inode(inode, i, block);
		//dprintk("start=%Lu,offset=%d,end=%Lu\n", segp->start, segp->offset, segp->end);
		segusetbl_add_livebytes(sb, segp->segnum, bytes);
		
		written += bytes;
		buf += bytes;
		pos += bytes;
		count -= bytes;
	} while(count);

	*ppos = pos;
	if(pos > inode->i_size)
		i_size_write(inode, pos);
	if(written)
		mark_inode_dirty(inode);
	
	lfs_unlock(sb);
	//up(&inode->i_sem);
	mutex_unlock(&inode->i_mutex); //BrechREiZ: and unlocking...
	return written ? written : res;
out:
	lfs_unlock(sb);
	//up(&inode->i_sem);
	mutex_unlock(&inode->i_mutex); //BrechREiZ: and unlocking...
	return res; 
}