Loading fs/btrfs/tree-log.c +97 −81 Original line number Original line Diff line number Diff line Loading @@ -785,76 +785,18 @@ static noinline int backref_in_log(struct btrfs_root *log, return match; return match; } } static inline int __add_inode_ref(struct btrfs_trans_handle *trans, /* * replay one inode back reference item found in the log tree. * eb, slot and key refer to the buffer and key found in the log tree. * root is the destination we are replaying into, and path is for temp * use by this function. (it should be released on return). */ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_root *root, struct btrfs_root *log, struct btrfs_path *path, struct btrfs_path *path, struct extent_buffer *eb, int slot, struct btrfs_root *log_root, struct btrfs_key *key) struct inode *dir, struct inode *inode, struct btrfs_key *key, struct extent_buffer *eb, struct btrfs_inode_ref *ref, char *name, int namelen, int *search_done) { { struct btrfs_inode_ref *ref; struct btrfs_dir_item *di; struct inode *dir; struct inode *inode; unsigned long ref_ptr; unsigned long ref_end; char *name; int namelen; int ret; int ret; int search_done = 0; struct btrfs_dir_item *di; /* * it is possible that we didn't log all the parent directories * for a given inode. If we don't find the dir, just don't * copy the back ref in. The link count fixup code will take * care of the rest */ dir = read_one_inode(root, key->offset); if (!dir) return -ENOENT; inode = read_one_inode(root, key->objectid); if (!inode) { iput(dir); return -EIO; } ref_ptr = btrfs_item_ptr_offset(eb, slot); ref_end = ref_ptr + btrfs_item_size_nr(eb, slot); again: ref = (struct btrfs_inode_ref *)ref_ptr; namelen = btrfs_inode_ref_name_len(eb, ref); name = kmalloc(namelen, GFP_NOFS); BUG_ON(!name); read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen); /* if we already have a perfect match, we're done */ if (inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode), btrfs_inode_ref_index(eb, ref), name, namelen)) { goto out; } /* * look for a conflicting back reference in the metadata. * if we find one we have to unlink that name of the file * before we add our new link. Later on, we overwrite any * existing back reference, and we don't want to create * dangling pointers in the directory. */ if (search_done) goto insert; ret = btrfs_search_slot(NULL, root, key, path, 0, 0); ret = btrfs_search_slot(NULL, root, key, path, 0, 0); if (ret == 0) { if (ret == 0) { Loading @@ -869,7 +811,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, * if so, just jump out, we're done * if so, just jump out, we're done */ */ if (key->objectid == key->offset) if (key->objectid == key->offset) goto out_nowrite; return 1; /* check all the names in this back reference to see /* check all the names in this back reference to see * if they are in the log. if so, we allow them to stay * if they are in the log. if so, we allow them to stay Loading @@ -888,7 +830,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, (unsigned long)(victim_ref + 1), (unsigned long)(victim_ref + 1), victim_name_len); victim_name_len); if (!backref_in_log(log, key, victim_name, if (!backref_in_log(log_root, key, victim_name, victim_name_len)) { victim_name_len)) { btrfs_inc_nlink(inode); btrfs_inc_nlink(inode); btrfs_release_path(path); btrfs_release_path(path); Loading @@ -907,7 +849,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, * NOTE: we have searched root tree and checked the * NOTE: we have searched root tree and checked the * coresponding ref, it does not need to check again. * coresponding ref, it does not need to check again. */ */ search_done = 1; *search_done = 1; } } btrfs_release_path(path); btrfs_release_path(path); Loading @@ -930,25 +872,99 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, } } btrfs_release_path(path); btrfs_release_path(path); insert: return 0; } /* * replay one inode back reference item found in the log tree. * eb, slot and key refer to the buffer and key found in the log tree. * root is the destination we are replaying into, and path is for temp * use by this function. (it should be released on return). */ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_root *log, struct btrfs_path *path, struct extent_buffer *eb, int slot, struct btrfs_key *key) { struct btrfs_inode_ref *ref; struct inode *dir; struct inode *inode; unsigned long ref_ptr; unsigned long ref_end; char *name; int namelen; int ret; int search_done = 0; /* * it is possible that we didn't log all the parent directories * for a given inode. If we don't find the dir, just don't * copy the back ref in. The link count fixup code will take * care of the rest */ dir = read_one_inode(root, key->offset); if (!dir) return -ENOENT; inode = read_one_inode(root, key->objectid); if (!inode) { iput(dir); return -EIO; } ref_ptr = btrfs_item_ptr_offset(eb, slot); ref_end = ref_ptr + btrfs_item_size_nr(eb, slot); while (ref_ptr < ref_end) { ref = (struct btrfs_inode_ref *)ref_ptr; namelen = btrfs_inode_ref_name_len(eb, ref); name = kmalloc(namelen, GFP_NOFS); BUG_ON(!name); read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen); /* if we already have a perfect match, we're done */ if (!inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode), btrfs_inode_ref_index(eb, ref), name, namelen)) { /* * look for a conflicting back reference in the * metadata. if we find one we have to unlink that name * of the file before we add our new link. Later on, we * overwrite any existing back reference, and we don't * want to create dangling pointers in the directory. */ if (!search_done) { ret = __add_inode_ref(trans, root, path, log, dir, inode, key, eb, ref, name, namelen, &search_done); if (ret == 1) goto out; BUG_ON(ret); } /* insert our name */ /* insert our name */ ret = btrfs_add_link(trans, dir, inode, name, namelen, 0, ret = btrfs_add_link(trans, dir, inode, name, namelen, btrfs_inode_ref_index(eb, ref)); 0, btrfs_inode_ref_index(eb, ref)); BUG_ON(ret); BUG_ON(ret); btrfs_update_inode(trans, root, inode); btrfs_update_inode(trans, root, inode); } out: ref_ptr = (unsigned long)(ref + 1) + namelen; ref_ptr = (unsigned long)(ref + 1) + namelen; kfree(name); kfree(name); if (ref_ptr < ref_end) } goto again; /* finally write the back reference in the inode */ /* finally write the back reference in the inode */ ret = overwrite_item(trans, root, path, eb, slot, key); ret = overwrite_item(trans, root, path, eb, slot, key); BUG_ON(ret); BUG_ON(ret); out_nowrite: out: btrfs_release_path(path); btrfs_release_path(path); iput(dir); iput(dir); iput(inode); iput(inode); Loading Loading
fs/btrfs/tree-log.c +97 −81 Original line number Original line Diff line number Diff line Loading @@ -785,76 +785,18 @@ static noinline int backref_in_log(struct btrfs_root *log, return match; return match; } } static inline int __add_inode_ref(struct btrfs_trans_handle *trans, /* * replay one inode back reference item found in the log tree. * eb, slot and key refer to the buffer and key found in the log tree. * root is the destination we are replaying into, and path is for temp * use by this function. (it should be released on return). */ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_root *root, struct btrfs_root *log, struct btrfs_path *path, struct btrfs_path *path, struct extent_buffer *eb, int slot, struct btrfs_root *log_root, struct btrfs_key *key) struct inode *dir, struct inode *inode, struct btrfs_key *key, struct extent_buffer *eb, struct btrfs_inode_ref *ref, char *name, int namelen, int *search_done) { { struct btrfs_inode_ref *ref; struct btrfs_dir_item *di; struct inode *dir; struct inode *inode; unsigned long ref_ptr; unsigned long ref_end; char *name; int namelen; int ret; int ret; int search_done = 0; struct btrfs_dir_item *di; /* * it is possible that we didn't log all the parent directories * for a given inode. If we don't find the dir, just don't * copy the back ref in. The link count fixup code will take * care of the rest */ dir = read_one_inode(root, key->offset); if (!dir) return -ENOENT; inode = read_one_inode(root, key->objectid); if (!inode) { iput(dir); return -EIO; } ref_ptr = btrfs_item_ptr_offset(eb, slot); ref_end = ref_ptr + btrfs_item_size_nr(eb, slot); again: ref = (struct btrfs_inode_ref *)ref_ptr; namelen = btrfs_inode_ref_name_len(eb, ref); name = kmalloc(namelen, GFP_NOFS); BUG_ON(!name); read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen); /* if we already have a perfect match, we're done */ if (inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode), btrfs_inode_ref_index(eb, ref), name, namelen)) { goto out; } /* * look for a conflicting back reference in the metadata. * if we find one we have to unlink that name of the file * before we add our new link. Later on, we overwrite any * existing back reference, and we don't want to create * dangling pointers in the directory. */ if (search_done) goto insert; ret = btrfs_search_slot(NULL, root, key, path, 0, 0); ret = btrfs_search_slot(NULL, root, key, path, 0, 0); if (ret == 0) { if (ret == 0) { Loading @@ -869,7 +811,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, * if so, just jump out, we're done * if so, just jump out, we're done */ */ if (key->objectid == key->offset) if (key->objectid == key->offset) goto out_nowrite; return 1; /* check all the names in this back reference to see /* check all the names in this back reference to see * if they are in the log. if so, we allow them to stay * if they are in the log. if so, we allow them to stay Loading @@ -888,7 +830,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, (unsigned long)(victim_ref + 1), (unsigned long)(victim_ref + 1), victim_name_len); victim_name_len); if (!backref_in_log(log, key, victim_name, if (!backref_in_log(log_root, key, victim_name, victim_name_len)) { victim_name_len)) { btrfs_inc_nlink(inode); btrfs_inc_nlink(inode); btrfs_release_path(path); btrfs_release_path(path); Loading @@ -907,7 +849,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, * NOTE: we have searched root tree and checked the * NOTE: we have searched root tree and checked the * coresponding ref, it does not need to check again. * coresponding ref, it does not need to check again. */ */ search_done = 1; *search_done = 1; } } btrfs_release_path(path); btrfs_release_path(path); Loading @@ -930,25 +872,99 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, } } btrfs_release_path(path); btrfs_release_path(path); insert: return 0; } /* * replay one inode back reference item found in the log tree. * eb, slot and key refer to the buffer and key found in the log tree. * root is the destination we are replaying into, and path is for temp * use by this function. (it should be released on return). */ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_root *log, struct btrfs_path *path, struct extent_buffer *eb, int slot, struct btrfs_key *key) { struct btrfs_inode_ref *ref; struct inode *dir; struct inode *inode; unsigned long ref_ptr; unsigned long ref_end; char *name; int namelen; int ret; int search_done = 0; /* * it is possible that we didn't log all the parent directories * for a given inode. If we don't find the dir, just don't * copy the back ref in. The link count fixup code will take * care of the rest */ dir = read_one_inode(root, key->offset); if (!dir) return -ENOENT; inode = read_one_inode(root, key->objectid); if (!inode) { iput(dir); return -EIO; } ref_ptr = btrfs_item_ptr_offset(eb, slot); ref_end = ref_ptr + btrfs_item_size_nr(eb, slot); while (ref_ptr < ref_end) { ref = (struct btrfs_inode_ref *)ref_ptr; namelen = btrfs_inode_ref_name_len(eb, ref); name = kmalloc(namelen, GFP_NOFS); BUG_ON(!name); read_extent_buffer(eb, name, (unsigned long)(ref + 1), namelen); /* if we already have a perfect match, we're done */ if (!inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode), btrfs_inode_ref_index(eb, ref), name, namelen)) { /* * look for a conflicting back reference in the * metadata. if we find one we have to unlink that name * of the file before we add our new link. Later on, we * overwrite any existing back reference, and we don't * want to create dangling pointers in the directory. */ if (!search_done) { ret = __add_inode_ref(trans, root, path, log, dir, inode, key, eb, ref, name, namelen, &search_done); if (ret == 1) goto out; BUG_ON(ret); } /* insert our name */ /* insert our name */ ret = btrfs_add_link(trans, dir, inode, name, namelen, 0, ret = btrfs_add_link(trans, dir, inode, name, namelen, btrfs_inode_ref_index(eb, ref)); 0, btrfs_inode_ref_index(eb, ref)); BUG_ON(ret); BUG_ON(ret); btrfs_update_inode(trans, root, inode); btrfs_update_inode(trans, root, inode); } out: ref_ptr = (unsigned long)(ref + 1) + namelen; ref_ptr = (unsigned long)(ref + 1) + namelen; kfree(name); kfree(name); if (ref_ptr < ref_end) } goto again; /* finally write the back reference in the inode */ /* finally write the back reference in the inode */ ret = overwrite_item(trans, root, path, eb, slot, key); ret = overwrite_item(trans, root, path, eb, slot, key); BUG_ON(ret); BUG_ON(ret); out_nowrite: out: btrfs_release_path(path); btrfs_release_path(path); iput(dir); iput(dir); iput(inode); iput(inode); Loading