diff options
author | Josef Bacik <jbacik@redhat.com> | 2008-07-24 12:17:14 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:05 -0400 |
commit | 7b1287662304c3cb05cb38f5e3e2d69f386e8f10 (patch) | |
tree | bb589bfc3854f801b4098f2f2140e42a2f9e8071 /fs/btrfs | |
parent | 33268eaf0b3db5e2bd12c0ada81a8e8f87a46d68 (diff) |
Btrfs: Create orphan inode records to prevent lost files after a crash
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/Makefile | 2 | ||||
-rw-r--r-- | fs/btrfs/btrfs_inode.h | 3 | ||||
-rw-r--r-- | fs/btrfs/ctree.c | 2 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 14 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 2 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 237 | ||||
-rw-r--r-- | fs/btrfs/orphan.c | 67 |
7 files changed, 322 insertions, 5 deletions
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index f8a38b0da7fb..5a0fd7b0e3e7 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile | |||
@@ -6,7 +6,7 @@ btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ | |||
6 | hash.o file-item.o inode-item.o inode-map.o disk-io.o \ | 6 | hash.o file-item.o inode-item.o inode-map.o disk-io.o \ |
7 | transaction.o bit-radix.o inode.o file.o tree-defrag.o \ | 7 | transaction.o bit-radix.o inode.o file.o tree-defrag.o \ |
8 | extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ | 8 | extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ |
9 | extent_io.o volumes.o async-thread.o ioctl.o locking.o | 9 | extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o |
10 | 10 | ||
11 | btrfs-$(CONFIG_FS_POSIX_ACL) += acl.o | 11 | btrfs-$(CONFIG_FS_POSIX_ACL) += acl.o |
12 | else | 12 | else |
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 9f2a4ef944a7..df624fd735c1 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h | |||
@@ -39,6 +39,9 @@ struct btrfs_inode { | |||
39 | struct posix_acl *i_acl; | 39 | struct posix_acl *i_acl; |
40 | struct posix_acl *i_default_acl; | 40 | struct posix_acl *i_default_acl; |
41 | 41 | ||
42 | /* for keeping track of orphaned inodes */ | ||
43 | struct list_head i_orphan; | ||
44 | |||
42 | /* | 45 | /* |
43 | * transid of the trans_handle that last modified this inode | 46 | * transid of the trans_handle that last modified this inode |
44 | */ | 47 | */ |
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index cdc713062b03..f2a94999c371 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -2622,7 +2622,7 @@ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, | |||
2622 | total_data += data_size[i]; | 2622 | total_data += data_size[i]; |
2623 | } | 2623 | } |
2624 | 2624 | ||
2625 | total_size = total_data + (nr - 1) * sizeof(struct btrfs_item); | 2625 | total_size = total_data + (nr * sizeof(struct btrfs_item)); |
2626 | ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1); | 2626 | ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1); |
2627 | if (ret == 0) { | 2627 | if (ret == 0) { |
2628 | return -EEXIST; | 2628 | return -EEXIST; |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index f87d7263f2d7..012ad529cb18 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -74,6 +74,9 @@ struct btrfs_ordered_sum; | |||
74 | /* directory objectid inside the root tree */ | 74 | /* directory objectid inside the root tree */ |
75 | #define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL | 75 | #define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL |
76 | 76 | ||
77 | /* orhpan objectid for tracking unlinked/truncated files */ | ||
78 | #define BTRFS_ORPHAN_OBJECTID -5ULL | ||
79 | |||
77 | /* | 80 | /* |
78 | * All files have objectids higher than this. | 81 | * All files have objectids higher than this. |
79 | */ | 82 | */ |
@@ -646,6 +649,9 @@ struct btrfs_root { | |||
646 | 649 | ||
647 | /* the dirty list is only used by non-reference counted roots */ | 650 | /* the dirty list is only used by non-reference counted roots */ |
648 | struct list_head dirty_list; | 651 | struct list_head dirty_list; |
652 | |||
653 | spinlock_t orphan_lock; | ||
654 | struct list_head orphan_list; | ||
649 | }; | 655 | }; |
650 | 656 | ||
651 | /* | 657 | /* |
@@ -657,6 +663,7 @@ struct btrfs_root { | |||
657 | #define BTRFS_INODE_ITEM_KEY 1 | 663 | #define BTRFS_INODE_ITEM_KEY 1 |
658 | #define BTRFS_INODE_REF_KEY 2 | 664 | #define BTRFS_INODE_REF_KEY 2 |
659 | #define BTRFS_XATTR_ITEM_KEY 8 | 665 | #define BTRFS_XATTR_ITEM_KEY 8 |
666 | #define BTRFS_ORPHAN_ITEM_KEY 9 | ||
660 | /* reserve 2-15 close to the inode for later flexibility */ | 667 | /* reserve 2-15 close to the inode for later flexibility */ |
661 | 668 | ||
662 | /* | 669 | /* |
@@ -1560,6 +1567,13 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, | |||
1560 | struct btrfs_path *path, u64 dir, | 1567 | struct btrfs_path *path, u64 dir, |
1561 | const char *name, u16 name_len, | 1568 | const char *name, u16 name_len, |
1562 | int mod); | 1569 | int mod); |
1570 | |||
1571 | /* orphan.c */ | ||
1572 | int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, | ||
1573 | struct btrfs_root *root, u64 offset); | ||
1574 | int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, | ||
1575 | struct btrfs_root *root, u64 offset); | ||
1576 | |||
1563 | /* inode-map.c */ | 1577 | /* inode-map.c */ |
1564 | int btrfs_find_free_objectid(struct btrfs_trans_handle *trans, | 1578 | int btrfs_find_free_objectid(struct btrfs_trans_handle *trans, |
1565 | struct btrfs_root *fs_root, | 1579 | struct btrfs_root *fs_root, |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index ec01062eb41d..d60923967347 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -732,7 +732,9 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | |||
732 | root->in_sysfs = 0; | 732 | root->in_sysfs = 0; |
733 | 733 | ||
734 | INIT_LIST_HEAD(&root->dirty_list); | 734 | INIT_LIST_HEAD(&root->dirty_list); |
735 | INIT_LIST_HEAD(&root->orphan_list); | ||
735 | spin_lock_init(&root->node_lock); | 736 | spin_lock_init(&root->node_lock); |
737 | spin_lock_init(&root->orphan_lock); | ||
736 | mutex_init(&root->objectid_mutex); | 738 | mutex_init(&root->objectid_mutex); |
737 | memset(&root->root_key, 0, sizeof(root->root_key)); | 739 | memset(&root->root_key, 0, sizeof(root->root_key)); |
738 | memset(&root->root_item, 0, sizeof(root->root_item)); | 740 | memset(&root->root_item, 0, sizeof(root->root_item)); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2d8853543a71..0c9ec8aa304a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -78,6 +78,8 @@ static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = { | |||
78 | [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK, | 78 | [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | static void btrfs_truncate(struct inode *inode); | ||
82 | |||
81 | int btrfs_check_free_space(struct btrfs_root *root, u64 num_required, | 83 | int btrfs_check_free_space(struct btrfs_root *root, u64 num_required, |
82 | int for_del) | 84 | int for_del) |
83 | { | 85 | { |
@@ -826,6 +828,190 @@ zeroit: | |||
826 | return -EIO; | 828 | return -EIO; |
827 | } | 829 | } |
828 | 830 | ||
831 | /* | ||
832 | * This creates an orphan entry for the given inode in case something goes | ||
833 | * wrong in the middle of an unlink/truncate. | ||
834 | */ | ||
835 | int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode) | ||
836 | { | ||
837 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
838 | int ret = 0; | ||
839 | |||
840 | spin_lock(&root->orphan_lock); | ||
841 | |||
842 | /* already on the orphan list, we're good */ | ||
843 | if (!list_empty(&BTRFS_I(inode)->i_orphan)) { | ||
844 | spin_unlock(&root->orphan_lock); | ||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | list_add(&BTRFS_I(inode)->i_orphan, &root->orphan_list); | ||
849 | |||
850 | spin_unlock(&root->orphan_lock); | ||
851 | |||
852 | /* | ||
853 | * insert an orphan item to track this unlinked/truncated file | ||
854 | */ | ||
855 | ret = btrfs_insert_orphan_item(trans, root, inode->i_ino); | ||
856 | |||
857 | return ret; | ||
858 | } | ||
859 | |||
860 | /* | ||
861 | * We have done the truncate/delete so we can go ahead and remove the orphan | ||
862 | * item for this particular inode. | ||
863 | */ | ||
864 | int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode) | ||
865 | { | ||
866 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
867 | int ret = 0; | ||
868 | |||
869 | spin_lock(&root->orphan_lock); | ||
870 | |||
871 | if (list_empty(&BTRFS_I(inode)->i_orphan)) { | ||
872 | spin_unlock(&root->orphan_lock); | ||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | list_del_init(&BTRFS_I(inode)->i_orphan); | ||
877 | if (!trans) { | ||
878 | spin_unlock(&root->orphan_lock); | ||
879 | return 0; | ||
880 | } | ||
881 | |||
882 | spin_unlock(&root->orphan_lock); | ||
883 | |||
884 | ret = btrfs_del_orphan_item(trans, root, inode->i_ino); | ||
885 | |||
886 | return ret; | ||
887 | } | ||
888 | |||
889 | /* | ||
890 | * this cleans up any orphans that may be left on the list from the last use | ||
891 | * of this root. | ||
892 | */ | ||
893 | void btrfs_orphan_cleanup(struct btrfs_root *root) | ||
894 | { | ||
895 | struct btrfs_path *path; | ||
896 | struct extent_buffer *leaf; | ||
897 | struct btrfs_item *item; | ||
898 | struct btrfs_key key, found_key; | ||
899 | struct btrfs_trans_handle *trans; | ||
900 | struct inode *inode; | ||
901 | int ret = 0, nr_unlink = 0, nr_truncate = 0; | ||
902 | |||
903 | /* don't do orphan cleanup if the fs is readonly. */ | ||
904 | if (root->inode->i_sb->s_flags & MS_RDONLY) | ||
905 | return; | ||
906 | |||
907 | path = btrfs_alloc_path(); | ||
908 | if (!path) | ||
909 | return; | ||
910 | path->reada = -1; | ||
911 | |||
912 | key.objectid = BTRFS_ORPHAN_OBJECTID; | ||
913 | btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY); | ||
914 | key.offset = (u64)-1; | ||
915 | |||
916 | trans = btrfs_start_transaction(root, 1); | ||
917 | btrfs_set_trans_block_group(trans, root->inode); | ||
918 | |||
919 | while (1) { | ||
920 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
921 | if (ret < 0) { | ||
922 | printk(KERN_ERR "Error searching slot for orphan: %d" | ||
923 | "\n", ret); | ||
924 | break; | ||
925 | } | ||
926 | |||
927 | /* | ||
928 | * if ret == 0 means we found what we were searching for, which | ||
929 | * is weird, but possible, so only screw with path if we didnt | ||
930 | * find the key and see if we have stuff that matches | ||
931 | */ | ||
932 | if (ret > 0) { | ||
933 | if (path->slots[0] == 0) | ||
934 | break; | ||
935 | path->slots[0]--; | ||
936 | } | ||
937 | |||
938 | /* pull out the item */ | ||
939 | leaf = path->nodes[0]; | ||
940 | item = btrfs_item_nr(leaf, path->slots[0]); | ||
941 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | ||
942 | |||
943 | /* make sure the item matches what we want */ | ||
944 | if (found_key.objectid != BTRFS_ORPHAN_OBJECTID) | ||
945 | break; | ||
946 | if (btrfs_key_type(&found_key) != BTRFS_ORPHAN_ITEM_KEY) | ||
947 | break; | ||
948 | |||
949 | /* release the path since we're done with it */ | ||
950 | btrfs_release_path(root, path); | ||
951 | |||
952 | /* | ||
953 | * this is where we are basically btrfs_lookup, without the | ||
954 | * crossing root thing. we store the inode number in the | ||
955 | * offset of the orphan item. | ||
956 | */ | ||
957 | inode = btrfs_iget_locked(root->inode->i_sb, | ||
958 | found_key.offset, root); | ||
959 | if (!inode) | ||
960 | break; | ||
961 | |||
962 | if (inode->i_state & I_NEW) { | ||
963 | BTRFS_I(inode)->root = root; | ||
964 | |||
965 | /* have to set the location manually */ | ||
966 | BTRFS_I(inode)->location.objectid = inode->i_ino; | ||
967 | BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY; | ||
968 | BTRFS_I(inode)->location.offset = 0; | ||
969 | |||
970 | btrfs_read_locked_inode(inode); | ||
971 | unlock_new_inode(inode); | ||
972 | } | ||
973 | |||
974 | /* | ||
975 | * add this inode to the orphan list so btrfs_orphan_del does | ||
976 | * the proper thing when we hit it | ||
977 | */ | ||
978 | spin_lock(&root->orphan_lock); | ||
979 | list_add(&BTRFS_I(inode)->i_orphan, &root->orphan_list); | ||
980 | spin_unlock(&root->orphan_lock); | ||
981 | |||
982 | /* | ||
983 | * if this is a bad inode, means we actually succeeded in | ||
984 | * removing the inode, but not the orphan record, which means | ||
985 | * we need to manually delete the orphan since iput will just | ||
986 | * do a destroy_inode | ||
987 | */ | ||
988 | if (is_bad_inode(inode)) { | ||
989 | btrfs_orphan_del(trans, inode); | ||
990 | iput(inode); | ||
991 | continue; | ||
992 | } | ||
993 | |||
994 | /* if we have links, this was a truncate, lets do that */ | ||
995 | if (inode->i_nlink) { | ||
996 | nr_truncate++; | ||
997 | btrfs_truncate(inode); | ||
998 | } else { | ||
999 | nr_unlink++; | ||
1000 | } | ||
1001 | |||
1002 | /* this will do delete_inode and everything for us */ | ||
1003 | iput(inode); | ||
1004 | } | ||
1005 | |||
1006 | if (nr_unlink) | ||
1007 | printk(KERN_INFO "btrfs: unlinked %d orphans\n", nr_unlink); | ||
1008 | if (nr_truncate) | ||
1009 | printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate); | ||
1010 | |||
1011 | btrfs_free_path(path); | ||
1012 | btrfs_end_transaction(trans, root); | ||
1013 | } | ||
1014 | |||
829 | void btrfs_read_locked_inode(struct inode *inode) | 1015 | void btrfs_read_locked_inode(struct inode *inode) |
830 | { | 1016 | { |
831 | struct btrfs_path *path; | 1017 | struct btrfs_path *path; |
@@ -1067,6 +1253,7 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1067 | { | 1253 | { |
1068 | struct btrfs_root *root; | 1254 | struct btrfs_root *root; |
1069 | struct btrfs_trans_handle *trans; | 1255 | struct btrfs_trans_handle *trans; |
1256 | struct inode *inode = dentry->d_inode; | ||
1070 | int ret; | 1257 | int ret; |
1071 | unsigned long nr = 0; | 1258 | unsigned long nr = 0; |
1072 | 1259 | ||
@@ -1080,6 +1267,10 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1080 | 1267 | ||
1081 | btrfs_set_trans_block_group(trans, dir); | 1268 | btrfs_set_trans_block_group(trans, dir); |
1082 | ret = btrfs_unlink_trans(trans, root, dir, dentry); | 1269 | ret = btrfs_unlink_trans(trans, root, dir, dentry); |
1270 | |||
1271 | if (inode->i_nlink == 0) | ||
1272 | ret = btrfs_orphan_add(trans, inode); | ||
1273 | |||
1083 | nr = trans->blocks_used; | 1274 | nr = trans->blocks_used; |
1084 | 1275 | ||
1085 | btrfs_end_transaction_throttle(trans, root); | 1276 | btrfs_end_transaction_throttle(trans, root); |
@@ -1108,12 +1299,17 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1108 | trans = btrfs_start_transaction(root, 1); | 1299 | trans = btrfs_start_transaction(root, 1); |
1109 | btrfs_set_trans_block_group(trans, dir); | 1300 | btrfs_set_trans_block_group(trans, dir); |
1110 | 1301 | ||
1302 | err = btrfs_orphan_add(trans, inode); | ||
1303 | if (err) | ||
1304 | goto fail_trans; | ||
1305 | |||
1111 | /* now the directory is empty */ | 1306 | /* now the directory is empty */ |
1112 | err = btrfs_unlink_trans(trans, root, dir, dentry); | 1307 | err = btrfs_unlink_trans(trans, root, dir, dentry); |
1113 | if (!err) { | 1308 | if (!err) { |
1114 | btrfs_i_size_write(inode, 0); | 1309 | btrfs_i_size_write(inode, 0); |
1115 | } | 1310 | } |
1116 | 1311 | ||
1312 | fail_trans: | ||
1117 | nr = trans->blocks_used; | 1313 | nr = trans->blocks_used; |
1118 | ret = btrfs_end_transaction_throttle(trans, root); | 1314 | ret = btrfs_end_transaction_throttle(trans, root); |
1119 | fail: | 1315 | fail: |
@@ -1131,6 +1327,9 @@ fail: | |||
1131 | * | 1327 | * |
1132 | * csum items that cross the new i_size are truncated to the new size | 1328 | * csum items that cross the new i_size are truncated to the new size |
1133 | * as well. | 1329 | * as well. |
1330 | * | ||
1331 | * min_type is the minimum key type to truncate down to. If set to 0, this | ||
1332 | * will kill all the items on this inode, including the INODE_ITEM_KEY. | ||
1134 | */ | 1333 | */ |
1135 | static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | 1334 | static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, |
1136 | struct btrfs_root *root, | 1335 | struct btrfs_root *root, |
@@ -1495,6 +1694,7 @@ void btrfs_delete_inode(struct inode *inode) | |||
1495 | 1694 | ||
1496 | truncate_inode_pages(&inode->i_data, 0); | 1695 | truncate_inode_pages(&inode->i_data, 0); |
1497 | if (is_bad_inode(inode)) { | 1696 | if (is_bad_inode(inode)) { |
1697 | btrfs_orphan_del(NULL, inode); | ||
1498 | goto no_delete; | 1698 | goto no_delete; |
1499 | } | 1699 | } |
1500 | btrfs_wait_ordered_range(inode, 0, (u64)-1); | 1700 | btrfs_wait_ordered_range(inode, 0, (u64)-1); |
@@ -1504,8 +1704,12 @@ void btrfs_delete_inode(struct inode *inode) | |||
1504 | 1704 | ||
1505 | btrfs_set_trans_block_group(trans, inode); | 1705 | btrfs_set_trans_block_group(trans, inode); |
1506 | ret = btrfs_truncate_in_trans(trans, root, inode, 0); | 1706 | ret = btrfs_truncate_in_trans(trans, root, inode, 0); |
1507 | if (ret) | 1707 | if (ret) { |
1708 | btrfs_orphan_del(NULL, inode); | ||
1508 | goto no_delete_lock; | 1709 | goto no_delete_lock; |
1710 | } | ||
1711 | |||
1712 | btrfs_orphan_del(trans, inode); | ||
1509 | 1713 | ||
1510 | nr = trans->blocks_used; | 1714 | nr = trans->blocks_used; |
1511 | clear_inode(inode); | 1715 | clear_inode(inode); |
@@ -1688,7 +1892,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
1688 | struct btrfs_root *root = bi->root; | 1892 | struct btrfs_root *root = bi->root; |
1689 | struct btrfs_root *sub_root = root; | 1893 | struct btrfs_root *sub_root = root; |
1690 | struct btrfs_key location; | 1894 | struct btrfs_key location; |
1691 | int ret; | 1895 | int ret, do_orphan = 0; |
1692 | 1896 | ||
1693 | if (dentry->d_name.len > BTRFS_NAME_LEN) | 1897 | if (dentry->d_name.len > BTRFS_NAME_LEN) |
1694 | return ERR_PTR(-ENAMETOOLONG); | 1898 | return ERR_PTR(-ENAMETOOLONG); |
@@ -1706,6 +1910,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
1706 | return ERR_PTR(ret); | 1910 | return ERR_PTR(ret); |
1707 | if (ret > 0) | 1911 | if (ret > 0) |
1708 | return ERR_PTR(-ENOENT); | 1912 | return ERR_PTR(-ENOENT); |
1913 | |||
1709 | inode = btrfs_iget_locked(dir->i_sb, location.objectid, | 1914 | inode = btrfs_iget_locked(dir->i_sb, location.objectid, |
1710 | sub_root); | 1915 | sub_root); |
1711 | if (!inode) | 1916 | if (!inode) |
@@ -1715,6 +1920,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
1715 | if (sub_root != root) { | 1920 | if (sub_root != root) { |
1716 | igrab(inode); | 1921 | igrab(inode); |
1717 | sub_root->inode = inode; | 1922 | sub_root->inode = inode; |
1923 | do_orphan = 1; | ||
1718 | } | 1924 | } |
1719 | BTRFS_I(inode)->root = sub_root; | 1925 | BTRFS_I(inode)->root = sub_root; |
1720 | memcpy(&BTRFS_I(inode)->location, &location, | 1926 | memcpy(&BTRFS_I(inode)->location, &location, |
@@ -1723,6 +1929,10 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
1723 | unlock_new_inode(inode); | 1929 | unlock_new_inode(inode); |
1724 | } | 1930 | } |
1725 | } | 1931 | } |
1932 | |||
1933 | if (unlikely(do_orphan)) | ||
1934 | btrfs_orphan_cleanup(sub_root); | ||
1935 | |||
1726 | return d_splice_alias(inode, dentry); | 1936 | return d_splice_alias(inode, dentry); |
1727 | } | 1937 | } |
1728 | 1938 | ||
@@ -2964,12 +3174,19 @@ static void btrfs_truncate(struct inode *inode) | |||
2964 | btrfs_set_trans_block_group(trans, inode); | 3174 | btrfs_set_trans_block_group(trans, inode); |
2965 | btrfs_i_size_write(inode, inode->i_size); | 3175 | btrfs_i_size_write(inode, inode->i_size); |
2966 | 3176 | ||
3177 | ret = btrfs_orphan_add(trans, inode); | ||
3178 | if (ret) | ||
3179 | goto out; | ||
2967 | /* FIXME, add redo link to tree so we don't leak on crash */ | 3180 | /* FIXME, add redo link to tree so we don't leak on crash */ |
2968 | ret = btrfs_truncate_in_trans(trans, root, inode, | 3181 | ret = btrfs_truncate_in_trans(trans, root, inode, |
2969 | BTRFS_EXTENT_DATA_KEY); | 3182 | BTRFS_EXTENT_DATA_KEY); |
2970 | btrfs_update_inode(trans, root, inode); | 3183 | btrfs_update_inode(trans, root, inode); |
2971 | nr = trans->blocks_used; | ||
2972 | 3184 | ||
3185 | ret = btrfs_orphan_del(trans, inode); | ||
3186 | BUG_ON(ret); | ||
3187 | |||
3188 | out: | ||
3189 | nr = trans->blocks_used; | ||
2973 | ret = btrfs_end_transaction_throttle(trans, root); | 3190 | ret = btrfs_end_transaction_throttle(trans, root); |
2974 | BUG_ON(ret); | 3191 | BUG_ON(ret); |
2975 | btrfs_btree_balance_dirty(root, nr); | 3192 | btrfs_btree_balance_dirty(root, nr); |
@@ -3046,6 +3263,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) | |||
3046 | btrfs_ordered_inode_tree_init(&ei->ordered_tree); | 3263 | btrfs_ordered_inode_tree_init(&ei->ordered_tree); |
3047 | ei->i_acl = BTRFS_ACL_NOT_CACHED; | 3264 | ei->i_acl = BTRFS_ACL_NOT_CACHED; |
3048 | ei->i_default_acl = BTRFS_ACL_NOT_CACHED; | 3265 | ei->i_default_acl = BTRFS_ACL_NOT_CACHED; |
3266 | INIT_LIST_HEAD(&ei->i_orphan); | ||
3049 | return &ei->vfs_inode; | 3267 | return &ei->vfs_inode; |
3050 | } | 3268 | } |
3051 | 3269 | ||
@@ -3062,6 +3280,14 @@ void btrfs_destroy_inode(struct inode *inode) | |||
3062 | BTRFS_I(inode)->i_default_acl != BTRFS_ACL_NOT_CACHED) | 3280 | BTRFS_I(inode)->i_default_acl != BTRFS_ACL_NOT_CACHED) |
3063 | posix_acl_release(BTRFS_I(inode)->i_default_acl); | 3281 | posix_acl_release(BTRFS_I(inode)->i_default_acl); |
3064 | 3282 | ||
3283 | spin_lock(&BTRFS_I(inode)->root->orphan_lock); | ||
3284 | if (!list_empty(&BTRFS_I(inode)->i_orphan)) { | ||
3285 | printk(KERN_ERR "BTRFS: inode %lu: inode still on the orphan" | ||
3286 | " list\n", inode->i_ino); | ||
3287 | dump_stack(); | ||
3288 | } | ||
3289 | spin_unlock(&BTRFS_I(inode)->root->orphan_lock); | ||
3290 | |||
3065 | while(1) { | 3291 | while(1) { |
3066 | ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1); | 3292 | ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1); |
3067 | if (!ordered) | 3293 | if (!ordered) |
@@ -3202,6 +3428,11 @@ static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry, | |||
3202 | ret = btrfs_unlink_trans(trans, root, new_dir, new_dentry); | 3428 | ret = btrfs_unlink_trans(trans, root, new_dir, new_dentry); |
3203 | if (ret) | 3429 | if (ret) |
3204 | goto out_fail; | 3430 | goto out_fail; |
3431 | if (new_inode->i_nlink == 0) { | ||
3432 | ret = btrfs_orphan_add(trans, new_inode); | ||
3433 | if (ret) | ||
3434 | goto out_fail; | ||
3435 | } | ||
3205 | } | 3436 | } |
3206 | ret = btrfs_set_inode_index(new_dir, old_inode); | 3437 | ret = btrfs_set_inode_index(new_dir, old_inode); |
3207 | if (ret) | 3438 | if (ret) |
diff --git a/fs/btrfs/orphan.c b/fs/btrfs/orphan.c new file mode 100644 index 000000000000..3c0d52af4f80 --- /dev/null +++ b/fs/btrfs/orphan.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Red Hat. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License v2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
11 | * General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public | ||
14 | * License along with this program; if not, write to the | ||
15 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
16 | * Boston, MA 021110-1307, USA. | ||
17 | */ | ||
18 | |||
19 | #include "ctree.h" | ||
20 | #include "disk-io.h" | ||
21 | |||
22 | int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, | ||
23 | struct btrfs_root *root, u64 offset) | ||
24 | { | ||
25 | struct btrfs_path *path; | ||
26 | struct btrfs_key key; | ||
27 | int ret = 0; | ||
28 | |||
29 | key.objectid = BTRFS_ORPHAN_OBJECTID; | ||
30 | btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY); | ||
31 | key.offset = offset; | ||
32 | |||
33 | path = btrfs_alloc_path(); | ||
34 | if (!path) | ||
35 | return -ENOMEM; | ||
36 | |||
37 | ret = btrfs_insert_empty_item(trans, root, path, &key, 0); | ||
38 | |||
39 | btrfs_free_path(path); | ||
40 | return ret; | ||
41 | } | ||
42 | |||
43 | int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, | ||
44 | struct btrfs_root *root, u64 offset) | ||
45 | { | ||
46 | struct btrfs_path *path; | ||
47 | struct btrfs_key key; | ||
48 | int ret = 0; | ||
49 | |||
50 | key.objectid = BTRFS_ORPHAN_OBJECTID; | ||
51 | btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY); | ||
52 | key.offset = offset; | ||
53 | |||
54 | path = btrfs_alloc_path(); | ||
55 | if (!path) | ||
56 | return -ENOMEM; | ||
57 | |||
58 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | ||
59 | if (ret) | ||
60 | goto out; | ||
61 | |||
62 | ret = btrfs_del_item(trans, root, path); | ||
63 | |||
64 | out: | ||
65 | btrfs_free_path(path); | ||
66 | return ret; | ||
67 | } | ||