diff options
Diffstat (limited to 'fs/nilfs2/inode.c')
| -rw-r--r-- | fs/nilfs2/inode.c | 394 | 
1 files changed, 293 insertions, 101 deletions
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 71d4bc8464e..6252b173a46 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -25,7 +25,7 @@  #include <linux/gfp.h>  #include <linux/mpage.h>  #include <linux/writeback.h> -#include <linux/uio.h> +#include <linux/aio.h>  #include "nilfs.h"  #include "btnode.h"  #include "segment.h" @@ -34,6 +34,13 @@  #include "cpfile.h"  #include "ifile.h" +/** + * struct nilfs_iget_args - arguments used during comparison between inodes + * @ino: inode number + * @cno: checkpoint number + * @root: pointer on NILFS root object (mounted checkpoint) + * @for_gc: inode for GC flag + */  struct nilfs_iget_args {  	u64 ino;  	__u64 cno; @@ -41,6 +48,24 @@ struct nilfs_iget_args {  	int for_gc;  }; +void nilfs_inode_add_blocks(struct inode *inode, int n) +{ +	struct nilfs_root *root = NILFS_I(inode)->i_root; + +	inode_add_bytes(inode, (1 << inode->i_blkbits) * n); +	if (root) +		atomic64_add(n, &root->blocks_count); +} + +void nilfs_inode_sub_blocks(struct inode *inode, int n) +{ +	struct nilfs_root *root = NILFS_I(inode)->i_root; + +	inode_sub_bytes(inode, (1 << inode->i_blkbits) * n); +	if (root) +		atomic64_sub(n, &root->blocks_count); +} +  /**   * nilfs_get_block() - get a file block on the filesystem (callback function)   * @inode - inode struct of the target file @@ -56,14 +81,14 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,  		    struct buffer_head *bh_result, int create)  {  	struct nilfs_inode_info *ii = NILFS_I(inode); +	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;  	__u64 blknum = 0;  	int err = 0, ret; -	struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode));  	unsigned maxblocks = bh_result->b_size >> inode->i_blkbits; -	down_read(&NILFS_MDT(dat)->mi_sem); +	down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);  	ret = nilfs_bmap_lookup_contig(ii->i_bmap, blkoff, &blknum, maxblocks); -	up_read(&NILFS_MDT(dat)->mi_sem); +	up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);  	if (ret >= 0) {	/* found */  		map_bh(bh_result, inode->i_sb, blknum);  		if (ret > 0) @@ -96,11 +121,6 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,  				       inode->i_ino,  				       (unsigned long long)blkoff);  				err = 0; -			} else if (err == -EINVAL) { -				nilfs_error(inode->i_sb, __func__, -					    "broken bmap (inode=%lu)\n", -					    inode->i_ino); -				err = -EIO;  			}  			nilfs_transaction_abort(inode->i_sb);  			goto out; @@ -109,6 +129,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,  		nilfs_transaction_commit(inode->i_sb); /* never fails */  		/* Error handling should be detailed */  		set_buffer_new(bh_result); +		set_buffer_delay(bh_result);  		map_bh(bh_result, inode->i_sb, 0); /* dbn must be changed  						      to proper value */  	} else if (ret == -ENOENT) { @@ -154,6 +175,11 @@ static int nilfs_writepages(struct address_space *mapping,  	struct inode *inode = mapping->host;  	int err = 0; +	if (inode->i_sb->s_flags & MS_RDONLY) { +		nilfs_clear_dirty_pages(mapping, false); +		return -EROFS; +	} +  	if (wbc->sync_mode == WB_SYNC_ALL)  		err = nilfs_construct_dsync_segment(inode->i_sb, inode,  						    wbc->range_start, @@ -166,6 +192,18 @@ static int nilfs_writepage(struct page *page, struct writeback_control *wbc)  	struct inode *inode = page->mapping->host;  	int err; +	if (inode->i_sb->s_flags & MS_RDONLY) { +		/* +		 * It means that filesystem was remounted in read-only +		 * mode because of error or metadata corruption. But we +		 * have dirty pages that try to be flushed in background. +		 * So, here we simply discard this dirty page. +		 */ +		nilfs_clear_dirty_page(page, false); +		unlock_page(page); +		return -EROFS; +	} +  	redirty_page_for_writepage(wbc, page);  	unlock_page(page); @@ -181,18 +219,46 @@ static int nilfs_writepage(struct page *page, struct writeback_control *wbc)  static int nilfs_set_page_dirty(struct page *page)  { -	int ret = __set_page_dirty_buffers(page); +	int ret = __set_page_dirty_nobuffers(page); -	if (ret) { +	if (page_has_buffers(page)) {  		struct inode *inode = page->mapping->host; -		struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb); -		unsigned nr_dirty = 1 << (PAGE_SHIFT - inode->i_blkbits); - -		nilfs_set_file_dirty(sbi, inode, nr_dirty); +		unsigned nr_dirty = 0; +		struct buffer_head *bh, *head; + +		/* +		 * This page is locked by callers, and no other thread +		 * concurrently marks its buffers dirty since they are +		 * only dirtied through routines in fs/buffer.c in +		 * which call sites of mark_buffer_dirty are protected +		 * by page lock. +		 */ +		bh = head = page_buffers(page); +		do { +			/* Do not mark hole blocks dirty */ +			if (buffer_dirty(bh) || !buffer_mapped(bh)) +				continue; + +			set_buffer_dirty(bh); +			nr_dirty++; +		} while (bh = bh->b_this_page, bh != head); + +		if (nr_dirty) +			nilfs_set_file_dirty(inode, nr_dirty);  	}  	return ret;  } +void nilfs_write_failed(struct address_space *mapping, loff_t to) +{ +	struct inode *inode = mapping->host; + +	if (to > inode->i_size) { +		truncate_pagecache(inode, inode->i_size); +		nilfs_truncate(inode); +	} +} +  static int nilfs_write_begin(struct file *file, struct address_space *mapping,  			     loff_t pos, unsigned len, unsigned flags,  			     struct page **pagep, void **fsdata) @@ -207,10 +273,7 @@ static int nilfs_write_begin(struct file *file, struct address_space *mapping,  	err = block_write_begin(mapping, pos, len, flags, pagep,  				nilfs_get_block);  	if (unlikely(err)) { -		loff_t isize = mapping->host->i_size; -		if (pos + len > isize) -			vmtruncate(mapping->host, isize); - +		nilfs_write_failed(mapping, pos + len);  		nilfs_transaction_abort(inode->i_sb);  	}  	return err; @@ -229,25 +292,27 @@ static int nilfs_write_end(struct file *file, struct address_space *mapping,  						  start + copied);  	copied = generic_write_end(file, mapping, pos, len, copied, page,  				   fsdata); -	nilfs_set_file_dirty(NILFS_SB(inode->i_sb), inode, nr_dirty); +	nilfs_set_file_dirty(inode, nr_dirty);  	err = nilfs_transaction_commit(inode->i_sb);  	return err ? : copied;  }  static ssize_t -nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, -		loff_t offset, unsigned long nr_segs) +nilfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, +		loff_t offset)  {  	struct file *file = iocb->ki_filp; +	struct address_space *mapping = file->f_mapping;  	struct inode *inode = file->f_mapping->host; +	size_t count = iov_iter_count(iter);  	ssize_t size;  	if (rw == WRITE)  		return 0;  	/* Needs synchronization with the cleaner */ -	size = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, -				  offset, nr_segs, nilfs_get_block, NULL); +	size = blockdev_direct_IO(rw, iocb, inode, iter, offset, +				  nilfs_get_block);  	/*  	 * In case of error extending write may have instantiated a few @@ -255,10 +320,10 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,  	 */  	if (unlikely((rw & WRITE) && size < 0)) {  		loff_t isize = i_size_read(inode); -		loff_t end = offset + iov_length(iov, nr_segs); +		loff_t end = offset + count;  		if (end > isize) -			vmtruncate(inode, isize); +			nilfs_write_failed(mapping, end);  	}  	return size; @@ -267,7 +332,6 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,  const struct address_space_operations nilfs_aops = {  	.writepage		= nilfs_writepage,  	.readpage		= nilfs_readpage, -	.sync_page		= block_sync_page,  	.writepages		= nilfs_writepages,  	.set_page_dirty		= nilfs_set_page_dirty,  	.readpages		= nilfs_readpages, @@ -279,10 +343,10 @@ const struct address_space_operations nilfs_aops = {  	.is_partially_uptodate  = block_is_partially_uptodate,  }; -struct inode *nilfs_new_inode(struct inode *dir, int mode) +struct inode *nilfs_new_inode(struct inode *dir, umode_t mode)  {  	struct super_block *sb = dir->i_sb; -	struct nilfs_sb_info *sbi = NILFS_SB(sb); +	struct the_nilfs *nilfs = sb->s_fs_info;  	struct inode *inode;  	struct nilfs_inode_info *ii;  	struct nilfs_root *root; @@ -306,7 +370,7 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode)  		goto failed_ifile_create_inode;  	/* reference count of i_bh inherits from nilfs_mdt_read_block() */ -	atomic_inc(&root->inodes_count); +	atomic64_inc(&root->inodes_count);  	inode_init_owner(inode, dir, mode);  	inode->i_ino = ino;  	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; @@ -320,19 +384,16 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode)  		/* No lock is needed; iget() ensures it. */  	} -	ii->i_flags = NILFS_I(dir)->i_flags; -	if (S_ISLNK(mode)) -		ii->i_flags &= ~(NILFS_IMMUTABLE_FL | NILFS_APPEND_FL); -	if (!S_ISDIR(mode)) -		ii->i_flags &= ~NILFS_DIRSYNC_FL; +	ii->i_flags = nilfs_mask_flags( +		mode, NILFS_I(dir)->i_flags & NILFS_FL_INHERITED);  	/* ii->i_file_acl = 0; */  	/* ii->i_dir_acl = 0; */  	ii->i_dir_start_lookup = 0;  	nilfs_set_inode_flags(inode); -	spin_lock(&sbi->s_next_gen_lock); -	inode->i_generation = sbi->s_next_generation++; -	spin_unlock(&sbi->s_next_gen_lock); +	spin_lock(&nilfs->ns_next_gen_lock); +	inode->i_generation = nilfs->ns_next_generation++; +	spin_unlock(&nilfs->ns_next_gen_lock);  	insert_inode_hash(inode);  	err = nilfs_init_acl(inode, dir); @@ -345,7 +406,7 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode)   failed_acl:   failed_bmap: -	inode->i_nlink = 0; +	clear_nlink(inode);  	iput(inode);  /* raw_inode will be deleted through  			 generic_delete_inode() */  	goto failed; @@ -364,17 +425,15 @@ void nilfs_set_inode_flags(struct inode *inode)  	inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME |  			    S_DIRSYNC); -	if (flags & NILFS_SYNC_FL) +	if (flags & FS_SYNC_FL)  		inode->i_flags |= S_SYNC; -	if (flags & NILFS_APPEND_FL) +	if (flags & FS_APPEND_FL)  		inode->i_flags |= S_APPEND; -	if (flags & NILFS_IMMUTABLE_FL) +	if (flags & FS_IMMUTABLE_FL)  		inode->i_flags |= S_IMMUTABLE; -#ifndef NILFS_ATIME_DISABLE -	if (flags & NILFS_NOATIME_FL) -#endif +	if (flags & FS_NOATIME_FL)  		inode->i_flags |= S_NOATIME; -	if (flags & NILFS_DIRSYNC_FL) +	if (flags & FS_DIRSYNC_FL)  		inode->i_flags |= S_DIRSYNC;  	mapping_set_gfp_mask(inode->i_mapping,  			     mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); @@ -387,9 +446,9 @@ int nilfs_read_inode_common(struct inode *inode,  	int err;  	inode->i_mode = le16_to_cpu(raw_inode->i_mode); -	inode->i_uid = (uid_t)le32_to_cpu(raw_inode->i_uid); -	inode->i_gid = (gid_t)le32_to_cpu(raw_inode->i_gid); -	inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); +	i_uid_write(inode, le32_to_cpu(raw_inode->i_uid)); +	i_gid_write(inode, le32_to_cpu(raw_inode->i_gid)); +	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));  	inode->i_size = le64_to_cpu(raw_inode->i_size);  	inode->i_atime.tv_sec = le64_to_cpu(raw_inode->i_mtime);  	inode->i_ctime.tv_sec = le64_to_cpu(raw_inode->i_ctime); @@ -425,13 +484,12 @@ static int __nilfs_read_inode(struct super_block *sb,  			      struct nilfs_root *root, unsigned long ino,  			      struct inode *inode)  { -	struct nilfs_sb_info *sbi = NILFS_SB(sb); -	struct inode *dat = nilfs_dat_inode(sbi->s_nilfs); +	struct the_nilfs *nilfs = sb->s_fs_info;  	struct buffer_head *bh;  	struct nilfs_inode *raw_inode;  	int err; -	down_read(&NILFS_MDT(dat)->mi_sem);	/* XXX */ +	down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);  	err = nilfs_ifile_get_inode_block(root->ifile, ino, &bh);  	if (unlikely(err))  		goto bad_inode; @@ -461,7 +519,7 @@ static int __nilfs_read_inode(struct super_block *sb,  	}  	nilfs_ifile_unmap_inode(root->ifile, ino, bh);  	brelse(bh); -	up_read(&NILFS_MDT(dat)->mi_sem);	/* XXX */ +	up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);  	nilfs_set_inode_flags(inode);  	return 0; @@ -470,7 +528,7 @@ static int __nilfs_read_inode(struct super_block *sb,  	brelse(bh);   bad_inode: -	up_read(&NILFS_MDT(dat)->mi_sem);	/* XXX */ +	up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);  	return err;  } @@ -577,8 +635,8 @@ void nilfs_write_inode_common(struct inode *inode,  	struct nilfs_inode_info *ii = NILFS_I(inode);  	raw_inode->i_mode = cpu_to_le16(inode->i_mode); -	raw_inode->i_uid = cpu_to_le32(inode->i_uid); -	raw_inode->i_gid = cpu_to_le32(inode->i_gid); +	raw_inode->i_uid = cpu_to_le32(i_uid_read(inode)); +	raw_inode->i_gid = cpu_to_le32(i_gid_read(inode));  	raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);  	raw_inode->i_size = cpu_to_le64(inode->i_size);  	raw_inode->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec); @@ -590,6 +648,16 @@ void nilfs_write_inode_common(struct inode *inode,  	raw_inode->i_flags = cpu_to_le32(ii->i_flags);  	raw_inode->i_generation = cpu_to_le32(inode->i_generation); +	if (NILFS_ROOT_METADATA_FILE(inode->i_ino)) { +		struct the_nilfs *nilfs = inode->i_sb->s_fs_info; + +		/* zero-fill unused portion in the case of super root block */ +		raw_inode->i_xattr = 0; +		raw_inode->i_pad = 0; +		memset((void *)raw_inode + sizeof(*raw_inode), 0, +		       nilfs->ns_inode_size - sizeof(*raw_inode)); +	} +  	if (has_bmap)  		nilfs_bmap_write(ii->i_bmap, raw_inode);  	else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) @@ -629,7 +697,7 @@ static void nilfs_truncate_bmap(struct nilfs_inode_info *ii,  	if (!test_bit(NILFS_I_BMAP, &ii->i_state))  		return; - repeat: +repeat:  	ret = nilfs_bmap_last_key(ii->i_bmap, &b);  	if (ret == -ENOENT)  		return; @@ -646,14 +714,10 @@ static void nilfs_truncate_bmap(struct nilfs_inode_info *ii,  		     nilfs_bmap_truncate(ii->i_bmap, b) == 0))  		goto repeat; - failed: -	if (ret == -EINVAL) -		nilfs_error(ii->vfs_inode.i_sb, __func__, -			    "bmap is broken (ino=%lu)", ii->vfs_inode.i_ino); -	else -		nilfs_warning(ii->vfs_inode.i_sb, __func__, -			      "failed to truncate bmap (ino=%lu, err=%d)", -			      ii->vfs_inode.i_ino, ret); +failed: +	nilfs_warning(ii->vfs_inode.i_sb, __func__, +		      "failed to truncate bmap (ino=%lu, err=%d)", +		      ii->vfs_inode.i_ino, ret);  }  void nilfs_truncate(struct inode *inode) @@ -682,7 +746,7 @@ void nilfs_truncate(struct inode *inode)  		nilfs_set_transaction_flag(NILFS_TI_SYNC);  	nilfs_mark_inode_dirty(inode); -	nilfs_set_file_dirty(NILFS_SB(sb), inode, 0); +	nilfs_set_file_dirty(inode, 0);  	nilfs_transaction_commit(sb);  	/* May construct a logical segment and may fail in sync mode.  	   But truncate has no return value. */ @@ -717,26 +781,26 @@ void nilfs_evict_inode(struct inode *inode)  	struct nilfs_transaction_info ti;  	struct super_block *sb = inode->i_sb;  	struct nilfs_inode_info *ii = NILFS_I(inode); +	int ret;  	if (inode->i_nlink || !ii->i_root || unlikely(is_bad_inode(inode))) { -		if (inode->i_data.nrpages) -			truncate_inode_pages(&inode->i_data, 0); -		end_writeback(inode); +		truncate_inode_pages_final(&inode->i_data); +		clear_inode(inode);  		nilfs_clear_inode(inode);  		return;  	}  	nilfs_transaction_begin(sb, &ti, 0); /* never fails */ -	if (inode->i_data.nrpages) -		truncate_inode_pages(&inode->i_data, 0); +	truncate_inode_pages_final(&inode->i_data);  	/* TODO: some of the following operations may fail.  */  	nilfs_truncate_bmap(ii, 0);  	nilfs_mark_inode_dirty(inode); -	end_writeback(inode); +	clear_inode(inode); -	nilfs_ifile_delete_inode(ii->i_root->ifile, inode->i_ino); -	atomic_dec(&ii->i_root->inodes_count); +	ret = nilfs_ifile_delete_inode(ii->i_root->ifile, inode->i_ino); +	if (!ret) +		atomic64_dec(&ii->i_root->inodes_count);  	nilfs_clear_inode(inode); @@ -764,9 +828,9 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr)  	if ((iattr->ia_valid & ATTR_SIZE) &&  	    iattr->ia_size != i_size_read(inode)) { -		err = vmtruncate(inode, iattr->ia_size); -		if (unlikely(err)) -			goto out_err; +		inode_dio_wait(inode); +		truncate_setsize(inode, iattr->ia_size); +		nilfs_truncate(inode);  	}  	setattr_copy(inode, iattr); @@ -788,28 +852,27 @@ out_err:  int nilfs_permission(struct inode *inode, int mask)  {  	struct nilfs_root *root = NILFS_I(inode)->i_root; -  	if ((mask & MAY_WRITE) && root &&  	    root->cno != NILFS_CPTREE_CURRENT_CNO)  		return -EROFS; /* snapshot is not writable */ -	return generic_permission(inode, mask, NULL); +	return generic_permission(inode, mask);  } -int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode, -			   struct buffer_head **pbh) +int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh)  { +	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;  	struct nilfs_inode_info *ii = NILFS_I(inode);  	int err; -	spin_lock(&sbi->s_inode_lock); +	spin_lock(&nilfs->ns_inode_lock);  	if (ii->i_bh == NULL) { -		spin_unlock(&sbi->s_inode_lock); +		spin_unlock(&nilfs->ns_inode_lock);  		err = nilfs_ifile_get_inode_block(ii->i_root->ifile,  						  inode->i_ino, pbh);  		if (unlikely(err))  			return err; -		spin_lock(&sbi->s_inode_lock); +		spin_lock(&nilfs->ns_inode_lock);  		if (ii->i_bh == NULL)  			ii->i_bh = *pbh;  		else { @@ -820,36 +883,36 @@ int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode,  		*pbh = ii->i_bh;  	get_bh(*pbh); -	spin_unlock(&sbi->s_inode_lock); +	spin_unlock(&nilfs->ns_inode_lock);  	return 0;  }  int nilfs_inode_dirty(struct inode *inode)  {  	struct nilfs_inode_info *ii = NILFS_I(inode); -	struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb); +	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;  	int ret = 0;  	if (!list_empty(&ii->i_dirty)) { -		spin_lock(&sbi->s_inode_lock); +		spin_lock(&nilfs->ns_inode_lock);  		ret = test_bit(NILFS_I_DIRTY, &ii->i_state) ||  			test_bit(NILFS_I_BUSY, &ii->i_state); -		spin_unlock(&sbi->s_inode_lock); +		spin_unlock(&nilfs->ns_inode_lock);  	}  	return ret;  } -int nilfs_set_file_dirty(struct nilfs_sb_info *sbi, struct inode *inode, -			 unsigned nr_dirty) +int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty)  {  	struct nilfs_inode_info *ii = NILFS_I(inode); +	struct the_nilfs *nilfs = inode->i_sb->s_fs_info; -	atomic_add(nr_dirty, &sbi->s_nilfs->ns_ndirtyblks); +	atomic_add(nr_dirty, &nilfs->ns_ndirtyblks);  	if (test_and_set_bit(NILFS_I_DIRTY, &ii->i_state))  		return 0; -	spin_lock(&sbi->s_inode_lock); +	spin_lock(&nilfs->ns_inode_lock);  	if (!test_bit(NILFS_I_QUEUED, &ii->i_state) &&  	    !test_bit(NILFS_I_BUSY, &ii->i_state)) {  		/* Because this routine may race with nilfs_dispose_list(), @@ -857,35 +920,33 @@ int nilfs_set_file_dirty(struct nilfs_sb_info *sbi, struct inode *inode,  		if (list_empty(&ii->i_dirty) && igrab(inode) == NULL) {  			/* This will happen when somebody is freeing  			   this inode. */ -			nilfs_warning(sbi->s_super, __func__, +			nilfs_warning(inode->i_sb, __func__,  				      "cannot get inode (ino=%lu)\n",  				      inode->i_ino); -			spin_unlock(&sbi->s_inode_lock); +			spin_unlock(&nilfs->ns_inode_lock);  			return -EINVAL; /* NILFS_I_DIRTY may remain for  					   freeing inode */  		} -		list_del(&ii->i_dirty); -		list_add_tail(&ii->i_dirty, &sbi->s_dirty_files); +		list_move_tail(&ii->i_dirty, &nilfs->ns_dirty_files);  		set_bit(NILFS_I_QUEUED, &ii->i_state);  	} -	spin_unlock(&sbi->s_inode_lock); +	spin_unlock(&nilfs->ns_inode_lock);  	return 0;  }  int nilfs_mark_inode_dirty(struct inode *inode)  { -	struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb);  	struct buffer_head *ibh;  	int err; -	err = nilfs_load_inode_block(sbi, inode, &ibh); +	err = nilfs_load_inode_block(inode, &ibh);  	if (unlikely(err)) {  		nilfs_warning(inode->i_sb, __func__,  			      "failed to reget inode block.\n");  		return err;  	}  	nilfs_update_inode(inode, ibh); -	nilfs_mdt_mark_buffer_dirty(ibh); +	mark_buffer_dirty(ibh);  	nilfs_mdt_mark_dirty(NILFS_I(inode)->i_root->ifile);  	brelse(ibh);  	return 0; @@ -901,7 +962,7 @@ int nilfs_mark_inode_dirty(struct inode *inode)   * construction. This function can be called both as a single operation   * and as a part of indivisible file operations.   */ -void nilfs_dirty_inode(struct inode *inode) +void nilfs_dirty_inode(struct inode *inode, int flags)  {  	struct nilfs_transaction_info ti;  	struct nilfs_mdt_info *mdi = NILFS_MDT(inode); @@ -920,3 +981,134 @@ void nilfs_dirty_inode(struct inode *inode)  	nilfs_mark_inode_dirty(inode);  	nilfs_transaction_commit(inode->i_sb); /* never fails */  } + +int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, +		 __u64 start, __u64 len) +{ +	struct the_nilfs *nilfs = inode->i_sb->s_fs_info; +	__u64 logical = 0, phys = 0, size = 0; +	__u32 flags = 0; +	loff_t isize; +	sector_t blkoff, end_blkoff; +	sector_t delalloc_blkoff; +	unsigned long delalloc_blklen; +	unsigned int blkbits = inode->i_blkbits; +	int ret, n; + +	ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); +	if (ret) +		return ret; + +	mutex_lock(&inode->i_mutex); + +	isize = i_size_read(inode); + +	blkoff = start >> blkbits; +	end_blkoff = (start + len - 1) >> blkbits; + +	delalloc_blklen = nilfs_find_uncommitted_extent(inode, blkoff, +							&delalloc_blkoff); + +	do { +		__u64 blkphy; +		unsigned int maxblocks; + +		if (delalloc_blklen && blkoff == delalloc_blkoff) { +			if (size) { +				/* End of the current extent */ +				ret = fiemap_fill_next_extent( +					fieinfo, logical, phys, size, flags); +				if (ret) +					break; +			} +			if (blkoff > end_blkoff) +				break; + +			flags = FIEMAP_EXTENT_MERGED | FIEMAP_EXTENT_DELALLOC; +			logical = blkoff << blkbits; +			phys = 0; +			size = delalloc_blklen << blkbits; + +			blkoff = delalloc_blkoff + delalloc_blklen; +			delalloc_blklen = nilfs_find_uncommitted_extent( +				inode, blkoff, &delalloc_blkoff); +			continue; +		} + +		/* +		 * Limit the number of blocks that we look up so as +		 * not to get into the next delayed allocation extent. +		 */ +		maxblocks = INT_MAX; +		if (delalloc_blklen) +			maxblocks = min_t(sector_t, delalloc_blkoff - blkoff, +					  maxblocks); +		blkphy = 0; + +		down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); +		n = nilfs_bmap_lookup_contig( +			NILFS_I(inode)->i_bmap, blkoff, &blkphy, maxblocks); +		up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); + +		if (n < 0) { +			int past_eof; + +			if (unlikely(n != -ENOENT)) +				break; /* error */ + +			/* HOLE */ +			blkoff++; +			past_eof = ((blkoff << blkbits) >= isize); + +			if (size) { +				/* End of the current extent */ + +				if (past_eof) +					flags |= FIEMAP_EXTENT_LAST; + +				ret = fiemap_fill_next_extent( +					fieinfo, logical, phys, size, flags); +				if (ret) +					break; +				size = 0; +			} +			if (blkoff > end_blkoff || past_eof) +				break; +		} else { +			if (size) { +				if (phys && blkphy << blkbits == phys + size) { +					/* The current extent goes on */ +					size += n << blkbits; +				} else { +					/* Terminate the current extent */ +					ret = fiemap_fill_next_extent( +						fieinfo, logical, phys, size, +						flags); +					if (ret || blkoff > end_blkoff) +						break; + +					/* Start another extent */ +					flags = FIEMAP_EXTENT_MERGED; +					logical = blkoff << blkbits; +					phys = blkphy << blkbits; +					size = n << blkbits; +				} +			} else { +				/* Start a new extent */ +				flags = FIEMAP_EXTENT_MERGED; +				logical = blkoff << blkbits; +				phys = blkphy << blkbits; +				size = n << blkbits; +			} +			blkoff += n; +		} +		cond_resched(); +	} while (true); + +	/* If ret is 1 then we just hit the end of the extent array */ +	if (ret == 1) +		ret = 0; + +	mutex_unlock(&inode->i_mutex); +	return ret; +}  | 
