| From: Filipe Manana <fdmanana@suse.com> |
| Date: Fri, 1 Aug 2014 00:10:32 +0100 |
| Subject: Btrfs: ensure tmpfile inode is always persisted with link count of 0 |
| |
| commit 5762b5c958abbecb7fb9f4596a6476d1ce91ecf6 upstream. |
| |
| If we open a file with O_TMPFILE, don't do any further operation on |
| it (so that the inode item isn't updated) and then force a transaction |
| commit, we get a persisted inode item with a link count of 1, and not 0 |
| as it should be. |
| |
| Steps to reproduce it (requires a modern xfs_io with -T support): |
| |
| $ mkfs.btrfs -f /dev/sdd |
| $ mount -o /dev/sdd /mnt |
| $ xfs_io -T /mnt & |
| $ sync |
| |
| Then btrfs-debug-tree shows the inode item with a link count of 1: |
| |
| $ btrfs-debug-tree /dev/sdd |
| (...) |
| fs tree key (FS_TREE ROOT_ITEM 0) |
| leaf 29556736 items 4 free space 15851 generation 6 owner 5 |
| fs uuid f164d01b-1b92-481d-a4e4-435fb0f843d0 |
| chunk uuid 0e3d0e56-bcca-4a1c-aa5f-cec2c6f4f7a6 |
| item 0 key (256 INODE_ITEM 0) itemoff 16123 itemsize 160 |
| inode generation 3 transid 6 size 0 block group 0 mode 40755 links 1 |
| item 1 key (256 INODE_REF 256) itemoff 16111 itemsize 12 |
| inode ref index 0 namelen 2 name: .. |
| item 2 key (257 INODE_ITEM 0) itemoff 15951 itemsize 160 |
| inode generation 6 transid 6 size 0 block group 0 mode 100600 links 1 |
| item 3 key (ORPHAN ORPHAN_ITEM 257) itemoff 15951 itemsize 0 |
| orphan item |
| checksum tree key (CSUM_TREE ROOT_ITEM 0) |
| (...) |
| |
| Signed-off-by: Filipe Manana <fdmanana@suse.com> |
| Signed-off-by: Chris Mason <clm@fb.com> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| fs/btrfs/inode.c | 15 +++++++++++++++ |
| 1 file changed, 15 insertions(+) |
| |
| --- a/fs/btrfs/inode.c |
| +++ b/fs/btrfs/inode.c |
| @@ -5731,6 +5731,13 @@ static struct inode *btrfs_new_inode(str |
| } |
| |
| /* |
| + * O_TMPFILE, set link count to 0, so that after this point, |
| + * we fill in an inode item with the correct link count. |
| + */ |
| + if (!name) |
| + set_nlink(inode, 0); |
| + |
| + /* |
| * we have to initialize this early, so we can reclaim the inode |
| * number if we fail afterwards in this function. |
| */ |
| @@ -9096,6 +9103,14 @@ static int btrfs_tmpfile(struct inode *d |
| if (ret) |
| goto out; |
| |
| + /* |
| + * We set number of links to 0 in btrfs_new_inode(), and here we set |
| + * it to 1 because d_tmpfile() will issue a warning if the count is 0, |
| + * through: |
| + * |
| + * d_tmpfile() -> inode_dec_link_count() -> drop_nlink() |
| + */ |
| + set_nlink(inode, 1); |
| d_tmpfile(dentry, inode); |
| mark_inode_dirty(inode); |
| |