diff options
Diffstat (limited to 'fs/btrfs/inode.c')
| -rw-r--r-- | fs/btrfs/inode.c | 52 | 
1 files changed, 17 insertions, 35 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 115bc05e42b..61b16c641ce 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1947,7 +1947,7 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,   * extent_io.c will try to find good copies for us.   */  static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end, -			       struct extent_state *state) +			       struct extent_state *state, int mirror)  {  	size_t offset = start - ((u64)page->index << PAGE_CACHE_SHIFT);  	struct inode *inode = page->mapping->host; @@ -4069,7 +4069,7 @@ static struct inode *new_simple_dir(struct super_block *s,  	BTRFS_I(inode)->dummy_inode = 1;  	inode->i_ino = BTRFS_EMPTY_SUBVOL_DIR_OBJECTID; -	inode->i_op = &simple_dir_inode_operations; +	inode->i_op = &btrfs_dir_ro_inode_operations;  	inode->i_fop = &simple_dir_operations;  	inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO;  	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; @@ -4140,14 +4140,18 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)  static int btrfs_dentry_delete(const struct dentry *dentry)  {  	struct btrfs_root *root; +	struct inode *inode = dentry->d_inode; -	if (!dentry->d_inode && !IS_ROOT(dentry)) -		dentry = dentry->d_parent; +	if (!inode && !IS_ROOT(dentry)) +		inode = dentry->d_parent->d_inode; -	if (dentry->d_inode) { -		root = BTRFS_I(dentry->d_inode)->root; +	if (inode) { +		root = BTRFS_I(inode)->root;  		if (btrfs_root_refs(&root->root_item) == 0)  			return 1; + +		if (btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID) +			return 1;  	}  	return 0;  } @@ -4188,7 +4192,6 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,  	struct btrfs_path *path;  	struct list_head ins_list;  	struct list_head del_list; -	struct qstr q;  	int ret;  	struct extent_buffer *leaf;  	int slot; @@ -4279,7 +4282,6 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,  		while (di_cur < di_total) {  			struct btrfs_key location; -			struct dentry *tmp;  			if (verify_dir_item(root, leaf, di))  				break; @@ -4300,35 +4302,15 @@ static int btrfs_real_readdir(struct file *filp, void *dirent,  			d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)];  			btrfs_dir_item_key_to_cpu(leaf, di, &location); -			q.name = name_ptr; -			q.len = name_len; -			q.hash = full_name_hash(q.name, q.len); -			tmp = d_lookup(filp->f_dentry, &q); -			if (!tmp) { -				struct btrfs_key *newkey; -				newkey = kzalloc(sizeof(struct btrfs_key), -						 GFP_NOFS); -				if (!newkey) -					goto no_dentry; -				tmp = d_alloc(filp->f_dentry, &q); -				if (!tmp) { -					kfree(newkey); -					dput(tmp); -					goto no_dentry; -				} -				memcpy(newkey, &location, -				       sizeof(struct btrfs_key)); -				tmp->d_fsdata = newkey; -				tmp->d_flags |= DCACHE_NEED_LOOKUP; -				d_rehash(tmp); -				dput(tmp); -			} else { -				dput(tmp); -			} -no_dentry:  			/* is this a reference to our own snapshot? If so -			 * skip it +			 * skip it. +			 * +			 * In contrast to old kernels, we insert the snapshot's +			 * dir item and dir index after it has been created, so +			 * we won't find a reference to our own snapshot. We +			 * still keep the following code for backward +			 * compatibility.  			 */  			if (location.type == BTRFS_ROOT_ITEM_KEY &&  			    location.objectid == root->root_key.objectid) {  |