Commit ef3b9af5 authored by Filipe Manana's avatar Filipe Manana Committed by Chris Mason

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: default avatarFilipe David Borba Manana <fdmanana@gmail.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.cz>
parent e4ef90ff
...@@ -5553,6 +5553,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -5553,6 +5553,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
struct btrfs_inode_ref *ref; struct btrfs_inode_ref *ref;
struct btrfs_key key[2]; struct btrfs_key key[2];
u32 sizes[2]; u32 sizes[2];
int nitems = name ? 2 : 1;
unsigned long ptr; unsigned long ptr;
int ret; int ret;
...@@ -5572,7 +5573,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -5572,7 +5573,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
*/ */
inode->i_ino = objectid; inode->i_ino = objectid;
if (dir) { if (dir && name) {
trace_btrfs_inode_request(dir); trace_btrfs_inode_request(dir);
ret = btrfs_set_inode_index(dir, index); ret = btrfs_set_inode_index(dir, index);
...@@ -5581,6 +5582,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -5581,6 +5582,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
iput(inode); iput(inode);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
} else if (dir) {
*index = 0;
} }
/* /*
* index_cnt is ignored for everything but a dir, * index_cnt is ignored for everything but a dir,
...@@ -5605,21 +5608,24 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -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); btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
key[0].offset = 0; 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[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; 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) if (ret != 0)
goto fail; goto fail;
...@@ -5632,12 +5638,14 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -5632,12 +5638,14 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
sizeof(*inode_item)); sizeof(*inode_item));
fill_inode_item(trans, path->nodes[0], inode_item, inode); fill_inode_item(trans, path->nodes[0], inode_item, inode);
ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1, if (name) {
struct btrfs_inode_ref); ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1,
btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); struct btrfs_inode_ref);
btrfs_set_inode_ref_index(path->nodes[0], ref, *index); btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
ptr = (unsigned long)(ref + 1); btrfs_set_inode_ref_index(path->nodes[0], ref, *index);
write_extent_buffer(path->nodes[0], name, ptr, name_len); ptr = (unsigned long)(ref + 1);
write_extent_buffer(path->nodes[0], name, ptr, name_len);
}
btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_mark_buffer_dirty(path->nodes[0]);
btrfs_free_path(path); btrfs_free_path(path);
...@@ -5673,7 +5681,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, ...@@ -5673,7 +5681,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
return inode; return inode;
fail: fail:
if (dir) if (dir && name)
BTRFS_I(dir)->index_cnt--; BTRFS_I(dir)->index_cnt--;
btrfs_free_path(path); btrfs_free_path(path);
iput(inode); iput(inode);
...@@ -5958,6 +5966,15 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -5958,6 +5966,15 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
err = btrfs_update_inode(trans, root, inode); err = btrfs_update_inode(trans, root, inode);
if (err) if (err)
goto fail; 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); d_instantiate(dentry, inode);
btrfs_log_new_name(trans, inode, NULL, parent); btrfs_log_new_name(trans, inode, NULL, parent);
} }
...@@ -8884,6 +8901,66 @@ static int btrfs_permission(struct inode *inode, int mask) ...@@ -8884,6 +8901,66 @@ static int btrfs_permission(struct inode *inode, int mask)
return generic_permission(inode, 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 = { static const struct inode_operations btrfs_dir_inode_operations = {
.getattr = btrfs_getattr, .getattr = btrfs_getattr,
.lookup = btrfs_lookup, .lookup = btrfs_lookup,
...@@ -8904,6 +8981,7 @@ static const struct inode_operations btrfs_dir_inode_operations = { ...@@ -8904,6 +8981,7 @@ static const struct inode_operations btrfs_dir_inode_operations = {
.get_acl = btrfs_get_acl, .get_acl = btrfs_get_acl,
.set_acl = btrfs_set_acl, .set_acl = btrfs_set_acl,
.update_time = btrfs_update_time, .update_time = btrfs_update_time,
.tmpfile = btrfs_tmpfile,
}; };
static const struct inode_operations btrfs_dir_ro_inode_operations = { static const struct inode_operations btrfs_dir_ro_inode_operations = {
.lookup = btrfs_lookup, .lookup = btrfs_lookup,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment