Btrfs: implement inode_operations callback tmpfile
This implements the tmpfile callback of struct inode_operations, introduced in the linux kernel 3.11, and implemented already by some filesystems. This callback is invoked by the VFS when the flag O_TMPFILE is passed to the open system call. Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com> Signed-off-by: Chris Mason <clm@fb.com> Reviewed-by: David Sterba <dsterba@suse.cz>
This commit is contained in:
		
					parent
					
						
							
								e4ef90ff61
							
						
					
				
			
			
				commit
				
					
						ef3b9af50b
					
				
			
		
					 1 changed files with 98 additions and 20 deletions
				
			
		
							
								
								
									
										118
									
								
								fs/btrfs/inode.c
									
										
									
									
									
								
							
							
						
						
									
										118
									
								
								fs/btrfs/inode.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -5553,6 +5553,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
	struct btrfs_inode_ref *ref;
 | 
			
		||||
	struct btrfs_key key[2];
 | 
			
		||||
	u32 sizes[2];
 | 
			
		||||
	int nitems = name ? 2 : 1;
 | 
			
		||||
	unsigned long ptr;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5572,7 +5573,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
	 */
 | 
			
		||||
	inode->i_ino = objectid;
 | 
			
		||||
 | 
			
		||||
	if (dir) {
 | 
			
		||||
	if (dir && name) {
 | 
			
		||||
		trace_btrfs_inode_request(dir);
 | 
			
		||||
 | 
			
		||||
		ret = btrfs_set_inode_index(dir, index);
 | 
			
		||||
| 
						 | 
				
			
			@ -5581,6 +5582,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
			iput(inode);
 | 
			
		||||
			return ERR_PTR(ret);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (dir) {
 | 
			
		||||
		*index = 0;
 | 
			
		||||
	}
 | 
			
		||||
	/*
 | 
			
		||||
	 * index_cnt is ignored for everything but a dir,
 | 
			
		||||
| 
						 | 
				
			
			@ -5605,21 +5608,24 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
	btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
 | 
			
		||||
	key[0].offset = 0;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Start new inodes with an inode_ref. This is slightly more
 | 
			
		||||
	 * efficient for small numbers of hard links since they will
 | 
			
		||||
	 * be packed into one item. Extended refs will kick in if we
 | 
			
		||||
	 * add more hard links than can fit in the ref item.
 | 
			
		||||
	 */
 | 
			
		||||
	key[1].objectid = objectid;
 | 
			
		||||
	btrfs_set_key_type(&key[1], BTRFS_INODE_REF_KEY);
 | 
			
		||||
	key[1].offset = ref_objectid;
 | 
			
		||||
 | 
			
		||||
	sizes[0] = sizeof(struct btrfs_inode_item);
 | 
			
		||||
	sizes[1] = name_len + sizeof(*ref);
 | 
			
		||||
 | 
			
		||||
	if (name) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Start new inodes with an inode_ref. This is slightly more
 | 
			
		||||
		 * efficient for small numbers of hard links since they will
 | 
			
		||||
		 * be packed into one item. Extended refs will kick in if we
 | 
			
		||||
		 * add more hard links than can fit in the ref item.
 | 
			
		||||
		 */
 | 
			
		||||
		key[1].objectid = objectid;
 | 
			
		||||
		btrfs_set_key_type(&key[1], BTRFS_INODE_REF_KEY);
 | 
			
		||||
		key[1].offset = ref_objectid;
 | 
			
		||||
 | 
			
		||||
		sizes[1] = name_len + sizeof(*ref);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	path->leave_spinning = 1;
 | 
			
		||||
	ret = btrfs_insert_empty_items(trans, root, path, key, sizes, 2);
 | 
			
		||||
	ret = btrfs_insert_empty_items(trans, root, path, key, sizes, nitems);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5632,12 +5638,14 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
			     sizeof(*inode_item));
 | 
			
		||||
	fill_inode_item(trans, path->nodes[0], inode_item, inode);
 | 
			
		||||
 | 
			
		||||
	ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1,
 | 
			
		||||
			     struct btrfs_inode_ref);
 | 
			
		||||
	btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
 | 
			
		||||
	btrfs_set_inode_ref_index(path->nodes[0], ref, *index);
 | 
			
		||||
	ptr = (unsigned long)(ref + 1);
 | 
			
		||||
	write_extent_buffer(path->nodes[0], name, ptr, name_len);
 | 
			
		||||
	if (name) {
 | 
			
		||||
		ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1,
 | 
			
		||||
				     struct btrfs_inode_ref);
 | 
			
		||||
		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
 | 
			
		||||
		btrfs_set_inode_ref_index(path->nodes[0], ref, *index);
 | 
			
		||||
		ptr = (unsigned long)(ref + 1);
 | 
			
		||||
		write_extent_buffer(path->nodes[0], name, ptr, name_len);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	btrfs_mark_buffer_dirty(path->nodes[0]);
 | 
			
		||||
	btrfs_free_path(path);
 | 
			
		||||
| 
						 | 
				
			
			@ -5673,7 +5681,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 | 
			
		|||
 | 
			
		||||
	return inode;
 | 
			
		||||
fail:
 | 
			
		||||
	if (dir)
 | 
			
		||||
	if (dir && name)
 | 
			
		||||
		BTRFS_I(dir)->index_cnt--;
 | 
			
		||||
	btrfs_free_path(path);
 | 
			
		||||
	iput(inode);
 | 
			
		||||
| 
						 | 
				
			
			@ -5958,6 +5966,15 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 | 
			
		|||
		err = btrfs_update_inode(trans, root, inode);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto fail;
 | 
			
		||||
		if (inode->i_nlink == 1) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * If new hard link count is 1, it's a file created
 | 
			
		||||
			 * with open(2) O_TMPFILE flag.
 | 
			
		||||
			 */
 | 
			
		||||
			err = btrfs_orphan_del(trans, inode);
 | 
			
		||||
			if (err)
 | 
			
		||||
				goto fail;
 | 
			
		||||
		}
 | 
			
		||||
		d_instantiate(dentry, inode);
 | 
			
		||||
		btrfs_log_new_name(trans, inode, NULL, parent);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -8884,6 +8901,66 @@ static int btrfs_permission(struct inode *inode, int mask)
 | 
			
		|||
	return generic_permission(inode, mask);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
 | 
			
		||||
{
 | 
			
		||||
	struct btrfs_trans_handle *trans;
 | 
			
		||||
	struct btrfs_root *root = BTRFS_I(dir)->root;
 | 
			
		||||
	struct inode *inode = NULL;
 | 
			
		||||
	u64 objectid;
 | 
			
		||||
	u64 index;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * 5 units required for adding orphan entry
 | 
			
		||||
	 */
 | 
			
		||||
	trans = btrfs_start_transaction(root, 5);
 | 
			
		||||
	if (IS_ERR(trans))
 | 
			
		||||
		return PTR_ERR(trans);
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_find_free_ino(root, &objectid);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	inode = btrfs_new_inode(trans, root, dir, NULL, 0,
 | 
			
		||||
				btrfs_ino(dir), objectid, mode, &index);
 | 
			
		||||
	if (IS_ERR(inode)) {
 | 
			
		||||
		ret = PTR_ERR(inode);
 | 
			
		||||
		inode = NULL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_init_inode_security(trans, inode, dir, NULL);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_update_inode(trans, root, inode);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	inode->i_fop = &btrfs_file_operations;
 | 
			
		||||
	inode->i_op = &btrfs_file_inode_operations;
 | 
			
		||||
 | 
			
		||||
	inode->i_mapping->a_ops = &btrfs_aops;
 | 
			
		||||
	inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
 | 
			
		||||
	BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
 | 
			
		||||
 | 
			
		||||
	ret = btrfs_orphan_add(trans, inode);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	d_tmpfile(dentry, inode);
 | 
			
		||||
	mark_inode_dirty(inode);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	btrfs_end_transaction(trans, root);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		iput(inode);
 | 
			
		||||
	btrfs_balance_delayed_items(root);
 | 
			
		||||
	btrfs_btree_balance_dirty(root);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct inode_operations btrfs_dir_inode_operations = {
 | 
			
		||||
	.getattr	= btrfs_getattr,
 | 
			
		||||
	.lookup		= btrfs_lookup,
 | 
			
		||||
| 
						 | 
				
			
			@ -8904,6 +8981,7 @@ static const struct inode_operations btrfs_dir_inode_operations = {
 | 
			
		|||
	.get_acl	= btrfs_get_acl,
 | 
			
		||||
	.set_acl	= btrfs_set_acl,
 | 
			
		||||
	.update_time	= btrfs_update_time,
 | 
			
		||||
	.tmpfile        = btrfs_tmpfile,
 | 
			
		||||
};
 | 
			
		||||
static const struct inode_operations btrfs_dir_ro_inode_operations = {
 | 
			
		||||
	.lookup		= btrfs_lookup,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue