diff options
author | Filipe Manana <fdmanana@gmail.com> | 2014-04-27 15:40:45 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-06-09 20:20:30 -0400 |
commit | ef3b9af50bfa6a1f02cd7b3f5124b712b1ba3e3c (patch) | |
tree | 8aeb9ff9803aa2060676c1817ca11f0015d1da1c /fs/btrfs/inode.c | |
parent | e4ef90ff6198ac58d4c7dbbeae8cc7b24867d1ca (diff) |
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>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 118 |
1 files changed, 98 insertions, 20 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 24dfa27a4f76..5c0def8dd761 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -5553,6 +5553,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
5553 | struct btrfs_inode_ref *ref; | 5553 | struct btrfs_inode_ref *ref; |
5554 | struct btrfs_key key[2]; | 5554 | struct btrfs_key key[2]; |
5555 | u32 sizes[2]; | 5555 | u32 sizes[2]; |
5556 | int nitems = name ? 2 : 1; | ||
5556 | unsigned long ptr; | 5557 | unsigned long ptr; |
5557 | int ret; | 5558 | int ret; |
5558 | 5559 | ||
@@ -5572,7 +5573,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
5572 | */ | 5573 | */ |
5573 | inode->i_ino = objectid; | 5574 | inode->i_ino = objectid; |
5574 | 5575 | ||
5575 | if (dir) { | 5576 | if (dir && name) { |
5576 | trace_btrfs_inode_request(dir); | 5577 | trace_btrfs_inode_request(dir); |
5577 | 5578 | ||
5578 | ret = btrfs_set_inode_index(dir, index); | 5579 | ret = btrfs_set_inode_index(dir, index); |
@@ -5581,6 +5582,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
5581 | iput(inode); | 5582 | iput(inode); |
5582 | return ERR_PTR(ret); | 5583 | return ERR_PTR(ret); |
5583 | } | 5584 | } |
5585 | } else if (dir) { | ||
5586 | *index = 0; | ||
5584 | } | 5587 | } |
5585 | /* | 5588 | /* |
5586 | * index_cnt is ignored for everything but a dir, | 5589 | * 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 | btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY); | 5608 | btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY); |
5606 | key[0].offset = 0; | 5609 | key[0].offset = 0; |
5607 | 5610 | ||
5608 | /* | ||
5609 | * Start new inodes with an inode_ref. This is slightly more | ||
5610 | * efficient for small numbers of hard links since they will | ||
5611 | * be packed into one item. Extended refs will kick in if we | ||
5612 | * add more hard links than can fit in the ref item. | ||
5613 | */ | ||
5614 | key[1].objectid = objectid; | ||
5615 | btrfs_set_key_type(&key[1], BTRFS_INODE_REF_KEY); | ||
5616 | key[1].offset = ref_objectid; | ||
5617 | |||
5618 | sizes[0] = sizeof(struct btrfs_inode_item); | 5611 | sizes[0] = sizeof(struct btrfs_inode_item); |
5619 | sizes[1] = name_len + sizeof(*ref); | 5612 | |
5613 | if (name) { | ||
5614 | /* | ||
5615 | * Start new inodes with an inode_ref. This is slightly more | ||
5616 | * efficient for small numbers of hard links since they will | ||
5617 | * be packed into one item. Extended refs will kick in if we | ||
5618 | * add more hard links than can fit in the ref item. | ||
5619 | */ | ||
5620 | key[1].objectid = objectid; | ||
5621 | btrfs_set_key_type(&key[1], BTRFS_INODE_REF_KEY); | ||
5622 | key[1].offset = ref_objectid; | ||
5623 | |||
5624 | sizes[1] = name_len + sizeof(*ref); | ||
5625 | } | ||
5620 | 5626 | ||
5621 | path->leave_spinning = 1; | 5627 | path->leave_spinning = 1; |
5622 | ret = btrfs_insert_empty_items(trans, root, path, key, sizes, 2); | 5628 | ret = btrfs_insert_empty_items(trans, root, path, key, sizes, nitems); |
5623 | if (ret != 0) | 5629 | if (ret != 0) |
5624 | goto fail; | 5630 | goto fail; |
5625 | 5631 | ||
@@ -5632,12 +5638,14 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
5632 | sizeof(*inode_item)); | 5638 | sizeof(*inode_item)); |
5633 | fill_inode_item(trans, path->nodes[0], inode_item, inode); | 5639 | fill_inode_item(trans, path->nodes[0], inode_item, inode); |
5634 | 5640 | ||
5635 | ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1, | 5641 | if (name) { |
5636 | struct btrfs_inode_ref); | 5642 | ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1, |
5637 | btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); | 5643 | struct btrfs_inode_ref); |
5638 | btrfs_set_inode_ref_index(path->nodes[0], ref, *index); | 5644 | btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); |
5639 | ptr = (unsigned long)(ref + 1); | 5645 | btrfs_set_inode_ref_index(path->nodes[0], ref, *index); |
5640 | write_extent_buffer(path->nodes[0], name, ptr, name_len); | 5646 | ptr = (unsigned long)(ref + 1); |
5647 | write_extent_buffer(path->nodes[0], name, ptr, name_len); | ||
5648 | } | ||
5641 | 5649 | ||
5642 | btrfs_mark_buffer_dirty(path->nodes[0]); | 5650 | btrfs_mark_buffer_dirty(path->nodes[0]); |
5643 | btrfs_free_path(path); | 5651 | btrfs_free_path(path); |
@@ -5673,7 +5681,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
5673 | 5681 | ||
5674 | return inode; | 5682 | return inode; |
5675 | fail: | 5683 | fail: |
5676 | if (dir) | 5684 | if (dir && name) |
5677 | BTRFS_I(dir)->index_cnt--; | 5685 | BTRFS_I(dir)->index_cnt--; |
5678 | btrfs_free_path(path); | 5686 | btrfs_free_path(path); |
5679 | iput(inode); | 5687 | iput(inode); |
@@ -5958,6 +5966,15 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, | |||
5958 | err = btrfs_update_inode(trans, root, inode); | 5966 | err = btrfs_update_inode(trans, root, inode); |
5959 | if (err) | 5967 | if (err) |
5960 | goto fail; | 5968 | goto fail; |
5969 | if (inode->i_nlink == 1) { | ||
5970 | /* | ||
5971 | * If new hard link count is 1, it's a file created | ||
5972 | * with open(2) O_TMPFILE flag. | ||
5973 | */ | ||
5974 | err = btrfs_orphan_del(trans, inode); | ||
5975 | if (err) | ||
5976 | goto fail; | ||
5977 | } | ||
5961 | d_instantiate(dentry, inode); | 5978 | d_instantiate(dentry, inode); |
5962 | btrfs_log_new_name(trans, inode, NULL, parent); | 5979 | btrfs_log_new_name(trans, inode, NULL, parent); |
5963 | } | 5980 | } |
@@ -8884,6 +8901,66 @@ static int btrfs_permission(struct inode *inode, int mask) | |||
8884 | return generic_permission(inode, mask); | 8901 | return generic_permission(inode, mask); |
8885 | } | 8902 | } |
8886 | 8903 | ||
8904 | static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) | ||
8905 | { | ||
8906 | struct btrfs_trans_handle *trans; | ||
8907 | struct btrfs_root *root = BTRFS_I(dir)->root; | ||
8908 | struct inode *inode = NULL; | ||
8909 | u64 objectid; | ||
8910 | u64 index; | ||
8911 | int ret = 0; | ||
8912 | |||
8913 | /* | ||
8914 | * 5 units required for adding orphan entry | ||
8915 | */ | ||
8916 | trans = btrfs_start_transaction(root, 5); | ||
8917 | if (IS_ERR(trans)) | ||
8918 | return PTR_ERR(trans); | ||
8919 | |||
8920 | ret = btrfs_find_free_ino(root, &objectid); | ||
8921 | if (ret) | ||
8922 | goto out; | ||
8923 | |||
8924 | inode = btrfs_new_inode(trans, root, dir, NULL, 0, | ||
8925 | btrfs_ino(dir), objectid, mode, &index); | ||
8926 | if (IS_ERR(inode)) { | ||
8927 | ret = PTR_ERR(inode); | ||
8928 | inode = NULL; | ||
8929 | goto out; | ||
8930 | } | ||
8931 | |||
8932 | ret = btrfs_init_inode_security(trans, inode, dir, NULL); | ||
8933 | if (ret) | ||
8934 | goto out; | ||
8935 | |||
8936 | ret = btrfs_update_inode(trans, root, inode); | ||
8937 | if (ret) | ||
8938 | goto out; | ||
8939 | |||
8940 | inode->i_fop = &btrfs_file_operations; | ||
8941 | inode->i_op = &btrfs_file_inode_operations; | ||
8942 | |||
8943 | inode->i_mapping->a_ops = &btrfs_aops; | ||
8944 | inode->i_mapping->backing_dev_info = &root->fs_info->bdi; | ||
8945 | BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; | ||
8946 | |||
8947 | ret = btrfs_orphan_add(trans, inode); | ||
8948 | if (ret) | ||
8949 | goto out; | ||
8950 | |||
8951 | d_tmpfile(dentry, inode); | ||
8952 | mark_inode_dirty(inode); | ||
8953 | |||
8954 | out: | ||
8955 | btrfs_end_transaction(trans, root); | ||
8956 | if (ret) | ||
8957 | iput(inode); | ||
8958 | btrfs_balance_delayed_items(root); | ||
8959 | btrfs_btree_balance_dirty(root); | ||
8960 | |||
8961 | return ret; | ||
8962 | } | ||
8963 | |||
8887 | static const struct inode_operations btrfs_dir_inode_operations = { | 8964 | static const struct inode_operations btrfs_dir_inode_operations = { |
8888 | .getattr = btrfs_getattr, | 8965 | .getattr = btrfs_getattr, |
8889 | .lookup = btrfs_lookup, | 8966 | .lookup = btrfs_lookup, |
@@ -8904,6 +8981,7 @@ static const struct inode_operations btrfs_dir_inode_operations = { | |||
8904 | .get_acl = btrfs_get_acl, | 8981 | .get_acl = btrfs_get_acl, |
8905 | .set_acl = btrfs_set_acl, | 8982 | .set_acl = btrfs_set_acl, |
8906 | .update_time = btrfs_update_time, | 8983 | .update_time = btrfs_update_time, |
8984 | .tmpfile = btrfs_tmpfile, | ||
8907 | }; | 8985 | }; |
8908 | static const struct inode_operations btrfs_dir_ro_inode_operations = { | 8986 | static const struct inode_operations btrfs_dir_ro_inode_operations = { |
8909 | .lookup = btrfs_lookup, | 8987 | .lookup = btrfs_lookup, |