diff options
Diffstat (limited to 'fs/logfs/readwrite.c')
| -rw-r--r-- | fs/logfs/readwrite.c | 121 | 
1 files changed, 73 insertions, 48 deletions
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index 6127baf0e18..48140315f62 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c @@ -119,14 +119,14 @@ static void logfs_disk_to_inode(struct logfs_disk_inode *di, struct inode*inode)  	inode->i_mode	= be16_to_cpu(di->di_mode);  	li->li_height	= di->di_height;  	li->li_flags	= be32_to_cpu(di->di_flags); -	inode->i_uid	= be32_to_cpu(di->di_uid); -	inode->i_gid	= be32_to_cpu(di->di_gid); +	i_uid_write(inode, be32_to_cpu(di->di_uid)); +	i_gid_write(inode, be32_to_cpu(di->di_gid));  	inode->i_size	= be64_to_cpu(di->di_size);  	logfs_set_blocks(inode, be64_to_cpu(di->di_used_bytes));  	inode->i_atime	= be64_to_timespec(di->di_atime);  	inode->i_ctime	= be64_to_timespec(di->di_ctime);  	inode->i_mtime	= be64_to_timespec(di->di_mtime); -	inode->i_nlink	= be32_to_cpu(di->di_refcount); +	set_nlink(inode, be32_to_cpu(di->di_refcount));  	inode->i_generation = be32_to_cpu(di->di_generation);  	switch (inode->i_mode & S_IFMT) { @@ -156,8 +156,8 @@ static void logfs_inode_to_disk(struct inode *inode, struct logfs_disk_inode*di)  	di->di_height	= li->li_height;  	di->di_pad	= 0;  	di->di_flags	= cpu_to_be32(li->li_flags); -	di->di_uid	= cpu_to_be32(inode->i_uid); -	di->di_gid	= cpu_to_be32(inode->i_gid); +	di->di_uid	= cpu_to_be32(i_uid_read(inode)); +	di->di_gid	= cpu_to_be32(i_gid_read(inode));  	di->di_size	= cpu_to_be64(i_size_read(inode));  	di->di_used_bytes = cpu_to_be64(li->li_used_bytes);  	di->di_atime	= timespec_to_be64(inode->i_atime); @@ -244,8 +244,7 @@ static void preunlock_page(struct super_block *sb, struct page *page, int lock)   * is waiting for s_write_mutex.  We annotate this fact by setting PG_pre_locked   * in addition to PG_locked.   */ -static void logfs_get_wblocks(struct super_block *sb, struct page *page, -		int lock) +void logfs_get_wblocks(struct super_block *sb, struct page *page, int lock)  {  	struct logfs_super *super = logfs_super(sb); @@ -260,8 +259,7 @@ static void logfs_get_wblocks(struct super_block *sb, struct page *page,  	}  } -static void logfs_put_wblocks(struct super_block *sb, struct page *page, -		int lock) +void logfs_put_wblocks(struct super_block *sb, struct page *page, int lock)  {  	struct logfs_super *super = logfs_super(sb); @@ -424,7 +422,7 @@ static void inode_write_block(struct logfs_block *block)  	if (inode->i_ino == LOGFS_INO_MASTER)  		logfs_write_anchor(inode->i_sb);  	else { -		ret = __logfs_write_inode(inode, 0); +		ret = __logfs_write_inode(inode, NULL, 0);  		/* see indirect_write_block comment */  		BUG_ON(ret);  	} @@ -481,7 +479,7 @@ static int inode_write_alias(struct super_block *sb,  			val = inode_val0(inode);  			break;  		case INODE_USED_OFS: -			val = cpu_to_be64(li->li_used_bytes);; +			val = cpu_to_be64(li->li_used_bytes);  			break;  		case INODE_SIZE_OFS:  			val = cpu_to_be64(i_size_read(inode)); @@ -519,9 +517,9 @@ static int indirect_write_alias(struct super_block *sb,  		ino = page->mapping->host->i_ino;  		logfs_unpack_index(page->index, &bix, &level); -		child = kmap_atomic(page, KM_USER0); +		child = kmap_atomic(page);  		val = child[pos]; -		kunmap_atomic(child, KM_USER0); +		kunmap_atomic(child);  		err = write_one_alias(sb, ino, bix, level, pos, val);  		if (err)  			return err; @@ -560,8 +558,13 @@ static void inode_free_block(struct super_block *sb, struct logfs_block *block)  static void indirect_free_block(struct super_block *sb,  		struct logfs_block *block)  { -	ClearPagePrivate(block->page); -	block->page->private = 0; +	struct page *page = block->page; + +	if (PagePrivate(page)) { +		ClearPagePrivate(page); +		page_cache_release(page); +		set_page_private(page, 0); +	}  	__free_block(sb, block);  } @@ -650,8 +653,11 @@ static void alloc_data_block(struct inode *inode, struct page *page)  	logfs_unpack_index(page->index, &bix, &level);  	block = __alloc_block(inode->i_sb, inode->i_ino, bix, level);  	block->page = page; +  	SetPagePrivate(page); -	page->private = (unsigned long)block; +	page_cache_get(page); +	set_page_private(page, (unsigned long) block); +  	block->ops = &indirect_block_ops;  } @@ -667,9 +673,9 @@ static void alloc_indirect_block(struct inode *inode, struct page *page,  	alloc_data_block(inode, page);  	block = logfs_block(page); -	array = kmap_atomic(page, KM_USER0); +	array = kmap_atomic(page);  	initialize_block_counters(page, block, array, page_is_empty); -	kunmap_atomic(array, KM_USER0); +	kunmap_atomic(array);  }  static void block_set_pointer(struct page *page, int index, u64 ptr) @@ -679,10 +685,10 @@ static void block_set_pointer(struct page *page, int index, u64 ptr)  	u64 oldptr;  	BUG_ON(!block); -	array = kmap_atomic(page, KM_USER0); +	array = kmap_atomic(page);  	oldptr = be64_to_cpu(array[index]);  	array[index] = cpu_to_be64(ptr); -	kunmap_atomic(array, KM_USER0); +	kunmap_atomic(array);  	SetPageUptodate(page);  	block->full += !!(ptr & LOGFS_FULLY_POPULATED) @@ -695,9 +701,9 @@ static u64 block_get_pointer(struct page *page, int index)  	__be64 *block;  	u64 ptr; -	block = kmap_atomic(page, KM_USER0); +	block = kmap_atomic(page);  	ptr = be64_to_cpu(block[index]); -	kunmap_atomic(block, KM_USER0); +	kunmap_atomic(block);  	return ptr;  } @@ -844,7 +850,7 @@ static u64 seek_holedata_loop(struct inode *inode, u64 bix, int data)  		}  		slot = get_bits(bix, SUBLEVEL(level)); -		rblock = kmap_atomic(page, KM_USER0); +		rblock = kmap_atomic(page);  		while (slot < LOGFS_BLOCK_FACTOR) {  			if (data && (rblock[slot] != 0))  				break; @@ -855,12 +861,12 @@ static u64 seek_holedata_loop(struct inode *inode, u64 bix, int data)  			bix &= ~(increment - 1);  		}  		if (slot >= LOGFS_BLOCK_FACTOR) { -			kunmap_atomic(rblock, KM_USER0); +			kunmap_atomic(rblock);  			logfs_put_read_page(page);  			return bix;  		}  		bofs = be64_to_cpu(rblock[slot]); -		kunmap_atomic(rblock, KM_USER0); +		kunmap_atomic(rblock);  		logfs_put_read_page(page);  		if (!bofs) {  			BUG_ON(data); @@ -1570,11 +1576,15 @@ int logfs_write_buf(struct inode *inode, struct page *page, long flags)  static int __logfs_delete(struct inode *inode, struct page *page)  {  	long flags = WF_DELETE; +	int err;  	inode->i_ctime = inode->i_mtime = CURRENT_TIME;  	if (page->index < I0_BLOCKS)  		return logfs_write_direct(inode, page, flags); +	err = grow_inode(inode, page->index, 0); +	if (err) +		return err;  	return logfs_write_rec(inode, page, page->index, 0, flags);  } @@ -1616,14 +1626,14 @@ int logfs_rewrite_block(struct inode *inode, u64 bix, u64 ofs,  		err = logfs_write_buf(inode, page, flags);  		if (!err && shrink_level(gc_level) == 0) {  			/* Rewrite cannot mark the inode dirty but has to -			 * write it immediatly. +			 * write it immediately.  			 * Q: Can't we just create an alias for the inode  			 * instead?  And if not, why not?  			 */  			if (inode->i_ino == LOGFS_INO_MASTER)  				logfs_write_anchor(inode->i_sb);  			else { -				err = __logfs_write_inode(inode, flags); +				err = __logfs_write_inode(inode, page, flags);  			}  		}  	} @@ -1873,13 +1883,19 @@ int logfs_truncate(struct inode *inode, u64 target)  		logfs_get_wblocks(sb, NULL, 1);  		err = __logfs_truncate(inode, size);  		if (!err) -			err = __logfs_write_inode(inode, 0); +			err = __logfs_write_inode(inode, NULL, 0);  		logfs_put_wblocks(sb, NULL, 1);  	} -	if (!err) -		err = vmtruncate(inode, target); +	if (!err) { +		err = inode_newsize_ok(inode, target); +		if (err) +			goto out; +		truncate_setsize(inode, target); +	} + + out:  	/* I don't trust error recovery yet. */  	WARN_ON(err);  	return err; @@ -1901,8 +1917,11 @@ static void move_page_to_inode(struct inode *inode, struct page *page)  	li->li_block = block;  	block->page = NULL; -	page->private = 0; -	ClearPagePrivate(page); +	if (PagePrivate(page)) { +		ClearPagePrivate(page); +		page_cache_release(page); +		set_page_private(page, 0); +	}  }  static void move_inode_to_page(struct page *page, struct inode *inode) @@ -1918,8 +1937,12 @@ static void move_inode_to_page(struct page *page, struct inode *inode)  	BUG_ON(PagePrivate(page));  	block->ops = &indirect_block_ops;  	block->page = page; -	page->private = (unsigned long)block; -	SetPagePrivate(page); + +	if (!PagePrivate(page)) { +		SetPagePrivate(page); +		page_cache_get(page); +		set_page_private(page, (unsigned long) block); +	}  	block->inode = NULL;  	li->li_block = NULL; @@ -1944,9 +1967,9 @@ int logfs_read_inode(struct inode *inode)  	if (IS_ERR(page))  		return PTR_ERR(page); -	di = kmap_atomic(page, KM_USER0); +	di = kmap_atomic(page);  	logfs_disk_to_inode(di, inode); -	kunmap_atomic(di, KM_USER0); +	kunmap_atomic(di);  	move_page_to_inode(inode, page);  	page_cache_release(page);  	return 0; @@ -1965,9 +1988,9 @@ static struct page *inode_to_page(struct inode *inode)  	if (!page)  		return NULL; -	di = kmap_atomic(page, KM_USER0); +	di = kmap_atomic(page);  	logfs_inode_to_disk(inode, di); -	kunmap_atomic(di, KM_USER0); +	kunmap_atomic(di);  	move_inode_to_page(page, inode);  	return page;  } @@ -1994,6 +2017,9 @@ static int do_write_inode(struct inode *inode)  	/* FIXME: transaction is part of logfs_block now.  Is that enough? */  	err = logfs_write_buf(master_inode, page, 0); +	if (err) +		move_page_to_inode(inode, page); +  	logfs_put_write_page(page);  	return err;  } @@ -2021,13 +2047,13 @@ static void logfs_mod_segment_entry(struct super_block *sb, u32 segno,  	if (write)  		alloc_indirect_block(inode, page, 0); -	se = kmap_atomic(page, KM_USER0); +	se = kmap_atomic(page);  	change_se(se + child_no, arg);  	if (write) {  		logfs_set_alias(sb, logfs_block(page), child_no);  		BUG_ON((int)be32_to_cpu(se[child_no].valid) > super->s_segsize);  	} -	kunmap_atomic(se, KM_USER0); +	kunmap_atomic(se);  	logfs_put_write_page(page);  } @@ -2103,14 +2129,14 @@ void logfs_set_segment_unreserved(struct super_block *sb, u32 segno, u32 ec)  			ec_level);  } -int __logfs_write_inode(struct inode *inode, long flags) +int __logfs_write_inode(struct inode *inode, struct page *page, long flags)  {  	struct super_block *sb = inode->i_sb;  	int ret; -	logfs_get_wblocks(sb, NULL, flags & WF_LOCK); +	logfs_get_wblocks(sb, page, flags & WF_LOCK);  	ret = do_write_inode(inode); -	logfs_put_wblocks(sb, NULL, flags & WF_LOCK); +	logfs_put_wblocks(sb, page, flags & WF_LOCK);  	return ret;  } @@ -2154,8 +2180,8 @@ void logfs_evict_inode(struct inode *inode)  			do_delete_inode(inode);  		}  	} -	truncate_inode_pages(&inode->i_data, 0); -	end_writeback(inode); +	truncate_inode_pages_final(&inode->i_data); +	clear_inode(inode);  	/* Cheaper version of write_inode.  All changes are concealed in  	 * aliases, which are moved back.  No write to the medium happens. @@ -2169,7 +2195,6 @@ void logfs_evict_inode(struct inode *inode)  		return;  	} -	BUG_ON(inode->i_ino < LOGFS_RESERVED_INOS);  	page = inode_to_page(inode);  	BUG_ON(!page); /* FIXME: Use emergency page */  	logfs_put_write_page(page); @@ -2225,10 +2250,10 @@ int logfs_inode_write(struct inode *inode, const void *buf, size_t count,  	if (!page)  		return -ENOMEM; -	pagebuf = kmap_atomic(page, KM_USER0); +	pagebuf = kmap_atomic(page);  	memcpy(pagebuf, buf, count);  	flush_dcache_page(page); -	kunmap_atomic(pagebuf, KM_USER0); +	kunmap_atomic(pagebuf);  	if (i_size_read(inode) < pos + LOGFS_BLOCKSIZE)  		i_size_write(inode, pos + LOGFS_BLOCKSIZE);  | 
