Created
April 12, 2018 15:50
-
-
Save barcharcraz/0678e3180615d627d7aa4769e07c274b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1,4c1,18 | |
< #ifndef MY_ABC_HERE | |
< #define MY_ABC_HERE | |
< #endif | |
< | |
--- | |
> /* | |
> * Copyright (C) 2012 Alexander Block. All rights reserved. | |
> * | |
> * This program is free software; you can redistribute it and/or | |
> * modify it under the terms of the GNU General Public | |
> * License v2 as published by the Free Software Foundation. | |
> * | |
> * This program is distributed in the hope that it will be useful, | |
> * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
> * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
> * General Public License for more details. | |
> * | |
> * You should have received a copy of the GNU General Public | |
> * License along with this program; if not, write to the | |
> * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
> * Boston, MA 021110-1307, USA. | |
> */ | |
> | |
12a27 | |
> #include <linux/crc32c.h> | |
14d28 | |
< #include <linux/string.h> | |
18d31 | |
< #include "hash.h" | |
24,27d36 | |
< #ifdef MY_DEF_HERE | |
< #include <linux/time.h> | |
< #endif | |
< | |
31a41,47 | |
> /* | |
> * A fs_path is a helper to dynamically build path names with unknown size. | |
> * It reallocates the internal buffer on demand. | |
> * It allows fast adding of path elements on the right side (normal path) and | |
> * fast adding to the left side (reversed path). A reversed path can also be | |
> * unreversed if needed. | |
> */ | |
36a53 | |
> char *prepared; | |
39,40c56,58 | |
< unsigned short buf_len:15; | |
< unsigned short reversed:1; | |
--- | |
> int buf_len; | |
> int reversed:1; | |
> int virtual_mem:1; | |
43,44c61 | |
< | |
< char pad[256]; | |
--- | |
> char pad[PAGE_SIZE]; | |
49a67,68 | |
> | |
> /* reused for each extent */ | |
61,75d79 | |
< #ifdef MY_DEF_HERE | |
< enum btrfs_send_phase { | |
< SEND_PHASE_STREAM_CHANGES, | |
< SEND_PHASE_COMPUTE_DATA_SIZE, | |
< }; | |
< #endif | |
< | |
< #ifdef MY_DEF_HERE | |
< enum syno_archive{ | |
< syno_archive_set = 0x1, | |
< syno_archive_set_owner_group = 0x1 << 1, | |
< syno_archive_set_acl = 0x1 << 2, | |
< }; | |
< #endif | |
< | |
84c88,90 | |
< u64 flags; | |
--- | |
> u64 flags; /* 'flags' member of btrfs_ioctl_send_args is u64 */ | |
> | |
> struct vfsmount *mnt; | |
90a97 | |
> /* current state of the compare_tree call */ | |
94a102,105 | |
> /* | |
> * infos of the currently processed inode. In case of deleted inodes, | |
> * these are the values from the deleted inode. | |
> */ | |
102,106d112 | |
< u64 cur_inode_rdev; | |
< u64 cur_inode_last_extent; | |
< #ifdef MY_DEF_HERE | |
< u32 cur_inode_archive; | |
< #endif | |
109,120d114 | |
< #ifdef MY_DEF_HERE | |
< enum btrfs_send_phase phase; | |
< u64 total_data_size; | |
< struct timeval write_timeval; | |
< #endif | |
< #ifdef MY_DEF_HERE | |
< u32 subvol_flags; | |
< #endif | |
< #ifdef MY_DEF_HERE | |
< u64 skip_cmd_count; | |
< u64 current_cmd_pos; | |
< #endif | |
129,130c123 | |
< struct file_ra_state ra; | |
< | |
--- | |
> struct file *cur_inode_filp; | |
132,167d124 | |
< | |
< struct rb_root pending_dir_moves; | |
< | |
< struct rb_root waiting_dir_moves; | |
< | |
< struct rb_root orphan_dirs; | |
< }; | |
< | |
< struct pending_dir_move { | |
< struct rb_node node; | |
< struct list_head list; | |
< u64 parent_ino; | |
< u64 ino; | |
< u64 gen; | |
< #ifdef MY_DEF_HERE | |
< #else | |
< bool is_orphan; | |
< #endif | |
< struct list_head update_refs; | |
< }; | |
< | |
< struct waiting_dir_move { | |
< struct rb_node node; | |
< u64 ino; | |
< | |
< u64 rmdir_ino; | |
< #ifdef MY_DEF_HERE | |
< bool orphanized; | |
< u64 gen; | |
< #endif | |
< }; | |
< | |
< struct orphan_dir_info { | |
< struct rb_node node; | |
< u64 ino; | |
< u64 gen; | |
172c129,136 | |
< | |
--- | |
> /* | |
> * radix_tree has only 32bit entries but we need to handle 64bit inums. | |
> * We use the lower 32bit of the 64bit inum to store it in the tree. If | |
> * more then one inum would fall into the same entry, we use radix_list | |
> * to store the additional entries. radix_list is also used to store | |
> * entries where two entries have the same inum but different | |
> * generations. | |
> */ | |
184,201d147 | |
< static int is_waiting_for_move(struct send_ctx *sctx, u64 ino); | |
< | |
< static struct waiting_dir_move * | |
< get_waiting_dir_move(struct send_ctx *sctx, u64 ino); | |
< | |
< #ifdef MY_DEF_HERE | |
< static int is_waiting_for_rm(struct send_ctx *sctx, u64 dir_ino, u64 dir_gen); | |
< #else | |
< static int is_waiting_for_rm(struct send_ctx *sctx, u64 dir_ino); | |
< #endif | |
< | |
< static int need_send_hole(struct send_ctx *sctx) | |
< { | |
< return (sctx->parent_root && !sctx->cur_inode_new && | |
< !sctx->cur_inode_new_gen && !sctx->cur_inode_deleted && | |
< S_ISREG(sctx->cur_inode_mode)); | |
< } | |
< | |
215c161 | |
< static struct fs_path *fs_path_alloc(void) | |
--- | |
> static struct fs_path *fs_path_alloc(struct send_ctx *sctx) | |
222a169 | |
> p->virtual_mem = 0; | |
229c176 | |
< static struct fs_path *fs_path_alloc_reversed(void) | |
--- | |
> static struct fs_path *fs_path_alloc_reversed(struct send_ctx *sctx) | |
233c180 | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
241c188 | |
< static void fs_path_free(struct fs_path *p) | |
--- | |
> static void fs_path_free(struct send_ctx *sctx, struct fs_path *p) | |
245,246c192,197 | |
< if (p->buf != p->inline_buf) | |
< kfree(p->buf); | |
--- | |
> if (p->buf != p->inline_buf) { | |
> if (p->virtual_mem) | |
> vfree(p->buf); | |
> else | |
> kfree(p->buf); | |
> } | |
266,270d216 | |
< if (len > PATH_MAX) { | |
< WARN_ON(1); | |
< return -ENOMEM; | |
< } | |
< | |
272a219 | |
> len = PAGE_ALIGN(len); | |
276,277c223,231 | |
< if (tmp_buf) | |
< memcpy(tmp_buf, p->buf, old_buf_len); | |
--- | |
> if (!tmp_buf) { | |
> tmp_buf = vmalloc(len); | |
> if (!tmp_buf) | |
> return -ENOMEM; | |
> p->virtual_mem = 1; | |
> } | |
> memcpy(tmp_buf, p->buf, p->buf_len); | |
> p->buf = tmp_buf; | |
> p->buf_len = len; | |
279c233,251 | |
< tmp_buf = krealloc(p->buf, len, GFP_NOFS); | |
--- | |
> if (p->virtual_mem) { | |
> tmp_buf = vmalloc(len); | |
> if (!tmp_buf) | |
> return -ENOMEM; | |
> memcpy(tmp_buf, p->buf, p->buf_len); | |
> vfree(p->buf); | |
> } else { | |
> tmp_buf = krealloc(p->buf, len, GFP_NOFS); | |
> if (!tmp_buf) { | |
> tmp_buf = vmalloc(len); | |
> if (!tmp_buf) | |
> return -ENOMEM; | |
> memcpy(tmp_buf, p->buf, p->buf_len); | |
> kfree(p->buf); | |
> p->virtual_mem = 1; | |
> } | |
> } | |
> p->buf = tmp_buf; | |
> p->buf_len = len; | |
281,286d252 | |
< if (!tmp_buf) | |
< return -ENOMEM; | |
< p->buf = tmp_buf; | |
< | |
< p->buf_len = ksize(p->buf); | |
< | |
299,300c265 | |
< static int fs_path_prepare_for_add(struct fs_path *p, int name_len, | |
< char **prepared) | |
--- | |
> static int fs_path_prepare_for_add(struct fs_path *p, int name_len) | |
316c281 | |
< *prepared = p->start; | |
--- | |
> p->prepared = p->start; | |
320c285 | |
< *prepared = p->end; | |
--- | |
> p->prepared = p->end; | |
332d296 | |
< char *prepared; | |
334c298 | |
< ret = fs_path_prepare_for_add(p, name_len, &prepared); | |
--- | |
> ret = fs_path_prepare_for_add(p, name_len); | |
337c301,302 | |
< memcpy(prepared, name, name_len); | |
--- | |
> memcpy(p->prepared, name, name_len); | |
> p->prepared = NULL; | |
346d310 | |
< char *prepared; | |
348c312 | |
< ret = fs_path_prepare_for_add(p, p2->end - p2->start, &prepared); | |
--- | |
> ret = fs_path_prepare_for_add(p, p2->end - p2->start); | |
351c315,316 | |
< memcpy(prepared, p2->start, p2->end - p2->start); | |
--- | |
> memcpy(p->prepared, p2->start, p2->end - p2->start); | |
> p->prepared = NULL; | |
362d326 | |
< char *prepared; | |
364c328 | |
< ret = fs_path_prepare_for_add(p, len, &prepared); | |
--- | |
> ret = fs_path_prepare_for_add(p, len); | |
368c332,333 | |
< read_extent_buffer(eb, prepared, off, len); | |
--- | |
> read_extent_buffer(eb, p->prepared, off, len); | |
> p->prepared = NULL; | |
373a339,348 | |
> #if 0 | |
> static void fs_path_remove(struct fs_path *p) | |
> { | |
> BUG_ON(p->reversed); | |
> while (p->start != p->end && *p->end != '/') | |
> p->end--; | |
> *p->end = 0; | |
> } | |
> #endif | |
> | |
385a361 | |
> | |
411d386 | |
< path->need_commit_sem = 1; | |
415,417d389 | |
< #if defined(MY_DEF_HERE) || defined(MY_DEF_HERE) | |
< int write_buf(struct file *filp, const void *buf, u32 len, loff_t *off) | |
< #else | |
419d390 | |
< #endif | |
430c401,404 | |
< | |
--- | |
> /* TODO handle that correctly */ | |
> /*if (ret == -ERESTARTSYS) { | |
> continue; | |
> }*/ | |
465,471c439,443 | |
< #define TLV_PUT_DEFINE_INT(bits) \ | |
< static int tlv_put_u##bits(struct send_ctx *sctx, \ | |
< u##bits attr, u##bits value) \ | |
< { \ | |
< __le##bits __tmp = cpu_to_le##bits(value); \ | |
< return tlv_put(sctx, attr, &__tmp, sizeof(__tmp)); \ | |
< } | |
--- | |
> #if 0 | |
> static int tlv_put_u8(struct send_ctx *sctx, u16 attr, u8 value) | |
> { | |
> return tlv_put(sctx, attr, &value, sizeof(value)); | |
> } | |
473,474c445,455 | |
< #ifdef MY_DEF_HERE | |
< TLV_PUT_DEFINE_INT(32) | |
--- | |
> static int tlv_put_u16(struct send_ctx *sctx, u16 attr, u16 value) | |
> { | |
> __le16 tmp = cpu_to_le16(value); | |
> return tlv_put(sctx, attr, &tmp, sizeof(tmp)); | |
> } | |
> | |
> static int tlv_put_u32(struct send_ctx *sctx, u16 attr, u32 value) | |
> { | |
> __le32 tmp = cpu_to_le32(value); | |
> return tlv_put(sctx, attr, &tmp, sizeof(tmp)); | |
> } | |
476c457,462 | |
< TLV_PUT_DEFINE_INT(64) | |
--- | |
> | |
> static int tlv_put_u64(struct send_ctx *sctx, u16 attr, u64 value) | |
> { | |
> __le64 tmp = cpu_to_le64(value); | |
> return tlv_put(sctx, attr, &tmp, sizeof(tmp)); | |
> } | |
491a478,488 | |
> #if 0 | |
> static int tlv_put_timespec(struct send_ctx *sctx, u16 attr, | |
> struct timespec *ts) | |
> { | |
> struct btrfs_timespec bts; | |
> bts.sec = cpu_to_le64(ts->tv_sec); | |
> bts.nsec = cpu_to_le32(ts->tv_nsec); | |
> return tlv_put(sctx, attr, &bts, sizeof(bts)); | |
> } | |
> #endif | |
> | |
501,507d497 | |
< #ifdef MY_DEF_HERE | |
< static int tlv_put_btrfs_subvol_timespec(struct send_ctx *sctx, u16 attr, | |
< struct btrfs_timespec *ts) | |
< { | |
< return tlv_put(sctx, attr, ts, sizeof(struct btrfs_timespec)); | |
< } | |
< #endif | |
546c536 | |
< #define TLV_PUT_BTRFS_TIMESPEC(sctx, attrtype, eb, ts) \ | |
--- | |
> #define TLV_PUT_TIMESPEC(sctx, attrtype, ts) \ | |
548c538 | |
< ret = tlv_put_btrfs_timespec(sctx, attrtype, eb, ts); \ | |
--- | |
> ret = tlv_put_timespec(sctx, attrtype, ts); \ | |
552,553c542 | |
< #ifdef MY_DEF_HERE | |
< #define TLV_PUT_BTRFS_SUBVOL_TIMESPEC(sctx, attrtype, ts) \ | |
--- | |
> #define TLV_PUT_BTRFS_TIMESPEC(sctx, attrtype, eb, ts) \ | |
555c544 | |
< ret = tlv_put_btrfs_subvol_timespec(sctx, attrtype, ts); \ | |
--- | |
> ret = tlv_put_btrfs_timespec(sctx, attrtype, eb, ts); \ | |
559d547 | |
< #endif | |
571a560,562 | |
> /* | |
> * For each command/item we want to send to userspace, we call this function. | |
> */ | |
576c567,568 | |
< if (WARN_ON(!sctx->send_buf)) | |
--- | |
> if (!sctx->send_buf) { | |
> WARN_ON(1); | |
577a570 | |
> } | |
595,603d587 | |
< | |
< #ifdef MY_DEF_HERE | |
< if (sctx->current_cmd_pos < sctx->skip_cmd_count && (le16_to_cpu(hdr->cmd) != BTRFS_SEND_C_SUBVOL) && (le16_to_cpu(hdr->cmd) != BTRFS_SEND_C_SNAPSHOT)) { | |
< sctx->current_cmd_pos++; | |
< sctx->send_size = 0; | |
< return 0; | |
< } | |
< #endif | |
< | |
607c591 | |
< crc = btrfs_crc32c(0, (unsigned char *)sctx->send_buf, sctx->send_size); | |
--- | |
> crc = crc32c(0, (unsigned char *)sctx->send_buf, sctx->send_size); | |
619a604,606 | |
> /* | |
> * Sends a move instruction to user space | |
> */ | |
640a628,630 | |
> /* | |
> * Sends a link instruction to user space | |
> */ | |
661a652,654 | |
> /* | |
> * Sends an unlink instruction to user space | |
> */ | |
680a674,676 | |
> /* | |
> * Sends a rmdir instruction to user space | |
> */ | |
700,702c696,702 | |
< static int __get_inode_info(struct btrfs_root *root, struct btrfs_path *path, | |
< u64 ino, u64 *size, u64 *gen, u64 *mode, u64 *uid, | |
< u64 *gid, u64 *rdev) | |
--- | |
> /* | |
> * Helper function to retrieve some fields from an inode item. | |
> */ | |
> static int get_inode_info(struct btrfs_root *root, | |
> u64 ino, u64 *size, u64 *gen, | |
> u64 *mode, u64 *uid, u64 *gid, | |
> u64 *rdev) | |
706a707,711 | |
> struct btrfs_path *path; | |
> | |
> path = alloc_path_for_send(); | |
> if (!path) | |
> return -ENOMEM; | |
711a717,718 | |
> if (ret < 0) | |
> goto out; | |
713,715c720,721 | |
< if (ret > 0) | |
< ret = -ENOENT; | |
< return ret; | |
--- | |
> ret = -ENOENT; | |
> goto out; | |
733,748c739 | |
< return ret; | |
< } | |
< | |
< static int get_inode_info(struct btrfs_root *root, | |
< u64 ino, u64 *size, u64 *gen, | |
< u64 *mode, u64 *uid, u64 *gid, | |
< u64 *rdev) | |
< { | |
< struct btrfs_path *path; | |
< int ret; | |
< | |
< path = alloc_path_for_send(); | |
< if (!path) | |
< return -ENOMEM; | |
< ret = __get_inode_info(root, path, ino, size, gen, mode, uid, gid, | |
< rdev); | |
--- | |
> out: | |
757c748,757 | |
< static int iterate_inode_ref(struct btrfs_root *root, struct btrfs_path *path, | |
--- | |
> /* | |
> * Helper function to iterate the entries in ONE btrfs_inode_ref or | |
> * btrfs_inode_extref. | |
> * The iterate callback may return a non zero value to stop iteration. This can | |
> * be a negative value for error codes or 1 to simply stop it. | |
> * | |
> * path must point to the INODE_REF or INODE_EXTREF when called. | |
> */ | |
> static int iterate_inode_ref(struct send_ctx *sctx, | |
> struct btrfs_root *root, struct btrfs_path *path, | |
780c780 | |
< p = fs_path_alloc_reversed(); | |
--- | |
> p = fs_path_alloc_reversed(sctx); | |
786c786 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
789a790 | |
> | |
793c794 | |
< item = btrfs_item_nr(slot); | |
--- | |
> item = btrfs_item_nr(eb, slot); | |
828c829 | |
< | |
--- | |
> /* overflow , try again with larger buffer */ | |
860c861 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
869c870,878 | |
< static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, | |
--- | |
> /* | |
> * Helper function to iterate the entries in ONE btrfs_dir_item. | |
> * The iterate callback may return a non zero value to stop iteration. This can | |
> * be a negative value for error codes or 1 to simply stop it. | |
> * | |
> * path must point to the dir item when called. | |
> */ | |
> static int iterate_dir_item(struct send_ctx *sctx, | |
> struct btrfs_root *root, struct btrfs_path *path, | |
878a888 | |
> char *buf2 = NULL; | |
879a890 | |
> int buf_virtual = 0; | |
889,893c900 | |
< if (found_key->type == BTRFS_XATTR_ITEM_KEY) | |
< buf_len = BTRFS_MAX_XATTR_SIZE(root); | |
< else | |
< buf_len = PATH_MAX; | |
< | |
--- | |
> buf_len = PAGE_SIZE; | |
902c909 | |
< item = btrfs_item_nr(slot); | |
--- | |
> item = btrfs_item_nr(eb, slot); | |
915,928c922,941 | |
< if (type == BTRFS_FT_XATTR) { | |
< if (name_len > XATTR_NAME_MAX) { | |
< ret = -ENAMETOOLONG; | |
< goto out; | |
< } | |
< if (name_len + data_len > buf_len) { | |
< ret = -E2BIG; | |
< goto out; | |
< } | |
< } else { | |
< | |
< if (name_len + data_len > buf_len) { | |
< ret = -ENAMETOOLONG; | |
< goto out; | |
--- | |
> if (name_len + data_len > buf_len) { | |
> buf_len = PAGE_ALIGN(name_len + data_len); | |
> if (buf_virtual) { | |
> buf2 = vmalloc(buf_len); | |
> if (!buf2) { | |
> ret = -ENOMEM; | |
> goto out; | |
> } | |
> vfree(buf); | |
> } else { | |
> buf2 = krealloc(buf, buf_len, GFP_NOFS); | |
> if (!buf2) { | |
> buf2 = vmalloc(buf_len); | |
> if (!buf2) { | |
> ret = -ENOMEM; | |
> goto out; | |
> } | |
> kfree(buf); | |
> buf_virtual = 1; | |
> } | |
929a943,945 | |
> | |
> buf = buf2; | |
> buf2 = NULL; | |
952c968,971 | |
< kfree(buf); | |
--- | |
> if (buf_virtual) | |
> vfree(buf); | |
> else | |
> kfree(buf); | |
965a985 | |
> /* we want the first only */ | |
969c989,993 | |
< static int get_inode_path(struct btrfs_root *root, | |
--- | |
> /* | |
> * Retrieve the first path of an inode. If an inode has more then one | |
> * ref/hardlink, this is ignored. | |
> */ | |
> static int get_inode_path(struct send_ctx *sctx, struct btrfs_root *root, | |
1001,1002c1025,1026 | |
< ret = iterate_inode_ref(root, p, &found_key, 1, | |
< __copy_first_ref, path); | |
--- | |
> ret = iterate_inode_ref(sctx, root, p, &found_key, 1, | |
> __copy_first_ref, path); | |
1015,1016c1039 | |
< struct btrfs_path *path; | |
< | |
--- | |
> /* number of total found references */ | |
1018a1042,1045 | |
> /* | |
> * used for clones found in send_root. clones found behind cur_objectid | |
> * and cur_offset are not considered as allowed clones. | |
> */ | |
1021a1049 | |
> /* may be truncated in case it's the last extent in a file */ | |
1024,1025c1052 | |
< u64 data_offset; | |
< | |
--- | |
> /* Just to check for bugs in backref resolving */ | |
1052a1080,1083 | |
> /* | |
> * Called for every backref that is found for the current extent. | |
> * Results are collected in sctx->clone_roots->ino/offset/found_refs | |
> */ | |
1059a1091 | |
> /* First check if the root is in the list of accepted clone sources */ | |
1073,1075c1105,1110 | |
< ret = __get_inode_info(found->root, bctx->path, ino, &i_size, NULL, NULL, | |
< NULL, NULL, NULL); | |
< btrfs_release_path(bctx->path); | |
--- | |
> /* | |
> * There are inodes that have extents that lie behind its i_size. Don't | |
> * accept clones from these extents. | |
> */ | |
> ret = get_inode_info(found->root, ino, &i_size, NULL, NULL, NULL, NULL, | |
> NULL); | |
1079c1114 | |
< if (offset + bctx->data_offset + bctx->extent_len > i_size) | |
--- | |
> if (offset + bctx->extent_len > i_size) | |
1081a1117,1120 | |
> /* | |
> * Make sure we don't consider clones from send_root that are | |
> * behind the current inode/offset. | |
> */ | |
1083c1122,1127 | |
< | |
--- | |
> /* | |
> * TODO for the moment we don't accept clones from the inode | |
> * that is currently send. We may change this when | |
> * BTRFS_IOC_CLONE_RANGE supports cloning from and to the same | |
> * file. | |
> */ | |
1100c1144,1146 | |
< | |
--- | |
> /* | |
> * same extent found more then once in the same file. | |
> */ | |
1107a1154,1162 | |
> /* | |
> * Given an inode, offset and extent item, it finds a good clone for a clone | |
> * instruction. Returns -ENOENT when none could be found. The function makes | |
> * sure that the returned clone is usable at the point where sending is at the | |
> * moment. This means, that no clones are accepted which lie behind the current | |
> * inode+offset. | |
> * | |
> * path must point to the extent item when called. | |
> */ | |
1134,1135d1188 | |
< tmp_path->need_commit_sem = 0; | |
< | |
1142,1143d1194 | |
< backref_ctx->path = tmp_path; | |
< | |
1145c1196,1200 | |
< | |
--- | |
> /* | |
> * There may be extents that lie behind the file's size. | |
> * I at least had this in combination with snapshotting while | |
> * writing large files. | |
> */ | |
1167d1221 | |
< down_read(&sctx->send_root->fs_info->commit_root_sem); | |
1170d1223 | |
< up_read(&sctx->send_root->fs_info->commit_root_sem); | |
1179a1233,1235 | |
> /* | |
> * Setup the clone roots. | |
> */ | |
1193,1197d1248 | |
< | |
< if (compressed == BTRFS_COMPRESS_NONE) | |
< backref_ctx->data_offset = 0; | |
< else | |
< backref_ctx->data_offset = btrfs_file_extent_offset(eb, fi); | |
1198a1250,1254 | |
> /* | |
> * The last extent of a file may be too large due to page alignment. | |
> * We need to adjust extent_len in this case so that the checks in | |
> * __iterate_backrefs work. | |
> */ | |
1201a1258,1260 | |
> /* | |
> * Now collect all backrefs. | |
> */ | |
1205a1265,1266 | |
> | |
> extent_item_pos = logical - found_key.objectid; | |
1214c1275 | |
< | |
--- | |
> /* found a bug in backref code? */ | |
1216c1277 | |
< btrfs_err(sctx->send_root->fs_info, "did not find backref in " | |
--- | |
> printk(KERN_ERR "btrfs: ERROR did not find backref in " | |
1218c1279 | |
< "disk_byte=%llu found extent=%llu", | |
--- | |
> "disk_byte=%llu found extent=%llu\n", | |
1237c1298 | |
< | |
--- | |
> /* prefer clones from send_root over others */ | |
1256c1317,1318 | |
< static int read_symlink(struct btrfs_root *root, | |
--- | |
> static int read_symlink(struct send_ctx *sctx, | |
> struct btrfs_root *root, | |
1279,1286c1341 | |
< if (ret) { | |
< | |
< btrfs_err(root->fs_info, | |
< "Found empty symlink inode %llu at root %llu", | |
< ino, root->root_key.objectid); | |
< ret = -EIO; | |
< goto out; | |
< } | |
--- | |
> BUG_ON(ret); | |
1296c1351 | |
< len = btrfs_file_extent_inline_len(path->nodes[0], path->slots[0], ei); | |
--- | |
> len = btrfs_file_extent_inline_len(path->nodes[0], ei); | |
1304a1360,1363 | |
> /* | |
> * Helper function to generate a file name that is unique in the root of | |
> * send_root and parent_root. This is used to generate names for orphan inodes. | |
> */ | |
1321c1380 | |
< len = snprintf(tmp, sizeof(tmp), "o%llu-%llu-%llu", | |
--- | |
> len = snprintf(tmp, sizeof(tmp) - 1, "o%llu-%llu-%llu", | |
1323c1382,1386 | |
< ASSERT(len < sizeof(tmp)); | |
--- | |
> if (len >= sizeof(tmp)) { | |
> /* should really not happen */ | |
> ret = -EOVERFLOW; | |
> goto out; | |
> } | |
1334c1397 | |
< | |
--- | |
> /* not unique, try again */ | |
1340c1403 | |
< | |
--- | |
> /* unique */ | |
1354c1417 | |
< | |
--- | |
> /* not unique, try again */ | |
1358c1421 | |
< | |
--- | |
> /* unique */ | |
1447,1452d1509 | |
< #ifdef MY_DEF_HERE | |
< if (ino == BTRFS_FIRST_FREE_OBJECTID) { | |
< return 1; | |
< } | |
< #endif | |
< | |
1467a1525,1527 | |
> /* | |
> * Helper function to lookup a dir item in a dir. | |
> */ | |
1493,1496d1552 | |
< if (key.type == BTRFS_ROOT_ITEM_KEY) { | |
< ret = -ENOENT; | |
< goto out; | |
< } | |
1505c1561,1566 | |
< static int get_first_ref(struct btrfs_root *root, u64 ino, | |
--- | |
> /* | |
> * Looks up the first btrfs_inode_ref of a given ino. It returns the parent dir, | |
> * generation of the parent dir and the name of the dir entry. | |
> */ | |
> static int get_first_ref(struct send_ctx *sctx, | |
> struct btrfs_root *root, u64 ino, | |
1536c1597 | |
< if (found_key.type == BTRFS_INODE_REF_KEY) { | |
--- | |
> if (key.type == BTRFS_INODE_REF_KEY) { | |
1558,1563c1619,1622 | |
< if (dir_gen) { | |
< ret = get_inode_info(root, parent_dir, NULL, dir_gen, NULL, | |
< NULL, NULL, NULL); | |
< if (ret < 0) | |
< goto out; | |
< } | |
--- | |
> ret = get_inode_info(root, parent_dir, NULL, dir_gen, NULL, NULL, | |
> NULL, NULL); | |
> if (ret < 0) | |
> goto out; | |
1572c1631,1632 | |
< static int is_first_ref(struct btrfs_root *root, | |
--- | |
> static int is_first_ref(struct send_ctx *sctx, | |
> struct btrfs_root *root, | |
1578a1639 | |
> u64 tmp_dir_gen; | |
1580c1641 | |
< tmp_name = fs_path_alloc(); | |
--- | |
> tmp_name = fs_path_alloc(sctx); | |
1584c1645 | |
< ret = get_first_ref(root, ino, &tmp_dir, NULL, tmp_name); | |
--- | |
> ret = get_first_ref(sctx, root, ino, &tmp_dir, &tmp_dir_gen, tmp_name); | |
1596c1657 | |
< fs_path_free(tmp_name); | |
--- | |
> fs_path_free(sctx, tmp_name); | |
1599a1661,1670 | |
> /* | |
> * Used by process_recorded_refs to determine if a new ref would overwrite an | |
> * already existing ref. In case it detects an overwrite, it returns the | |
> * inode/gen in who_ino/who_gen. | |
> * When an overwrite is detected, process_recorded_refs does proper orphanizing | |
> * to make sure later references to the overwritten inode are possible. | |
> * Orphanizing is however only required for the first ref of an inode. | |
> * process_recorded_refs does an additional is_first_ref check to see if | |
> * orphanizing is really required. | |
> */ | |
1605d1675 | |
< u64 gen; | |
1608,1610d1677 | |
< #ifdef MY_DEF_HERE | |
< struct waiting_dir_move *dm = NULL; | |
< #endif | |
1619,1635d1685 | |
< #ifdef MY_DEF_HERE | |
< if (sctx->parent_root && dir != BTRFS_FIRST_FREE_OBJECTID) { | |
< #else | |
< if (sctx->parent_root) { | |
< #endif | |
< ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL, | |
< NULL, NULL, NULL); | |
< if (ret < 0 && ret != -ENOENT) | |
< goto out; | |
< if (ret) { | |
< ret = 0; | |
< goto out; | |
< } | |
< if (gen != dir_gen) | |
< goto out; | |
< } | |
< | |
1645,1647c1695,1699 | |
< #ifdef MY_DEF_HERE | |
< if (other_inode > sctx->send_progress || ((dm = get_waiting_dir_move(sctx, other_inode)) != NULL)) { | |
< #else | |
--- | |
> /* | |
> * Check if the overwritten ref was already processed. If yes, the ref | |
> * was already unlinked/moved, so we can safely assume that we will not | |
> * overwrite anything at this point in time. | |
> */ | |
1649d1700 | |
< #endif | |
1654,1659d1704 | |
< #ifdef MY_DEF_HERE | |
< if (dm && dm->gen != *who_gen) { | |
< ret = 0; | |
< goto out; | |
< } | |
< #endif | |
1670a1716,1722 | |
> /* | |
> * Checks if the ref was overwritten by an already processed inode. This is | |
> * used by __get_cur_name_and_parent to find out if the ref was orphanized and | |
> * thus the orphan name needs be used. | |
> * process_recorded_refs also uses it to avoid unlinking of refs that were | |
> * overwritten. | |
> */ | |
1688,1702c1740 | |
< #ifdef MY_DEF_HERE | |
< if (dir != BTRFS_FIRST_FREE_OBJECTID) { | |
< ret = get_inode_info(sctx->send_root, dir, NULL, &gen, NULL, | |
< NULL, NULL, NULL); | |
< if (ret < 0 && ret != -ENOENT) | |
< goto out; | |
< if (ret) { | |
< ret = 0; | |
< goto out; | |
< } | |
< if (gen != dir_gen) | |
< goto out; | |
< } | |
< #endif | |
< | |
--- | |
> /* check if the ref was overwritten by another ref */ | |
1708c1746 | |
< | |
--- | |
> /* was never and will never be overwritten */ | |
1723,1725c1761,1762 | |
< if ((ow_inode < sctx->send_progress) || | |
< (ino != sctx->cur_ino && ow_inode == sctx->cur_ino && | |
< gen == sctx->cur_inode_gen)) | |
--- | |
> /* we know that it is or will be overwritten. check this now */ | |
> if (ow_inode < sctx->send_progress) | |
1733a1771,1775 | |
> /* | |
> * Same as did_overwrite_ref, but also checks if it is the first ref of an inode | |
> * that got overwritten. This is used by process_recorded_refs to determine | |
> * if it has to use the path as returned by get_cur_path or the orphan name. | |
> */ | |
1744c1786 | |
< name = fs_path_alloc(); | |
--- | |
> name = fs_path_alloc(sctx); | |
1748c1790 | |
< ret = get_first_ref(sctx->parent_root, ino, &dir, &dir_gen, name); | |
--- | |
> ret = get_first_ref(sctx, sctx->parent_root, ino, &dir, &dir_gen, name); | |
1756c1798 | |
< fs_path_free(name); | |
--- | |
> fs_path_free(sctx, name); | |
1759a1802,1807 | |
> /* | |
> * Insert a name cache entry. On 32bit kernels the radix tree index is 32bit, | |
> * so we need to do some special handling in case we have clashes. This function | |
> * takes care of this with the help of name_cache_entry::radix_list. | |
> * In case of error, nce is kfreed. | |
> */ | |
1797,1801c1845 | |
< if (!nce_head) { | |
< btrfs_err(sctx->send_root->fs_info, | |
< "name_cache_delete lookup failed ino %llu cache size %d, leaking memory", | |
< nce->ino, sctx->name_cache_size); | |
< } | |
--- | |
> BUG_ON(!nce_head); | |
1807c1851 | |
< if (nce_head && list_empty(nce_head)) { | |
--- | |
> if (list_empty(nce_head)) { | |
1829a1874,1877 | |
> /* | |
> * Removes the entry from the list and adds it back to the end. This marks the | |
> * entry as recently used so that name_cache_clean_unused does not remove it. | |
> */ | |
1835a1884,1886 | |
> /* | |
> * Remove some entries from the beginning of name_cache_list. | |
> */ | |
1862a1914,1921 | |
> /* | |
> * Used by get_cur_path for each ref up to the root. | |
> * Returns 0 if it succeeded. | |
> * Returns 1 if the inode is not existent or got overwritten. In that case, the | |
> * name is an orphan name. This instructs get_cur_path to stop iterating. If 1 | |
> * is returned, parent_ino/parent_gen are not guaranteed to be valid. | |
> * Returns <0 in case of error. | |
> */ | |
1870a1930 | |
> struct btrfs_path *path = NULL; | |
1872a1933,1937 | |
> /* | |
> * First check if we already did a call to this function with the same | |
> * ino/gen. If yes, check if the cache entry is still up-to-date. If yes | |
> * return the cached result. | |
> */ | |
1890a1956,1964 | |
> path = alloc_path_for_send(); | |
> if (!path) | |
> return -ENOMEM; | |
> | |
> /* | |
> * If the inode is not existent yet, add the orphan name and return 1. | |
> * This should only happen for the parent dir that we determine in | |
> * __record_new_ref | |
> */ | |
1902a1977,1980 | |
> /* | |
> * Depending on whether the inode was already processed or not, use | |
> * send_root or parent_root for ref lookup. | |
> */ | |
1904,1905c1982,1983 | |
< ret = get_first_ref(sctx->send_root, ino, | |
< parent_ino, parent_gen, dest); | |
--- | |
> ret = get_first_ref(sctx, sctx->send_root, ino, | |
> parent_ino, parent_gen, dest); | |
1907,1908c1985,1986 | |
< ret = get_first_ref(sctx->parent_root, ino, | |
< parent_ino, parent_gen, dest); | |
--- | |
> ret = get_first_ref(sctx, sctx->parent_root, ino, | |
> parent_ino, parent_gen, dest); | |
1911a1990,1993 | |
> /* | |
> * Check if the ref was overwritten by an inode's ref that was processed | |
> * earlier. If yes, treat as orphan and return 1. | |
> */ | |
1925c2007,2009 | |
< | |
--- | |
> /* | |
> * Store the result of the lookup in the name cache. | |
> */ | |
1950a2035 | |
> btrfs_free_path(path); | |
1953a2039,2063 | |
> /* | |
> * Magic happens here. This function returns the first ref to an inode as it | |
> * would look like while receiving the stream at this point in time. | |
> * We walk the path up to the root. For every inode in between, we check if it | |
> * was already processed/sent. If yes, we continue with the parent as found | |
> * in send_root. If not, we continue with the parent as found in parent_root. | |
> * If we encounter an inode that was deleted at this point in time, we use the | |
> * inodes "orphan" name instead of the real name and stop. Same with new inodes | |
> * that were not created yet and overwritten inodes/refs. | |
> * | |
> * When do we have have orphan inodes: | |
> * 1. When an inode is freshly created and thus no valid refs are available yet | |
> * 2. When a directory lost all it's refs (deleted) but still has dir items | |
> * inside which were not processed yet (pending for move/delete). If anyone | |
> * tried to get the path to the dir items, it would get a path inside that | |
> * orphan directory. | |
> * 3. When an inode is moved around or gets new links, it may overwrite the ref | |
> * of an unprocessed inode. If in that case the first ref would be | |
> * overwritten, the overwritten inode gets "orphanized". Later when we | |
> * process this overwritten inode, it is restored at a new place by moving | |
> * the orphan inode. | |
> * | |
> * sctx->send_progress tells this function at which point in time receiving | |
> * would be. | |
> */ | |
1963c2073 | |
< name = fs_path_alloc(); | |
--- | |
> name = fs_path_alloc(sctx); | |
1973,1976d2082 | |
< #ifdef MY_DEF_HERE | |
< struct waiting_dir_move *wdm; | |
< #endif | |
< | |
1979,2009c2085,2086 | |
< #ifdef MY_DEF_HERE | |
< if (is_waiting_for_rm(sctx, ino, gen)) { | |
< #else | |
< if (is_waiting_for_rm(sctx, ino)) { | |
< #endif | |
< ret = gen_unique_name(sctx, ino, gen, name); | |
< if (ret < 0) | |
< goto out; | |
< ret = fs_path_add_path(dest, name); | |
< break; | |
< } | |
< | |
< #ifdef MY_DEF_HERE | |
< wdm = get_waiting_dir_move(sctx, ino); | |
< if (wdm && wdm->orphanized) { | |
< ret = gen_unique_name(sctx, ino, gen, name); | |
< stop = 1; | |
< } else if (wdm) { | |
< #else | |
< if (is_waiting_for_move(sctx, ino)) { | |
< #endif | |
< ret = get_first_ref(sctx->parent_root, ino, | |
< &parent_inode, &parent_gen, name); | |
< } else { | |
< ret = __get_cur_name_and_parent(sctx, ino, gen, | |
< &parent_inode, | |
< &parent_gen, name); | |
< if (ret) | |
< stop = 1; | |
< } | |
< | |
--- | |
> ret = __get_cur_name_and_parent(sctx, ino, gen, | |
> &parent_inode, &parent_gen, name); | |
2011a2089,2090 | |
> if (ret) | |
> stop = 1; | |
2022c2101 | |
< fs_path_free(name); | |
--- | |
> fs_path_free(sctx, name); | |
2027a2107,2180 | |
> /* | |
> * Called for regular files when sending extents data. Opens a struct file | |
> * to read from the file. | |
> */ | |
> static int open_cur_inode_file(struct send_ctx *sctx) | |
> { | |
> int ret = 0; | |
> struct btrfs_key key; | |
> struct path path; | |
> struct inode *inode; | |
> struct dentry *dentry; | |
> struct file *filp; | |
> int new = 0; | |
> | |
> if (sctx->cur_inode_filp) | |
> goto out; | |
> | |
> key.objectid = sctx->cur_ino; | |
> key.type = BTRFS_INODE_ITEM_KEY; | |
> key.offset = 0; | |
> | |
> inode = btrfs_iget(sctx->send_root->fs_info->sb, &key, sctx->send_root, | |
> &new); | |
> if (IS_ERR(inode)) { | |
> ret = PTR_ERR(inode); | |
> goto out; | |
> } | |
> | |
> dentry = d_obtain_alias(inode); | |
> inode = NULL; | |
> if (IS_ERR(dentry)) { | |
> ret = PTR_ERR(dentry); | |
> goto out; | |
> } | |
> | |
> path.mnt = sctx->mnt; | |
> path.dentry = dentry; | |
> filp = dentry_open(&path, O_RDONLY | O_LARGEFILE, current_cred()); | |
> dput(dentry); | |
> dentry = NULL; | |
> if (IS_ERR(filp)) { | |
> ret = PTR_ERR(filp); | |
> goto out; | |
> } | |
> sctx->cur_inode_filp = filp; | |
> | |
> out: | |
> /* | |
> * no xxxput required here as every vfs op | |
> * does it by itself on failure | |
> */ | |
> return ret; | |
> } | |
> | |
> /* | |
> * Closes the struct file that was created in open_cur_inode_file | |
> */ | |
> static int close_cur_inode_file(struct send_ctx *sctx) | |
> { | |
> int ret = 0; | |
> | |
> if (!sctx->cur_inode_filp) | |
> goto out; | |
> | |
> ret = filp_close(sctx->cur_inode_filp, NULL); | |
> sctx->cur_inode_filp = NULL; | |
> | |
> out: | |
> return ret; | |
> } | |
> | |
> /* | |
> * Sends a BTRFS_SEND_C_SUBVOL command/item to userspace | |
> */ | |
2040c2193 | |
< path = btrfs_alloc_path(); | |
--- | |
> path = alloc_path_for_send(); | |
2086,2089d2238 | |
< #ifdef MY_DEF_HERE | |
< TLV_PUT_UUID(sctx, BTRFS_SEND_A_UUID, | |
< sctx->send_root->root_item.received_uuid); | |
< #else | |
2092d2240 | |
< #endif | |
2094,2097c2242 | |
< le64_to_cpu(sctx->send_root->root_item.ctransid)); | |
< #ifdef MY_DEF_HERE | |
< TLV_PUT_BTRFS_SUBVOL_TIMESPEC(sctx, BTRFS_SEND_A_OTIME, &sctx->send_root->root_item.otime); | |
< #endif | |
--- | |
> sctx->send_root->root_item.ctransid); | |
2099,2102d2243 | |
< #ifdef MY_DEF_HERE | |
< TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, | |
< sctx->parent_root->root_item.received_uuid); | |
< #else | |
2105d2245 | |
< #endif | |
2107c2247 | |
< le64_to_cpu(sctx->parent_root->root_item.ctransid)); | |
--- | |
> sctx->parent_root->root_item.ctransid); | |
2112,2126d2251 | |
< #ifdef MY_DEF_HERE | |
< if (ret < 0) { | |
< goto out; | |
< } | |
< if (!parent_root) { | |
< ret = begin_cmd(sctx, BTRFS_SEND_C_SUBVOL_FLAG); | |
< if (ret < 0) { | |
< goto out; | |
< } | |
< verbose_printk("btrfs: send_flag %u\n", sctx->subvol_flags); | |
< TLV_PUT_U32(sctx, BTRFS_SEND_A_FLAG, sctx->subvol_flags); | |
< ret = send_cmd(sctx); | |
< } | |
< #endif | |
< | |
2134,2153d2258 | |
< #ifdef MY_DEF_HERE | |
< static int write_calculate_size(struct send_ctx *sctx) | |
< { | |
< int ret = 0; | |
< struct timeval now; | |
< unsigned long val; | |
< | |
< do_gettimeofday(&now); | |
< | |
< val = ((now.tv_sec - sctx->write_timeval.tv_sec) * 1000); | |
< val += ((now.tv_usec - sctx->write_timeval.tv_usec) / 1000); | |
< if (val > 800) { | |
< snprintf(sctx->send_buf, sctx->send_max_size, "About:%llu\n", sctx->total_data_size); | |
< ret = write_buf(sctx->send_filp, sctx->send_buf, strlen(sctx->send_buf), &sctx->send_off); | |
< sctx->write_timeval = now; | |
< } | |
< return ret; | |
< } | |
< #endif | |
< | |
2159,2165d2263 | |
< #ifdef MY_DEF_HERE | |
< if (sctx->phase == SEND_PHASE_COMPUTE_DATA_SIZE) { | |
< sctx->total_data_size += sizeof(struct btrfs_cmd_header) + sizeof(struct fs_path); | |
< return write_calculate_size(sctx); | |
< } | |
< #endif | |
< | |
2168c2266 | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
2186c2284 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
2197c2295 | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
2215c2313 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
2226c2324 | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
2245c2343 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
2261c2359 | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
2296c2394,2395 | |
< | |
--- | |
> /* TODO Add otime support when the otime patches get into upstream */ | |
> | |
2301c2400 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
2305a2405,2409 | |
> /* | |
> * Sends a BTRFS_SEND_C_MKXXX or SYMLINK command to user space. We don't have | |
> * a valid path yet because we did not process the refs yet. So, the inode | |
> * is created as orphan. | |
> */ | |
2317c2421 | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
2321,2330c2425,2428 | |
< if (ino != sctx->cur_ino) { | |
< ret = get_inode_info(sctx->send_root, ino, NULL, &gen, &mode, | |
< NULL, NULL, &rdev); | |
< if (ret < 0) | |
< goto out; | |
< } else { | |
< gen = sctx->cur_inode_gen; | |
< mode = sctx->cur_inode_mode; | |
< rdev = sctx->cur_inode_rdev; | |
< } | |
--- | |
> ret = get_inode_info(sctx->send_root, ino, NULL, &gen, &mode, NULL, | |
> NULL, &rdev); | |
> if (ret < 0) | |
> goto out; | |
2364c2462 | |
< ret = read_symlink(sctx->send_root, ino, p); | |
--- | |
> ret = read_symlink(sctx, sctx->send_root, ino, p); | |
2377a2476 | |
> | |
2380c2479 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
2383a2483,2487 | |
> /* | |
> * We need some special handling for inodes that get processed before the parent | |
> * directory got created. See process_recorded_refs for details. | |
> * This function does the check if we already created the dir out of order. | |
> */ | |
2404,2407d2507 | |
< ret = btrfs_search_slot(NULL, sctx->send_root, &key, path, 0, 0); | |
< if (ret < 0) | |
< goto out; | |
< | |
2409,2419c2509,2516 | |
< eb = path->nodes[0]; | |
< slot = path->slots[0]; | |
< if (slot >= btrfs_header_nritems(eb)) { | |
< ret = btrfs_next_leaf(sctx->send_root, path); | |
< if (ret < 0) { | |
< goto out; | |
< } else if (ret > 0) { | |
< ret = 0; | |
< break; | |
< } | |
< continue; | |
--- | |
> ret = btrfs_search_slot_for_read(sctx->send_root, &key, path, | |
> 1, 0); | |
> if (ret < 0) | |
> goto out; | |
> if (!ret) { | |
> eb = path->nodes[0]; | |
> slot = path->slots[0]; | |
> btrfs_item_key_to_cpu(eb, &found_key, slot); | |
2421,2423c2518 | |
< | |
< btrfs_item_key_to_cpu(eb, &found_key, slot); | |
< if (found_key.objectid != key.objectid || | |
--- | |
> if (ret || found_key.objectid != key.objectid || | |
2432,2433c2527 | |
< if (di_key.type != BTRFS_ROOT_ITEM_KEY && | |
< di_key.objectid < sctx->send_progress) { | |
--- | |
> if (di_key.objectid < sctx->send_progress) { | |
2438c2532,2533 | |
< path->slots[0]++; | |
--- | |
> key.offset = found_key.offset + 1; | |
> btrfs_release_path(path); | |
2445a2541,2546 | |
> /* | |
> * Only creates the inode if it is: | |
> * 1. Not a directory | |
> * 2. Or a directory which was not created already due to out of order | |
> * directories. See did_create_dir and process_recorded_refs for details. | |
> */ | |
2479c2580,2585 | |
< static int __record_ref(struct list_head *head, u64 dir, | |
--- | |
> /* | |
> * We need to process new refs before deleted refs, but compare_tree gives us | |
> * everything mixed. So we first record all refs and later process them. | |
> * This function is a helper to record one ref. | |
> */ | |
> static int record_ref(struct list_head *head, u64 dir, | |
2482a2589 | |
> char *tmp; | |
2492,2495c2599,2602 | |
< ref->name = (char *)kbasename(ref->full_path->start); | |
< ref->name_len = ref->full_path->end - ref->name; | |
< ref->dir_path = ref->full_path->start; | |
< if (ref->name == ref->full_path->start) | |
--- | |
> tmp = strrchr(ref->full_path->start, '/'); | |
> if (!tmp) { | |
> ref->name_len = ref->full_path->end - ref->full_path->start; | |
> ref->name = ref->full_path->start; | |
2497c2604,2609 | |
< else | |
--- | |
> ref->dir_path = ref->full_path->start; | |
> } else { | |
> tmp++; | |
> ref->name_len = ref->full_path->end - tmp; | |
> ref->name = tmp; | |
> ref->dir_path = ref->full_path->start; | |
2499a2612 | |
> } | |
2505,2521c2618 | |
< static int dup_ref(struct recorded_ref *ref, struct list_head *list) | |
< { | |
< struct recorded_ref *new; | |
< | |
< new = kmalloc(sizeof(*ref), GFP_NOFS); | |
< if (!new) | |
< return -ENOMEM; | |
< | |
< new->dir = ref->dir; | |
< new->dir_gen = ref->dir_gen; | |
< new->full_path = NULL; | |
< INIT_LIST_HEAD(&new->list); | |
< list_add_tail(&new->list, list); | |
< return 0; | |
< } | |
< | |
< static void __free_recorded_refs(struct list_head *head) | |
--- | |
> static void __free_recorded_refs(struct send_ctx *sctx, struct list_head *head) | |
2527c2624 | |
< fs_path_free(cur->full_path); | |
--- | |
> fs_path_free(sctx, cur->full_path); | |
2535,2536c2632,2633 | |
< __free_recorded_refs(&sctx->new_refs); | |
< __free_recorded_refs(&sctx->deleted_refs); | |
--- | |
> __free_recorded_refs(sctx, &sctx->new_refs); | |
> __free_recorded_refs(sctx, &sctx->deleted_refs); | |
2538a2636,2640 | |
> /* | |
> * Renames/moves a file/dir to its orphan name. Used when the first | |
> * ref of an unprocessed inode gets overwritten and for all non empty | |
> * directories. | |
> */ | |
2545c2647 | |
< orphan = fs_path_alloc(); | |
--- | |
> orphan = fs_path_alloc(sctx); | |
2556c2658 | |
< fs_path_free(orphan); | |
--- | |
> fs_path_free(sctx, orphan); | |
2560,2648c2662,2667 | |
< static struct orphan_dir_info * | |
< add_orphan_dir_info(struct send_ctx *sctx, u64 dir_ino) | |
< { | |
< struct rb_node **p = &sctx->orphan_dirs.rb_node; | |
< struct rb_node *parent = NULL; | |
< struct orphan_dir_info *entry, *odi; | |
< | |
< #ifdef MY_DEF_HERE | |
< #else | |
< odi = kmalloc(sizeof(*odi), GFP_NOFS); | |
< if (!odi) | |
< return ERR_PTR(-ENOMEM); | |
< odi->ino = dir_ino; | |
< odi->gen = 0; | |
< #endif | |
< | |
< while (*p) { | |
< parent = *p; | |
< entry = rb_entry(parent, struct orphan_dir_info, node); | |
< if (dir_ino < entry->ino) { | |
< p = &(*p)->rb_left; | |
< } else if (dir_ino > entry->ino) { | |
< p = &(*p)->rb_right; | |
< } else { | |
< #ifdef MY_DEF_HERE | |
< #else | |
< kfree(odi); | |
< #endif | |
< return entry; | |
< } | |
< } | |
< | |
< #ifdef MY_DEF_HERE | |
< odi = kmalloc(sizeof(*odi), GFP_NOFS); | |
< if (!odi) | |
< return ERR_PTR(-ENOMEM); | |
< odi->ino = dir_ino; | |
< odi->gen = 0; | |
< #endif | |
< | |
< rb_link_node(&odi->node, parent, p); | |
< rb_insert_color(&odi->node, &sctx->orphan_dirs); | |
< return odi; | |
< } | |
< | |
< static struct orphan_dir_info * | |
< get_orphan_dir_info(struct send_ctx *sctx, u64 dir_ino) | |
< { | |
< struct rb_node *n = sctx->orphan_dirs.rb_node; | |
< struct orphan_dir_info *entry; | |
< | |
< while (n) { | |
< entry = rb_entry(n, struct orphan_dir_info, node); | |
< if (dir_ino < entry->ino) | |
< n = n->rb_left; | |
< else if (dir_ino > entry->ino) | |
< n = n->rb_right; | |
< else | |
< return entry; | |
< } | |
< return NULL; | |
< } | |
< | |
< #ifdef MY_DEF_HERE | |
< static int is_waiting_for_rm(struct send_ctx *sctx, u64 dir_ino, u64 dir_gen) | |
< #else | |
< static int is_waiting_for_rm(struct send_ctx *sctx, u64 dir_ino) | |
< #endif | |
< { | |
< struct orphan_dir_info *odi = get_orphan_dir_info(sctx, dir_ino); | |
< | |
< #ifdef MY_DEF_HERE | |
< return (odi != NULL && odi->gen == dir_gen); | |
< #else | |
< return odi != NULL; | |
< #endif | |
< } | |
< | |
< static void free_orphan_dir_info(struct send_ctx *sctx, | |
< struct orphan_dir_info *odi) | |
< { | |
< if (!odi) | |
< return; | |
< rb_erase(&odi->node, &sctx->orphan_dirs); | |
< kfree(odi); | |
< } | |
< | |
< static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 dir_gen, | |
< u64 send_progress) | |
--- | |
> /* | |
> * Returns 1 if a directory can be removed at this point in time. | |
> * We check this by iterating all dir items and checking if the inode behind | |
> * the dir item was already processed. | |
> */ | |
> static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 send_progress) | |
2657,2659d2675 | |
< #ifdef MY_DEF_HERE | |
< u64 loc_gen; | |
< #endif | |
2660a2677,2679 | |
> /* | |
> * Don't try to rmdir the top/root subvolume dir. | |
> */ | |
2671,2673d2689 | |
< ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | |
< if (ret < 0) | |
< goto out; | |
2676,2684c2692,2697 | |
< struct waiting_dir_move *dm; | |
< | |
< if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { | |
< ret = btrfs_next_leaf(root, path); | |
< if (ret < 0) | |
< goto out; | |
< else if (ret > 0) | |
< break; | |
< continue; | |
--- | |
> ret = btrfs_search_slot_for_read(root, &key, path, 1, 0); | |
> if (ret < 0) | |
> goto out; | |
> if (!ret) { | |
> btrfs_item_key_to_cpu(path->nodes[0], &found_key, | |
> path->slots[0]); | |
2686,2689c2699,2700 | |
< btrfs_item_key_to_cpu(path->nodes[0], &found_key, | |
< path->slots[0]); | |
< if (found_key.objectid != key.objectid || | |
< found_key.type != key.type) | |
--- | |
> if (ret || found_key.objectid != key.objectid || | |
> found_key.type != key.type) { | |
2690a2702 | |
> } | |
2696,2721d2707 | |
< #ifdef MY_DEF_HERE | |
< ret = get_inode_info(root, loc.objectid, NULL, &loc_gen, NULL, | |
< NULL, NULL, NULL); | |
< if (ret) | |
< goto out; | |
< #endif | |
< | |
< dm = get_waiting_dir_move(sctx, loc.objectid); | |
< #ifdef MY_DEF_HERE | |
< if (dm && dm->gen == loc_gen) { | |
< #else | |
< if (dm) { | |
< #endif | |
< struct orphan_dir_info *odi; | |
< | |
< odi = add_orphan_dir_info(sctx, dir); | |
< if (IS_ERR(odi)) { | |
< ret = PTR_ERR(odi); | |
< goto out; | |
< } | |
< odi->gen = dir_gen; | |
< dm->rmdir_ino = dir; | |
< ret = 0; | |
< goto out; | |
< } | |
< | |
2723,2729d2708 | |
< #ifdef MY_DEF_HERE | |
< struct orphan_dir_info *odi; | |
< | |
< odi = get_orphan_dir_info(sctx, dir); | |
< if (odi) | |
< free_orphan_dir_info(sctx, odi); | |
< #endif | |
2734c2713,2714 | |
< path->slots[0]++; | |
--- | |
> btrfs_release_path(path); | |
> key.offset = found_key.offset + 1; | |
2744,3372c2724,2727 | |
< static int is_waiting_for_move(struct send_ctx *sctx, u64 ino) | |
< { | |
< struct waiting_dir_move *entry = get_waiting_dir_move(sctx, ino); | |
< | |
< return entry != NULL; | |
< } | |
< | |
< #ifdef MY_DEF_HERE | |
< static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino, u64 gen, bool orphanized) | |
< #else | |
< static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino) | |
< #endif | |
< { | |
< struct rb_node **p = &sctx->waiting_dir_moves.rb_node; | |
< struct rb_node *parent = NULL; | |
< struct waiting_dir_move *entry, *dm; | |
< | |
< dm = kmalloc(sizeof(*dm), GFP_NOFS); | |
< if (!dm) | |
< return -ENOMEM; | |
< dm->ino = ino; | |
< dm->rmdir_ino = 0; | |
< #ifdef MY_DEF_HERE | |
< dm->orphanized = orphanized; | |
< dm->gen = gen; | |
< #endif | |
< | |
< while (*p) { | |
< parent = *p; | |
< entry = rb_entry(parent, struct waiting_dir_move, node); | |
< if (ino < entry->ino) { | |
< p = &(*p)->rb_left; | |
< } else if (ino > entry->ino) { | |
< p = &(*p)->rb_right; | |
< } else { | |
< kfree(dm); | |
< return -EEXIST; | |
< } | |
< } | |
< | |
< rb_link_node(&dm->node, parent, p); | |
< rb_insert_color(&dm->node, &sctx->waiting_dir_moves); | |
< return 0; | |
< } | |
< | |
< static struct waiting_dir_move * | |
< get_waiting_dir_move(struct send_ctx *sctx, u64 ino) | |
< { | |
< struct rb_node *n = sctx->waiting_dir_moves.rb_node; | |
< struct waiting_dir_move *entry; | |
< | |
< while (n) { | |
< entry = rb_entry(n, struct waiting_dir_move, node); | |
< if (ino < entry->ino) | |
< n = n->rb_left; | |
< else if (ino > entry->ino) | |
< n = n->rb_right; | |
< else | |
< return entry; | |
< } | |
< return NULL; | |
< } | |
< | |
< static void free_waiting_dir_move(struct send_ctx *sctx, | |
< struct waiting_dir_move *dm) | |
< { | |
< if (!dm) | |
< return; | |
< rb_erase(&dm->node, &sctx->waiting_dir_moves); | |
< kfree(dm); | |
< } | |
< | |
< static int add_pending_dir_move(struct send_ctx *sctx, | |
< u64 ino, | |
< u64 ino_gen, | |
< u64 parent_ino, | |
< struct list_head *new_refs, | |
< struct list_head *deleted_refs, | |
< const bool is_orphan) | |
< { | |
< struct rb_node **p = &sctx->pending_dir_moves.rb_node; | |
< struct rb_node *parent = NULL; | |
< struct pending_dir_move *entry = NULL, *pm; | |
< struct recorded_ref *cur; | |
< int exists = 0; | |
< int ret; | |
< | |
< pm = kmalloc(sizeof(*pm), GFP_NOFS); | |
< if (!pm) | |
< return -ENOMEM; | |
< pm->parent_ino = parent_ino; | |
< pm->ino = ino; | |
< pm->gen = ino_gen; | |
< #ifdef MY_DEF_HERE | |
< #else | |
< pm->is_orphan = is_orphan; | |
< #endif | |
< INIT_LIST_HEAD(&pm->list); | |
< INIT_LIST_HEAD(&pm->update_refs); | |
< RB_CLEAR_NODE(&pm->node); | |
< | |
< while (*p) { | |
< parent = *p; | |
< entry = rb_entry(parent, struct pending_dir_move, node); | |
< if (parent_ino < entry->parent_ino) { | |
< p = &(*p)->rb_left; | |
< } else if (parent_ino > entry->parent_ino) { | |
< p = &(*p)->rb_right; | |
< } else { | |
< exists = 1; | |
< break; | |
< } | |
< } | |
< | |
< list_for_each_entry(cur, deleted_refs, list) { | |
< ret = dup_ref(cur, &pm->update_refs); | |
< if (ret < 0) | |
< goto out; | |
< } | |
< list_for_each_entry(cur, new_refs, list) { | |
< ret = dup_ref(cur, &pm->update_refs); | |
< if (ret < 0) | |
< goto out; | |
< } | |
< | |
< #ifdef MY_DEF_HERE | |
< ret = add_waiting_dir_move(sctx, pm->ino, pm->gen, is_orphan); | |
< #else | |
< ret = add_waiting_dir_move(sctx, pm->ino); | |
< #endif | |
< if (ret) | |
< goto out; | |
< | |
< if (exists) { | |
< list_add_tail(&pm->list, &entry->list); | |
< } else { | |
< rb_link_node(&pm->node, parent, p); | |
< rb_insert_color(&pm->node, &sctx->pending_dir_moves); | |
< } | |
< ret = 0; | |
< out: | |
< if (ret) { | |
< __free_recorded_refs(&pm->update_refs); | |
< kfree(pm); | |
< } | |
< return ret; | |
< } | |
< | |
< static struct pending_dir_move *get_pending_dir_moves(struct send_ctx *sctx, | |
< u64 parent_ino) | |
< { | |
< struct rb_node *n = sctx->pending_dir_moves.rb_node; | |
< struct pending_dir_move *entry; | |
< | |
< while (n) { | |
< entry = rb_entry(n, struct pending_dir_move, node); | |
< if (parent_ino < entry->parent_ino) | |
< n = n->rb_left; | |
< else if (parent_ino > entry->parent_ino) | |
< n = n->rb_right; | |
< else | |
< return entry; | |
< } | |
< return NULL; | |
< } | |
< | |
< #ifdef MY_DEF_HERE | |
< static int path_loop(struct send_ctx *sctx, struct fs_path *name, | |
< u64 ino, u64 gen, u64 *ancestor_ino) | |
< { | |
< int ret = 0; | |
< u64 parent_inode = 0; | |
< u64 parent_gen = 0; | |
< u64 start_ino = ino; | |
< | |
< *ancestor_ino = 0; | |
< while (ino != BTRFS_FIRST_FREE_OBJECTID) { | |
< struct waiting_dir_move *wdm; | |
< fs_path_reset(name); | |
< | |
< if (is_waiting_for_rm(sctx, ino, gen)) | |
< break; | |
< | |
< wdm = get_waiting_dir_move(sctx, ino); | |
< if (wdm) { | |
< if (*ancestor_ino == 0) | |
< *ancestor_ino = ino; | |
< if (wdm->orphanized) { | |
< ret = gen_unique_name(sctx, ino, gen, name); | |
< break; | |
< } else { | |
< ret = get_first_ref(sctx->parent_root, ino, | |
< &parent_inode, &parent_gen, name); | |
< } | |
< } else { | |
< ret = __get_cur_name_and_parent(sctx, ino, gen, | |
< &parent_inode, | |
< &parent_gen, name); | |
< if (ret > 0) { | |
< ret = 0; | |
< break; | |
< } | |
< } | |
< if (ret < 0) | |
< break; | |
< if (parent_inode == start_ino) { | |
< ret = 1; | |
< if (*ancestor_ino == 0) | |
< *ancestor_ino = ino; | |
< break; | |
< } | |
< ino = parent_inode; | |
< gen = parent_gen; | |
< } | |
< return ret; | |
< } | |
< #endif | |
< | |
< static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) | |
< { | |
< struct fs_path *from_path = NULL; | |
< struct fs_path *to_path = NULL; | |
< struct fs_path *name = NULL; | |
< u64 orig_progress = sctx->send_progress; | |
< struct recorded_ref *cur; | |
< u64 parent_ino, parent_gen; | |
< struct waiting_dir_move *dm = NULL; | |
< u64 rmdir_ino = 0; | |
< int ret; | |
< #ifdef MY_DEF_HERE | |
< bool is_orphan; | |
< u64 ancestor = 0; | |
< #endif | |
< | |
< name = fs_path_alloc(); | |
< from_path = fs_path_alloc(); | |
< if (!name || !from_path) { | |
< ret = -ENOMEM; | |
< goto out; | |
< } | |
< | |
< dm = get_waiting_dir_move(sctx, pm->ino); | |
< ASSERT(dm); | |
< rmdir_ino = dm->rmdir_ino; | |
< #ifdef MY_DEF_HERE | |
< is_orphan = dm->orphanized; | |
< #endif | |
< free_waiting_dir_move(sctx, dm); | |
< | |
< #ifdef MY_DEF_HERE | |
< if (is_orphan) { | |
< #else | |
< if (pm->is_orphan) { | |
< #endif | |
< ret = gen_unique_name(sctx, pm->ino, | |
< pm->gen, from_path); | |
< } else { | |
< ret = get_first_ref(sctx->parent_root, pm->ino, | |
< &parent_ino, &parent_gen, name); | |
< if (ret < 0) | |
< goto out; | |
< ret = get_cur_path(sctx, parent_ino, parent_gen, | |
< from_path); | |
< if (ret < 0) | |
< goto out; | |
< ret = fs_path_add_path(from_path, name); | |
< } | |
< if (ret < 0) | |
< goto out; | |
< | |
< sctx->send_progress = sctx->cur_ino + 1; | |
< #ifdef MY_DEF_HERE | |
< ret = path_loop(sctx, name, pm->ino, pm->gen, &ancestor); | |
< if (ret) { | |
< LIST_HEAD(deleted_refs); | |
< ASSERT(ancestor > BTRFS_FIRST_FREE_OBJECTID); | |
< ret = add_pending_dir_move(sctx, pm->ino, pm->gen, ancestor, | |
< &pm->update_refs, &deleted_refs, | |
< is_orphan); | |
< if (ret < 0) | |
< goto out; | |
< if (rmdir_ino) { | |
< dm = get_waiting_dir_move(sctx, pm->ino); | |
< ASSERT(dm); | |
< dm->rmdir_ino = rmdir_ino; | |
< } | |
< goto out; | |
< } | |
< #endif | |
< fs_path_reset(name); | |
< to_path = name; | |
< name = NULL; | |
< ret = get_cur_path(sctx, pm->ino, pm->gen, to_path); | |
< if (ret < 0) | |
< goto out; | |
< | |
< ret = send_rename(sctx, from_path, to_path); | |
< if (ret < 0) | |
< goto out; | |
< | |
< if (rmdir_ino) { | |
< struct orphan_dir_info *odi; | |
< | |
< odi = get_orphan_dir_info(sctx, rmdir_ino); | |
< if (!odi) { | |
< | |
< goto finish; | |
< } | |
< #ifdef MY_DEF_HERE | |
< ret = can_rmdir(sctx, rmdir_ino, odi->gen, sctx->cur_ino); | |
< #else | |
< ret = can_rmdir(sctx, rmdir_ino, odi->gen, sctx->cur_ino + 1); | |
< #endif | |
< if (ret < 0) | |
< goto out; | |
< if (!ret) | |
< goto finish; | |
< | |
< name = fs_path_alloc(); | |
< if (!name) { | |
< ret = -ENOMEM; | |
< goto out; | |
< } | |
< ret = get_cur_path(sctx, rmdir_ino, odi->gen, name); | |
< if (ret < 0) | |
< goto out; | |
< ret = send_rmdir(sctx, name); | |
< if (ret < 0) | |
< goto out; | |
< free_orphan_dir_info(sctx, odi); | |
< } | |
< | |
< finish: | |
< ret = send_utimes(sctx, pm->ino, pm->gen); | |
< if (ret < 0) | |
< goto out; | |
< | |
< list_for_each_entry(cur, &pm->update_refs, list) { | |
< #ifdef MY_DEF_HERE | |
< | |
< u64 gen; | |
< ret = get_inode_info(sctx->send_root, cur->dir, NULL, | |
< &gen , NULL, NULL, NULL, NULL); | |
< if (ret < 0 && ret != -ENOENT) { | |
< goto out; | |
< } | |
< | |
< if (ret == -ENOENT || gen != cur->dir_gen) { | |
< ret = 0; | |
< continue; | |
< } | |
< #else | |
< if (cur->dir == rmdir_ino) | |
< continue; | |
< #endif | |
< | |
< ret = send_utimes(sctx, cur->dir, cur->dir_gen); | |
< if (ret < 0) | |
< goto out; | |
< } | |
< | |
< out: | |
< fs_path_free(name); | |
< fs_path_free(from_path); | |
< fs_path_free(to_path); | |
< sctx->send_progress = orig_progress; | |
< | |
< return ret; | |
< } | |
< | |
< static void free_pending_move(struct send_ctx *sctx, struct pending_dir_move *m) | |
< { | |
< if (!list_empty(&m->list)) | |
< list_del(&m->list); | |
< if (!RB_EMPTY_NODE(&m->node)) | |
< rb_erase(&m->node, &sctx->pending_dir_moves); | |
< __free_recorded_refs(&m->update_refs); | |
< kfree(m); | |
< } | |
< | |
< static void tail_append_pending_moves(struct pending_dir_move *moves, | |
< struct list_head *stack) | |
< { | |
< if (list_empty(&moves->list)) { | |
< list_add_tail(&moves->list, stack); | |
< } else { | |
< LIST_HEAD(list); | |
< list_splice_init(&moves->list, &list); | |
< list_add_tail(&moves->list, stack); | |
< list_splice_tail(&list, stack); | |
< } | |
< } | |
< | |
< static int apply_children_dir_moves(struct send_ctx *sctx) | |
< { | |
< struct pending_dir_move *pm; | |
< struct list_head stack; | |
< u64 parent_ino = sctx->cur_ino; | |
< int ret = 0; | |
< | |
< pm = get_pending_dir_moves(sctx, parent_ino); | |
< if (!pm) | |
< return 0; | |
< | |
< INIT_LIST_HEAD(&stack); | |
< tail_append_pending_moves(pm, &stack); | |
< | |
< while (!list_empty(&stack)) { | |
< pm = list_first_entry(&stack, struct pending_dir_move, list); | |
< parent_ino = pm->ino; | |
< ret = apply_dir_move(sctx, pm); | |
< free_pending_move(sctx, pm); | |
< if (ret) | |
< goto out; | |
< pm = get_pending_dir_moves(sctx, parent_ino); | |
< if (pm) | |
< tail_append_pending_moves(pm, &stack); | |
< } | |
< return 0; | |
< | |
< out: | |
< while (!list_empty(&stack)) { | |
< pm = list_first_entry(&stack, struct pending_dir_move, list); | |
< free_pending_move(sctx, pm); | |
< } | |
< return ret; | |
< } | |
< | |
< static int wait_for_dest_dir_move(struct send_ctx *sctx, | |
< struct recorded_ref *parent_ref, | |
< const bool is_orphan) | |
< { | |
< struct btrfs_path *path; | |
< struct btrfs_key key; | |
< struct btrfs_key di_key; | |
< struct btrfs_dir_item *di; | |
< u64 left_gen; | |
< u64 right_gen; | |
< int ret = 0; | |
< #ifdef MY_DEF_HERE | |
< struct waiting_dir_move *wdm; | |
< #endif | |
< | |
< if (RB_EMPTY_ROOT(&sctx->waiting_dir_moves)) | |
< return 0; | |
< | |
< path = alloc_path_for_send(); | |
< if (!path) | |
< return -ENOMEM; | |
< | |
< key.objectid = parent_ref->dir; | |
< key.type = BTRFS_DIR_ITEM_KEY; | |
< key.offset = btrfs_name_hash(parent_ref->name, parent_ref->name_len); | |
< | |
< ret = btrfs_search_slot(NULL, sctx->parent_root, &key, path, 0, 0); | |
< if (ret < 0) { | |
< goto out; | |
< } else if (ret > 0) { | |
< ret = 0; | |
< goto out; | |
< } | |
< | |
< di = btrfs_match_dir_item_name(sctx->parent_root, path, | |
< parent_ref->name, parent_ref->name_len); | |
< if (!di) { | |
< ret = 0; | |
< goto out; | |
< } | |
< | |
< btrfs_dir_item_key_to_cpu(path->nodes[0], di, &di_key); | |
< if (di_key.type != BTRFS_INODE_ITEM_KEY) { | |
< ret = 0; | |
< goto out; | |
< } | |
< | |
< ret = get_inode_info(sctx->parent_root, di_key.objectid, NULL, | |
< &left_gen, NULL, NULL, NULL, NULL); | |
< if (ret < 0) | |
< goto out; | |
< ret = get_inode_info(sctx->send_root, di_key.objectid, NULL, | |
< &right_gen, NULL, NULL, NULL, NULL); | |
< if (ret < 0) { | |
< if (ret == -ENOENT) | |
< ret = 0; | |
< goto out; | |
< } | |
< | |
< if (right_gen != left_gen) { | |
< ret = 0; | |
< goto out; | |
< } | |
< | |
< #ifdef MY_DEF_HERE | |
< wdm = get_waiting_dir_move(sctx, di_key.objectid); | |
< if (wdm && !wdm->orphanized) { | |
< #else | |
< if (is_waiting_for_move(sctx, di_key.objectid)) { | |
< #endif | |
< ret = add_pending_dir_move(sctx, | |
< sctx->cur_ino, | |
< sctx->cur_inode_gen, | |
< di_key.objectid, | |
< &sctx->new_refs, | |
< &sctx->deleted_refs, | |
< is_orphan); | |
< if (!ret) | |
< ret = 1; | |
< } | |
< out: | |
< btrfs_free_path(path); | |
< return ret; | |
< } | |
< | |
< #ifdef MY_DEF_HERE | |
< | |
< static int is_ancestor(struct btrfs_root *root, | |
< const u64 ino1, | |
< const u64 ino1_gen, | |
< const u64 ino2, | |
< struct fs_path *fs_path) | |
< { | |
< u64 ino = ino2; | |
< | |
< while (ino > BTRFS_FIRST_FREE_OBJECTID) { | |
< int ret; | |
< u64 parent; | |
< u64 parent_gen; | |
< | |
< fs_path_reset(fs_path); | |
< ret = get_first_ref(root, ino, &parent, &parent_gen, fs_path); | |
< if (ret < 0) { | |
< if (ret == -ENOENT && ino == ino2) | |
< ret = 0; | |
< return ret; | |
< } | |
< if (parent == ino1) | |
< return parent_gen == ino1_gen ? 1 : 0; | |
< ino = parent; | |
< } | |
< return 0; | |
< } | |
< #endif | |
< | |
< static int wait_for_parent_move(struct send_ctx *sctx, | |
< #ifdef MY_DEF_HERE | |
< struct recorded_ref *parent_ref, | |
< const bool is_orphan) | |
< #else | |
< struct recorded_ref *parent_ref) | |
< #endif | |
< { | |
< int ret = 0; | |
< u64 ino = parent_ref->dir; | |
< u64 parent_ino_before, parent_ino_after; | |
< struct fs_path *path_before = NULL; | |
< struct fs_path *path_after = NULL; | |
< int len1, len2; | |
< | |
< path_after = fs_path_alloc(); | |
< path_before = fs_path_alloc(); | |
< if (!path_after || !path_before) { | |
< ret = -ENOMEM; | |
< goto out; | |
< } | |
< | |
< while (ino > BTRFS_FIRST_FREE_OBJECTID) { | |
< if (is_waiting_for_move(sctx, ino)) { | |
< #ifdef MY_DEF_HERE | |
< | |
< ret = is_ancestor(sctx->parent_root, | |
< sctx->cur_ino, sctx->cur_inode_gen, | |
< ino, path_before); | |
< #else | |
< ret = 1; | |
< #endif | |
< break; | |
< } | |
< | |
< fs_path_reset(path_before); | |
< fs_path_reset(path_after); | |
< | |
< ret = get_first_ref(sctx->send_root, ino, &parent_ino_after, | |
< NULL, path_after); | |
< if (ret < 0) | |
< goto out; | |
< ret = get_first_ref(sctx->parent_root, ino, &parent_ino_before, | |
< NULL, path_before); | |
< if (ret < 0 && ret != -ENOENT) { | |
< goto out; | |
< } else if (ret == -ENOENT) { | |
< ret = 0; | |
< break; | |
< } | |
< | |
< len1 = fs_path_len(path_before); | |
< len2 = fs_path_len(path_after); | |
< if (ino > sctx->cur_ino && | |
< (parent_ino_before != parent_ino_after || len1 != len2 || | |
< memcmp(path_before->start, path_after->start, len1))) { | |
< ret = 1; | |
< break; | |
< } | |
< ino = parent_ino_after; | |
< } | |
< | |
< out: | |
< fs_path_free(path_before); | |
< fs_path_free(path_after); | |
< | |
< if (ret == 1) { | |
< ret = add_pending_dir_move(sctx, | |
< sctx->cur_ino, | |
< sctx->cur_inode_gen, | |
< ino, | |
< &sctx->new_refs, | |
< &sctx->deleted_refs, | |
< #ifdef MY_DEF_HERE | |
< is_orphan); | |
< #else | |
< false); | |
< #endif | |
< if (!ret) | |
< ret = 1; | |
< } | |
< | |
< return ret; | |
< } | |
< | |
< static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) | |
--- | |
> /* | |
> * This does all the move/link/unlink/rmdir magic. | |
> */ | |
> static int process_recorded_refs(struct send_ctx *sctx) | |
3377c2732,2734 | |
< struct list_head check_dirs; | |
--- | |
> struct ulist *check_dirs = NULL; | |
> struct ulist_iterator uit; | |
> struct ulist_node *un; | |
3383,3391d2739 | |
< u64 last_dir_ino_rm = 0; | |
< bool can_rename = true; | |
< | |
< #ifdef MY_DEF_HERE | |
< if (sctx->phase == SEND_PHASE_COMPUTE_DATA_SIZE) { | |
< sctx->total_data_size += sizeof(struct btrfs_cmd_header) + sizeof(struct fs_path); | |
< return write_calculate_size(sctx); | |
< } | |
< #endif | |
3394a2743,2746 | |
> /* | |
> * This should never happen as the root dir always has the same ref | |
> * which is always '..' | |
> */ | |
3396d2747 | |
< INIT_LIST_HEAD(&check_dirs); | |
3398c2749 | |
< valid_path = fs_path_alloc(); | |
--- | |
> valid_path = fs_path_alloc(sctx); | |
3403a2755,2771 | |
> check_dirs = ulist_alloc(GFP_NOFS); | |
> if (!check_dirs) { | |
> ret = -ENOMEM; | |
> goto out; | |
> } | |
> | |
> /* | |
> * First, check if the first ref of the current inode was overwritten | |
> * before. If yes, we know that the current inode was already orphanized | |
> * and thus use the orphan name. If not, we can use get_cur_path to | |
> * get the path of the first ref as it would like while receiving at | |
> * this point in time. | |
> * New inodes are always orphan at the beginning, so force to use the | |
> * orphan name in this case. | |
> * The first ref is stored in valid_path and will be updated if it | |
> * gets moved around. | |
> */ | |
3426c2794,2800 | |
< | |
--- | |
> /* | |
> * We may have refs where the parent directory does not exist | |
> * yet. This happens if the parent directories inum is higher | |
> * the the current inum. To handle this case, we create the | |
> * parent directory out of order. But we need to check if this | |
> * did already happen before due to other refs in the same dir. | |
> */ | |
3432c2806,2809 | |
< | |
--- | |
> /* | |
> * First check if any of the current inodes refs did | |
> * already create the dir. | |
> */ | |
3441a2819,2822 | |
> /* | |
> * If that did not happen, check if a previous inode | |
> * did already create the dir. | |
> */ | |
3452a2834,2839 | |
> /* | |
> * Check if this new ref would overwrite the first ref of | |
> * another unprocessed inode. If yes, orphanize the | |
> * overwritten inode. If we find an overwritten ref that is | |
> * not the first ref, simply unlink it. | |
> */ | |
3459,3461c2846,2848 | |
< ret = is_first_ref(sctx->parent_root, | |
< ow_inode, cur->dir, cur->name, | |
< cur->name_len); | |
--- | |
> ret = is_first_ref(sctx, sctx->parent_root, | |
> ow_inode, cur->dir, cur->name, | |
> cur->name_len); | |
3465,3469d2851 | |
< struct name_cache_entry *nce; | |
< #ifdef MY_DEF_HERE | |
< struct waiting_dir_move *wdm; | |
< #endif | |
< | |
3474,3496d2855 | |
< | |
< #ifdef MY_DEF_HERE | |
< | |
< if (is_waiting_for_move(sctx, ow_inode)) { | |
< wdm = get_waiting_dir_move(sctx, ow_inode); | |
< ASSERT(wdm); | |
< wdm->orphanized = true; | |
< } | |
< #endif | |
< | |
< nce = name_cache_search(sctx, ow_inode, ow_gen); | |
< if (nce) { | |
< name_cache_delete(sctx, nce); | |
< kfree(nce); | |
< } | |
< | |
< #ifdef MY_DEF_HERE | |
< | |
< fs_path_reset(valid_path); | |
< ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, valid_path); | |
< if (ret < 0) | |
< goto out; | |
< #endif | |
3504,3559c2863,2868 | |
< if (S_ISDIR(sctx->cur_inode_mode) && sctx->parent_root) { | |
< ret = wait_for_dest_dir_move(sctx, cur, is_orphan); | |
< if (ret < 0) | |
< goto out; | |
< if (ret == 1) { | |
< can_rename = false; | |
< *pending_move = 1; | |
< } | |
< } | |
< | |
< #ifdef MY_DEF_HERE | |
< if (S_ISDIR(sctx->cur_inode_mode) && sctx->parent_root && can_rename) { | |
< ret = wait_for_parent_move(sctx, cur, is_orphan); | |
< if (ret < 0) | |
< goto out; | |
< if (ret == 1) { | |
< can_rename = false; | |
< *pending_move = 1; | |
< } | |
< } | |
< #endif | |
< | |
< #ifdef MY_DEF_HERE | |
< | |
< if (can_rename) { | |
< struct fs_path *name = NULL; | |
< u64 ancestor; | |
< u64 old_send_progress = sctx->send_progress; | |
< | |
< name = fs_path_alloc(); | |
< if (!name) { | |
< ret = -ENOMEM; | |
< goto out; | |
< } | |
< | |
< sctx->send_progress = sctx->cur_ino + 1; | |
< ret = path_loop(sctx, name, sctx->cur_ino, sctx->cur_inode_gen, &ancestor); | |
< if (ret) { | |
< ret = add_pending_dir_move(sctx, sctx->cur_ino, sctx->cur_inode_gen, | |
< ancestor, &sctx->new_refs, &sctx->deleted_refs, is_orphan); | |
< if (ret < 0) { | |
< sctx->send_progress = old_send_progress; | |
< fs_path_free(name); | |
< goto out; | |
< } | |
< can_rename = false; | |
< *pending_move = 1; | |
< } | |
< sctx->send_progress = old_send_progress; | |
< fs_path_free(name); | |
< if (ret < 0) | |
< goto out; | |
< } | |
< #endif | |
< | |
< if (is_orphan && can_rename) { | |
--- | |
> /* | |
> * link/move the ref to the new place. If we have an orphan | |
> * inode, move it and update valid_path. If not, link or move | |
> * it depending on the inode mode. | |
> */ | |
> if (is_orphan) { | |
3567c2876 | |
< } else if (can_rename) { | |
--- | |
> } else { | |
3569,3575c2878,2884 | |
< | |
< #ifdef MY_DEF_HERE | |
< ret = send_rename(sctx, valid_path, cur->full_path); | |
< if (!ret) | |
< ret = fs_path_copy(valid_path, cur->full_path); | |
< #else | |
< ret = wait_for_parent_move(sctx, cur); | |
--- | |
> /* | |
> * Dirs can't be linked, so move it. For moved | |
> * dirs, we always have one new and one deleted | |
> * ref. The deleted ref is ignored later. | |
> */ | |
> ret = send_rename(sctx, valid_path, | |
> cur->full_path); | |
3578,3587c2887 | |
< if (ret) { | |
< *pending_move = 1; | |
< } else { | |
< ret = send_rename(sctx, valid_path, | |
< cur->full_path); | |
< if (!ret) | |
< ret = fs_path_copy(valid_path, | |
< cur->full_path); | |
< } | |
< #endif | |
--- | |
> ret = fs_path_copy(valid_path, cur->full_path); | |
3597c2897,2898 | |
< ret = dup_ref(cur, &check_dirs); | |
--- | |
> ret = ulist_add(check_dirs, cur->dir, cur->dir_gen, | |
> GFP_NOFS); | |
3603,3605c2904,2910 | |
< | |
< ret = can_rmdir(sctx, sctx->cur_ino, sctx->cur_inode_gen, | |
< sctx->cur_ino); | |
--- | |
> /* | |
> * Check if we can already rmdir the directory. If not, | |
> * orphanize it. For every dir item inside that gets deleted | |
> * later, we do this check again and rmdir it then if possible. | |
> * See the use of check_dirs for more details. | |
> */ | |
> ret = can_rmdir(sctx, sctx->cur_ino, sctx->cur_ino); | |
3621c2926,2927 | |
< ret = dup_ref(cur, &check_dirs); | |
--- | |
> ret = ulist_add(check_dirs, cur->dir, cur->dir_gen, | |
> GFP_NOFS); | |
3627c2933,2935 | |
< | |
--- | |
> /* | |
> * We have a moved dir. Add the old parent to check_dirs | |
> */ | |
3630c2938,2939 | |
< ret = dup_ref(cur, &check_dirs); | |
--- | |
> ret = ulist_add(check_dirs, cur->dir, cur->dir_gen, | |
> GFP_NOFS); | |
3634c2943,2947 | |
< | |
--- | |
> /* | |
> * We have a non dir inode. Go through all deleted refs and | |
> * unlink them if they were not already overwritten by other | |
> * inodes. | |
> */ | |
3646c2959,2960 | |
< ret = dup_ref(cur, &check_dirs); | |
--- | |
> ret = ulist_add(check_dirs, cur->dir, cur->dir_gen, | |
> GFP_NOFS); | |
3650c2964,2972 | |
< | |
--- | |
> | |
> /* | |
> * If the inode is still orphan, unlink the orphan. This may | |
> * happen when a previous inode did overwrite the first ref | |
> * of this inode and no new refs were added for the current | |
> * inode. Unlinking does not mean that the inode is deleted in | |
> * all cases. There may still be links to this inode in other | |
> * places. | |
> */ | |
3658,3660c2980,2993 | |
< list_for_each_entry(cur, &check_dirs, list) { | |
< | |
< if (cur->dir > sctx->cur_ino) | |
--- | |
> /* | |
> * We did collect all parent dirs where cur_inode was once located. We | |
> * now go through all these dirs and check if they are pending for | |
> * deletion and if it's finally possible to perform the rmdir now. | |
> * We also update the inode stats of the parent dirs here. | |
> */ | |
> ULIST_ITER_INIT(&uit); | |
> while ((un = ulist_next(check_dirs, &uit))) { | |
> /* | |
> * In case we had refs into dirs that were not processed yet, | |
> * we don't need to do the utime and rmdir logic for these dirs. | |
> * The dir will be processed later. | |
> */ | |
> if (un->val > sctx->cur_ino) | |
3663c2996 | |
< ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen); | |
--- | |
> ret = get_cur_inode_state(sctx, un->val, un->aux); | |
3669,3670c3002,3003 | |
< | |
< ret = send_utimes(sctx, cur->dir, cur->dir_gen); | |
--- | |
> /* TODO delayed utimes */ | |
> ret = send_utimes(sctx, un->val, un->aux); | |
3673,3676c3006,3007 | |
< } else if (ret == inode_state_did_delete && | |
< cur->dir != last_dir_ino_rm) { | |
< ret = can_rmdir(sctx, cur->dir, cur->dir_gen, | |
< sctx->cur_ino); | |
--- | |
> } else if (ret == inode_state_did_delete) { | |
> ret = can_rmdir(sctx, un->val, sctx->cur_ino); | |
3680,3681c3011,3012 | |
< ret = get_cur_path(sctx, cur->dir, | |
< cur->dir_gen, valid_path); | |
--- | |
> ret = get_cur_path(sctx, un->val, un->aux, | |
> valid_path); | |
3687d3017 | |
< last_dir_ino_rm = cur->dir; | |
3695d3024 | |
< __free_recorded_refs(&check_dirs); | |
3697c3026,3027 | |
< fs_path_free(valid_path); | |
--- | |
> ulist_free(check_dirs); | |
> fs_path_free(sctx, valid_path); | |
3701,3702c3031,3033 | |
< static int record_ref(struct btrfs_root *root, int num, u64 dir, int index, | |
< struct fs_path *name, void *ctx, struct list_head *refs) | |
--- | |
> static int __record_new_ref(int num, u64 dir, int index, | |
> struct fs_path *name, | |
> void *ctx) | |
3709c3040 | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
3713c3044 | |
< ret = get_inode_info(root, dir, NULL, &gen, NULL, NULL, | |
--- | |
> ret = get_inode_info(sctx->send_root, dir, NULL, &gen, NULL, NULL, | |
3725c3056 | |
< ret = __record_ref(refs, dir, gen, p); | |
--- | |
> ret = record_ref(&sctx->new_refs, dir, gen, p); | |
3729c3060 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
3733,3741d3063 | |
< static int __record_new_ref(int num, u64 dir, int index, | |
< struct fs_path *name, | |
< void *ctx) | |
< { | |
< struct send_ctx *sctx = ctx; | |
< return record_ref(sctx->send_root, num, dir, index, name, | |
< ctx, &sctx->new_refs); | |
< } | |
< | |
3745a3068 | |
> int ret = 0; | |
3747,3748c3070,3094 | |
< return record_ref(sctx->parent_root, num, dir, index, name, | |
< ctx, &sctx->deleted_refs); | |
--- | |
> struct fs_path *p; | |
> u64 gen; | |
> | |
> p = fs_path_alloc(sctx); | |
> if (!p) | |
> return -ENOMEM; | |
> | |
> ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL, NULL, | |
> NULL, NULL); | |
> if (ret < 0) | |
> goto out; | |
> | |
> ret = get_cur_path(sctx, dir, gen, p); | |
> if (ret < 0) | |
> goto out; | |
> ret = fs_path_add_path(p, name); | |
> if (ret < 0) | |
> goto out; | |
> | |
> ret = record_ref(&sctx->deleted_refs, dir, gen, p); | |
> | |
> out: | |
> if (ret) | |
> fs_path_free(sctx, p); | |
> return ret; | |
3755,3756c3101,3102 | |
< ret = iterate_inode_ref(sctx->send_root, sctx->left_path, | |
< sctx->cmp_key, 0, __record_new_ref, sctx); | |
--- | |
> ret = iterate_inode_ref(sctx, sctx->send_root, sctx->left_path, | |
> sctx->cmp_key, 0, __record_new_ref, sctx); | |
3769,3770c3115,3116 | |
< ret = iterate_inode_ref(sctx->parent_root, sctx->right_path, | |
< sctx->cmp_key, 0, __record_deleted_ref, sctx); | |
--- | |
> ret = iterate_inode_ref(sctx, sctx->parent_root, sctx->right_path, | |
> sctx->cmp_key, 0, __record_deleted_ref, sctx); | |
3781,3782d3126 | |
< u64 dir_gen; | |
< struct btrfs_root *root; | |
3792,3793d3135 | |
< u64 dir_gen; | |
< int ret; | |
3797,3803d3138 | |
< | |
< ret = get_inode_info(ctx->root, dir, NULL, &dir_gen, NULL, | |
< NULL, NULL, NULL); | |
< if (ret) | |
< return ret; | |
< if (dir_gen != ctx->dir_gen) | |
< return 0; | |
3810c3145,3146 | |
< static int find_iref(struct btrfs_root *root, | |
--- | |
> static int find_iref(struct send_ctx *sctx, | |
> struct btrfs_root *root, | |
3813c3149 | |
< u64 dir, u64 dir_gen, struct fs_path *name) | |
--- | |
> u64 dir, struct fs_path *name) | |
3820d3155 | |
< ctx.dir_gen = dir_gen; | |
3822d3156 | |
< ctx.root = root; | |
3824c3158 | |
< ret = iterate_inode_ref(root, path, key, 0, __find_iref, &ctx); | |
--- | |
> ret = iterate_inode_ref(sctx, root, path, key, 0, __find_iref, &ctx); | |
3838d3171 | |
< u64 dir_gen; | |
3842,3848c3175,3176 | |
< ret = get_inode_info(sctx->send_root, dir, NULL, &dir_gen, NULL, | |
< NULL, NULL, NULL); | |
< if (ret) | |
< return ret; | |
< | |
< ret = find_iref(sctx->parent_root, sctx->right_path, | |
< sctx->cmp_key, dir, dir_gen, name); | |
--- | |
> ret = find_iref(sctx, sctx->parent_root, sctx->right_path, | |
> sctx->cmp_key, dir, name); | |
3861d3188 | |
< u64 dir_gen; | |
3865,3871c3192,3193 | |
< ret = get_inode_info(sctx->parent_root, dir, NULL, &dir_gen, NULL, | |
< NULL, NULL, NULL); | |
< if (ret) | |
< return ret; | |
< | |
< ret = find_iref(sctx->send_root, sctx->left_path, sctx->cmp_key, | |
< dir, dir_gen, name); | |
--- | |
> ret = find_iref(sctx, sctx->send_root, sctx->left_path, sctx->cmp_key, | |
> dir, name); | |
3884c3206 | |
< ret = iterate_inode_ref(sctx->send_root, sctx->left_path, | |
--- | |
> ret = iterate_inode_ref(sctx, sctx->send_root, sctx->left_path, | |
3888c3210 | |
< ret = iterate_inode_ref(sctx->parent_root, sctx->right_path, | |
--- | |
> ret = iterate_inode_ref(sctx, sctx->parent_root, sctx->right_path, | |
3897a3220,3223 | |
> /* | |
> * Record and process all refs at once. Needed when an inode changes the | |
> * generation number, which means that it was deleted and recreated. | |
> */ | |
3909d3234 | |
< int pending_move = 0; | |
3922,3925c3247 | |
< btrfs_err(sctx->send_root->fs_info, | |
< "Wrong command %d in process_all_refs", cmd); | |
< ret = -EINVAL; | |
< goto out; | |
--- | |
> BUG(); | |
3931,3934d3252 | |
< ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | |
< if (ret < 0) | |
< goto out; | |
< | |
3935a3254,3259 | |
> ret = btrfs_search_slot_for_read(root, &key, path, 1, 0); | |
> if (ret < 0) | |
> goto out; | |
> if (ret) | |
> break; | |
> | |
3938,3946d3261 | |
< if (slot >= btrfs_header_nritems(eb)) { | |
< ret = btrfs_next_leaf(root, path); | |
< if (ret < 0) | |
< goto out; | |
< else if (ret > 0) | |
< break; | |
< continue; | |
< } | |
< | |
3954c3269,3271 | |
< ret = iterate_inode_ref(root, path, &found_key, 0, cb, sctx); | |
--- | |
> ret = iterate_inode_ref(sctx, root, path, &found_key, 0, cb, | |
> sctx); | |
> btrfs_release_path(path); | |
3958c3275 | |
< path->slots[0]++; | |
--- | |
> key.offset = found_key.offset + 1; | |
3962,3964c3279 | |
< ret = process_recorded_refs(sctx, &pending_move); | |
< | |
< ASSERT(pending_move == 0); | |
--- | |
> ret = process_recorded_refs(sctx); | |
4023,4031c3338 | |
< #ifdef MY_DEF_HERE | |
< | |
< if (!strncmp(name, XATTR_SYNO_PREFIX XATTR_SYNO_ARCHIVE_BIT, name_len)) { | |
< sctx->cur_inode_archive = syno_archive_set; | |
< return 0; | |
< } | |
< #endif | |
< | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
4034a3342,3347 | |
> /* | |
> * This hack is needed because empty acl's are stored as zero byte | |
> * data in xattrs. Problem with that is, that receiving these zero byte | |
> * acl's will fail later. To fix this, we send a dummy acl list that | |
> * only contains the version number and no entries. | |
> */ | |
4052c3365 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
4065c3378 | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
4076c3389 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
4084,4085c3397,3398 | |
< ret = iterate_dir_item(sctx->send_root, sctx->left_path, | |
< sctx->cmp_key, __process_new_xattr, sctx); | |
--- | |
> ret = iterate_dir_item(sctx, sctx->send_root, sctx->left_path, | |
> sctx->cmp_key, __process_new_xattr, sctx); | |
4094,4095c3407,3408 | |
< ret = iterate_dir_item(sctx->parent_root, sctx->right_path, | |
< sctx->cmp_key, __process_deleted_xattr, sctx); | |
--- | |
> ret = iterate_dir_item(sctx, sctx->parent_root, sctx->right_path, | |
> sctx->cmp_key, __process_deleted_xattr, sctx); | |
4119c3432 | |
< ctx->found_data = kmemdup(data, data_len, GFP_NOFS); | |
--- | |
> ctx->found_data = kmalloc(data_len, GFP_NOFS); | |
4121a3435 | |
> memcpy(ctx->found_data, data, data_len); | |
4127c3441,3442 | |
< static int find_xattr(struct btrfs_root *root, | |
--- | |
> static int find_xattr(struct send_ctx *sctx, | |
> struct btrfs_root *root, | |
4142c3457 | |
< ret = iterate_dir_item(root, path, key, __find_xattr, &ctx); | |
--- | |
> ret = iterate_dir_item(sctx, root, path, key, __find_xattr, &ctx); | |
4156a3472 | |
> | |
4167,4169c3483,3485 | |
< ret = find_xattr(sctx->parent_root, sctx->right_path, | |
< sctx->cmp_key, name, name_len, &found_data, | |
< &found_data_len); | |
--- | |
> ret = find_xattr(sctx, sctx->parent_root, sctx->right_path, | |
> sctx->cmp_key, name, name_len, &found_data, | |
> &found_data_len); | |
4195,4196c3511,3512 | |
< ret = find_xattr(sctx->send_root, sctx->left_path, sctx->cmp_key, | |
< name, name_len, NULL, NULL); | |
--- | |
> ret = find_xattr(sctx, sctx->send_root, sctx->left_path, sctx->cmp_key, | |
> name, name_len, NULL, NULL); | |
4210c3526 | |
< ret = iterate_dir_item(sctx->send_root, sctx->left_path, | |
--- | |
> ret = iterate_dir_item(sctx, sctx->send_root, sctx->left_path, | |
4214c3530 | |
< ret = iterate_dir_item(sctx->parent_root, sctx->right_path, | |
--- | |
> ret = iterate_dir_item(sctx, sctx->parent_root, sctx->right_path, | |
4240,4243d3555 | |
< ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | |
< if (ret < 0) | |
< goto out; | |
< | |
4245,4255c3557,3562 | |
< eb = path->nodes[0]; | |
< slot = path->slots[0]; | |
< if (slot >= btrfs_header_nritems(eb)) { | |
< ret = btrfs_next_leaf(root, path); | |
< if (ret < 0) { | |
< goto out; | |
< } else if (ret > 0) { | |
< ret = 0; | |
< break; | |
< } | |
< continue; | |
--- | |
> ret = btrfs_search_slot_for_read(root, &key, path, 1, 0); | |
> if (ret < 0) | |
> goto out; | |
> if (ret) { | |
> ret = 0; | |
> goto out; | |
4257a3565,3566 | |
> eb = path->nodes[0]; | |
> slot = path->slots[0]; | |
4258a3568 | |
> | |
4265,4266c3575,3576 | |
< ret = iterate_dir_item(root, path, &found_key, | |
< __process_new_xattr, sctx); | |
--- | |
> ret = iterate_dir_item(sctx, root, path, &found_key, | |
> __process_new_xattr, sctx); | |
4270c3580,3581 | |
< path->slots[0]++; | |
--- | |
> btrfs_release_path(path); | |
> key.offset = found_key.offset + 1; | |
4278,4389c3589,3592 | |
< #ifdef MY_DEF_HERE | |
< static ssize_t fill_read_buf(struct send_ctx *sctx, u64 offset, u32 len, bool onlyCalculateSize) | |
< #else | |
< static ssize_t fill_read_buf(struct send_ctx *sctx, u64 offset, u32 len) | |
< #endif | |
< { | |
< struct btrfs_root *root = sctx->send_root; | |
< struct btrfs_fs_info *fs_info = root->fs_info; | |
< struct inode *inode; | |
< struct page *page; | |
< char *addr; | |
< struct btrfs_key key; | |
< pgoff_t index = offset >> PAGE_CACHE_SHIFT; | |
< pgoff_t last_index; | |
< unsigned pg_offset = offset & ~PAGE_CACHE_MASK; | |
< ssize_t ret = 0; | |
< | |
< key.objectid = sctx->cur_ino; | |
< key.type = BTRFS_INODE_ITEM_KEY; | |
< key.offset = 0; | |
< | |
< inode = btrfs_iget(fs_info->sb, &key, root, NULL); | |
< if (IS_ERR(inode)) | |
< return PTR_ERR(inode); | |
< | |
< if (offset + len > i_size_read(inode)) { | |
< if (offset > i_size_read(inode)) | |
< len = 0; | |
< else | |
< len = offset - i_size_read(inode); | |
< } | |
< if (len == 0) | |
< goto out; | |
< | |
< last_index = (offset + len - 1) >> PAGE_CACHE_SHIFT; | |
< | |
< #ifdef MY_DEF_HERE | |
< if (!onlyCalculateSize) { | |
< #endif | |
< memset(&sctx->ra, 0, sizeof(struct file_ra_state)); | |
< file_ra_state_init(&sctx->ra, inode->i_mapping); | |
< #ifdef MY_DEF_HERE | |
< #else | |
< btrfs_force_ra(inode->i_mapping, &sctx->ra, NULL, index, | |
< last_index - index + 1); | |
< #endif | |
< #ifdef MY_DEF_HERE | |
< } | |
< #endif | |
< | |
< while (index <= last_index) { | |
< unsigned cur_len = min_t(unsigned, len, | |
< PAGE_CACHE_SIZE - pg_offset); | |
< #ifdef MY_DEF_HERE | |
< if (!onlyCalculateSize) { | |
< #endif | |
< #ifdef MY_DEF_HERE | |
< page = find_lock_page(inode->i_mapping, index); | |
< if (!page) { | |
< page_cache_sync_readahead(inode->i_mapping, | |
< &sctx->ra, NULL, index, | |
< last_index + 1 - index); | |
< | |
< page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); | |
< if (unlikely(page == NULL)) { | |
< ret = -ENOMEM; | |
< break; | |
< } | |
< } | |
< | |
< if (PageReadahead(page)) { | |
< page_cache_async_readahead(inode->i_mapping, | |
< &sctx->ra, NULL, page, index, | |
< last_index + 1 - index); | |
< } | |
< #else | |
< page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); | |
< if (!page) { | |
< ret = -ENOMEM; | |
< break; | |
< } | |
< #endif | |
< | |
< if (!PageUptodate(page)) { | |
< btrfs_readpage(NULL, page); | |
< lock_page(page); | |
< if (!PageUptodate(page)) { | |
< unlock_page(page); | |
< page_cache_release(page); | |
< ret = -EIO; | |
< break; | |
< } | |
< } | |
< | |
< addr = kmap(page); | |
< memcpy(sctx->read_buf + ret, addr + pg_offset, cur_len); | |
< kunmap(page); | |
< unlock_page(page); | |
< page_cache_release(page); | |
< #ifdef MY_DEF_HERE | |
< } | |
< #endif | |
< index++; | |
< pg_offset = 0; | |
< len -= cur_len; | |
< ret += cur_len; | |
< } | |
< out: | |
< iput(inode); | |
< return ret; | |
< } | |
< | |
--- | |
> /* | |
> * Read some bytes from the current inode/file and send a write command to | |
> * user space. | |
> */ | |
4394c3597,3599 | |
< ssize_t num_read = 0; | |
--- | |
> loff_t pos = offset; | |
> int num_read = 0; | |
> mm_segment_t old_fs; | |
4396c3601 | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
4399a3605,3613 | |
> /* | |
> * vfs normally only accepts user space buffers for security reasons. | |
> * we only read from the file and also only provide the read_buf buffer | |
> * to vfs. As this buffer does not come from a user space call, it's | |
> * ok to temporary allow kernel space buffers. | |
> */ | |
> old_fs = get_fs(); | |
> set_fs(KERNEL_DS); | |
> | |
4402,4413c3616,3617 | |
< #ifdef MY_DEF_HERE | |
< if (sctx->current_cmd_pos < sctx->skip_cmd_count) { | |
< num_read = fill_read_buf(sctx, offset, len, true); | |
< } else { | |
< num_read = fill_read_buf(sctx, offset, len, false); | |
< } | |
< #else | |
< num_read = fill_read_buf(sctx, offset, len); | |
< #endif | |
< if (num_read <= 0) { | |
< if (num_read < 0) | |
< ret = num_read; | |
--- | |
> ret = open_cur_inode_file(sctx); | |
> if (ret < 0) | |
4415d3618 | |
< } | |
4417c3620 | |
< ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE); | |
--- | |
> ret = vfs_read(sctx->cur_inode_filp, sctx->read_buf, len, &pos); | |
4419a3623,3625 | |
> num_read = ret; | |
> if (!num_read) | |
> goto out; | |
4421,4425c3627,3629 | |
< #ifdef MY_DEF_HERE | |
< if (sctx->current_cmd_pos < sctx->skip_cmd_count) { | |
< goto send_cmd_label; | |
< } | |
< #endif | |
--- | |
> ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE); | |
> if (ret < 0) | |
> goto out; | |
4435,4437d3638 | |
< #ifdef MY_DEF_HERE | |
< send_cmd_label: | |
< #endif | |
4442c3643,3644 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
> set_fs(old_fs); | |
4447a3650,3652 | |
> /* | |
> * Send a clone command to user space. | |
> */ | |
4461c3666 | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
4484c3689,3690 | |
< ret = get_inode_path(clone_root->root, clone_root->ino, p); | |
--- | |
> ret = get_inode_path(sctx, clone_root->root, | |
> clone_root->ino, p); | |
4489,4492d3694 | |
< #ifdef MY_DEF_HERE | |
< TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, | |
< clone_root->root->root_item.received_uuid); | |
< #else | |
4495d3696 | |
< #endif | |
4497c3698 | |
< le64_to_cpu(clone_root->root->root_item.ctransid)); | |
--- | |
> clone_root->root->root_item.ctransid); | |
4506c3707 | |
< fs_path_free(p); | |
--- | |
> fs_path_free(sctx, p); | |
4509a3711,3713 | |
> /* | |
> * Send an update extent command to user space. | |
> */ | |
4516c3720 | |
< p = fs_path_alloc(); | |
--- | |
> p = fs_path_alloc(sctx); | |
4536,4715c3740 | |
< fs_path_free(p); | |
< return ret; | |
< } | |
< | |
< static int send_hole(struct send_ctx *sctx, u64 end) | |
< { | |
< struct fs_path *p = NULL; | |
< u64 offset = sctx->cur_inode_last_extent; | |
< u64 len; | |
< int ret = 0; | |
< | |
< #ifdef MY_DEF_HERE | |
< if (sctx->phase == SEND_PHASE_COMPUTE_DATA_SIZE) { | |
< sctx->total_data_size += end - offset; | |
< return write_calculate_size(sctx); | |
< } | |
< #endif | |
< | |
< p = fs_path_alloc(); | |
< if (!p) | |
< return -ENOMEM; | |
< ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); | |
< if (ret < 0) | |
< goto tlv_put_failure; | |
< memset(sctx->read_buf, 0, BTRFS_SEND_READ_SIZE); | |
< while (offset < end) { | |
< len = min_t(u64, end - offset, BTRFS_SEND_READ_SIZE); | |
< | |
< ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE); | |
< if (ret < 0) | |
< break; | |
< TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); | |
< TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset); | |
< TLV_PUT(sctx, BTRFS_SEND_A_DATA, sctx->read_buf, len); | |
< ret = send_cmd(sctx); | |
< if (ret < 0) | |
< break; | |
< offset += len; | |
< } | |
< tlv_put_failure: | |
< fs_path_free(p); | |
< return ret; | |
< } | |
< | |
< static int send_extent_data(struct send_ctx *sctx, | |
< const u64 offset, | |
< const u64 len) | |
< { | |
< u64 sent = 0; | |
< | |
< if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) | |
< return send_update_extent(sctx, offset, len); | |
< | |
< while (sent < len) { | |
< u64 size = len - sent; | |
< int ret; | |
< | |
< if (size > BTRFS_SEND_READ_SIZE) | |
< size = BTRFS_SEND_READ_SIZE; | |
< ret = send_write(sctx, offset + sent, size); | |
< if (ret < 0) | |
< return ret; | |
< if (!ret) | |
< break; | |
< sent += ret; | |
< } | |
< return 0; | |
< } | |
< | |
< static int clone_range(struct send_ctx *sctx, | |
< struct clone_root *clone_root, | |
< const u64 disk_byte, | |
< u64 data_offset, | |
< u64 offset, | |
< u64 len) | |
< { | |
< struct btrfs_path *path; | |
< struct btrfs_key key; | |
< int ret; | |
< | |
< path = alloc_path_for_send(); | |
< if (!path) | |
< return -ENOMEM; | |
< | |
< key.objectid = clone_root->ino; | |
< key.type = BTRFS_EXTENT_DATA_KEY; | |
< key.offset = clone_root->offset; | |
< ret = btrfs_search_slot(NULL, clone_root->root, &key, path, 0, 0); | |
< if (ret < 0) | |
< goto out; | |
< if (ret > 0 && path->slots[0] > 0) { | |
< btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0] - 1); | |
< if (key.objectid == clone_root->ino && | |
< key.type == BTRFS_EXTENT_DATA_KEY) | |
< path->slots[0]--; | |
< } | |
< | |
< while (true) { | |
< struct extent_buffer *leaf = path->nodes[0]; | |
< int slot = path->slots[0]; | |
< struct btrfs_file_extent_item *ei; | |
< u8 type; | |
< u64 ext_len; | |
< u64 clone_len; | |
< | |
< if (slot >= btrfs_header_nritems(leaf)) { | |
< ret = btrfs_next_leaf(clone_root->root, path); | |
< if (ret < 0) | |
< goto out; | |
< else if (ret > 0) | |
< break; | |
< continue; | |
< } | |
< | |
< btrfs_item_key_to_cpu(leaf, &key, slot); | |
< | |
< if (key.objectid != clone_root->ino || | |
< key.type != BTRFS_EXTENT_DATA_KEY) | |
< break; | |
< | |
< ei = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); | |
< type = btrfs_file_extent_type(leaf, ei); | |
< if (type == BTRFS_FILE_EXTENT_INLINE) { | |
< ext_len = btrfs_file_extent_inline_len(leaf, slot, ei); | |
< ext_len = PAGE_CACHE_ALIGN(ext_len); | |
< } else { | |
< ext_len = btrfs_file_extent_num_bytes(leaf, ei); | |
< } | |
< | |
< if (key.offset + ext_len <= clone_root->offset) | |
< goto next; | |
< | |
< if (key.offset > clone_root->offset) { | |
< | |
< u64 hole_len = key.offset - clone_root->offset; | |
< | |
< if (hole_len > len) | |
< hole_len = len; | |
< ret = send_extent_data(sctx, offset, hole_len); | |
< if (ret < 0) | |
< goto out; | |
< | |
< len -= hole_len; | |
< if (len == 0) | |
< break; | |
< offset += hole_len; | |
< clone_root->offset += hole_len; | |
< data_offset += hole_len; | |
< } | |
< | |
< if (key.offset >= clone_root->offset + len) | |
< break; | |
< | |
< clone_len = min_t(u64, ext_len, len); | |
< | |
< if (btrfs_file_extent_disk_bytenr(leaf, ei) == disk_byte && | |
< btrfs_file_extent_offset(leaf, ei) == data_offset) | |
< ret = send_clone(sctx, offset, clone_len, clone_root); | |
< else | |
< ret = send_extent_data(sctx, offset, clone_len); | |
< | |
< if (ret < 0) | |
< goto out; | |
< | |
< len -= clone_len; | |
< if (len == 0) | |
< break; | |
< offset += clone_len; | |
< clone_root->offset += clone_len; | |
< data_offset += clone_len; | |
< next: | |
< path->slots[0]++; | |
< } | |
< | |
< if (len > 0) | |
< ret = send_extent_data(sctx, offset, len); | |
< else | |
< ret = 0; | |
< out: | |
< btrfs_free_path(path); | |
--- | |
> fs_path_free(sctx, p); | |
4726a3752 | |
> u64 pos = 0; | |
4727a3754 | |
> u32 l; | |
4729d3755 | |
< u64 bs = sctx->send_root->fs_info->sb->s_blocksize; | |
4735,4737c3761,3766 | |
< len = btrfs_file_extent_inline_len(path->nodes[0], | |
< path->slots[0], ei); | |
< | |
--- | |
> len = btrfs_file_extent_inline_len(path->nodes[0], ei); | |
> /* | |
> * it is possible the inline item won't cover the whole page, | |
> * but there may be items after this page. Make | |
> * sure to send the whole thing | |
> */ | |
4750,4770c3779,3782 | |
< #ifdef MY_DEF_HERE | |
< if (sctx->phase == SEND_PHASE_COMPUTE_DATA_SIZE) { | |
< if (clone_root && IS_ALIGNED(offset + len, bs)) { | |
< sctx->total_data_size += sizeof(struct btrfs_cmd_header) + sizeof(struct fs_path); | |
< ret = write_calculate_size(sctx); | |
< } else if (offset < sctx->cur_inode_size) { | |
< sctx->total_data_size += len; | |
< ret = write_calculate_size(sctx); | |
< } | |
< goto out; | |
< } | |
< #endif | |
< | |
< if (clone_root && IS_ALIGNED(offset + len, bs)) { | |
< u64 disk_byte; | |
< u64 data_offset; | |
< | |
< disk_byte = btrfs_file_extent_disk_bytenr(path->nodes[0], ei); | |
< data_offset = btrfs_file_extent_offset(path->nodes[0], ei); | |
< ret = clone_range(sctx, clone_root, disk_byte, data_offset, | |
< offset, len); | |
--- | |
> if (clone_root) { | |
> ret = send_clone(sctx, offset, len, clone_root); | |
> } else if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) { | |
> ret = send_update_extent(sctx, offset, len); | |
4772c3784,3795 | |
< ret = send_extent_data(sctx, offset, len); | |
--- | |
> while (pos < len) { | |
> l = len - pos; | |
> if (l > BTRFS_SEND_READ_SIZE) | |
> l = BTRFS_SEND_READ_SIZE; | |
> ret = send_write(sctx, pos + offset, l); | |
> if (ret < 0) | |
> goto out; | |
> if (!ret) | |
> break; | |
> pos += ret; | |
> } | |
> ret = 0; | |
4818a3842,3862 | |
> /* | |
> * Following comments will refer to these graphics. L is the left | |
> * extents which we are checking at the moment. 1-8 are the right | |
> * extents that we iterate. | |
> * | |
> * |-----L-----| | |
> * |-1-|-2a-|-3-|-4-|-5-|-6-| | |
> * | |
> * |-----L-----| | |
> * |--1--|-2b-|...(same as above) | |
> * | |
> * Alternative situation. Happens on files where extents got split. | |
> * |-----L-----| | |
> * |-----------7-----------|-6-| | |
> * | |
> * Alternative situation. Happens on files which got larger. | |
> * |-----L-----| | |
> * |-8-| | |
> * Nothing follows after 8. | |
> */ | |
> | |
4829a3874,3876 | |
> /* | |
> * Handle special case where the right side has no extents at all. | |
> */ | |
4835,4836c3882 | |
< | |
< ret = (left_disknr) ? 0 : 1; | |
--- | |
> ret = 0; | |
4839a3886,3888 | |
> /* | |
> * We're now on 2a, 2b or 7. | |
> */ | |
4844,4848d3892 | |
< if (right_type != BTRFS_FILE_EXTENT_REG) { | |
< ret = 0; | |
< goto out; | |
< } | |
< | |
4853a3898,3906 | |
> if (right_type != BTRFS_FILE_EXTENT_REG) { | |
> ret = 0; | |
> goto out; | |
> } | |
> | |
> /* | |
> * Are we at extent 8? If yes, we know the extent is changed. | |
> * This may only happen on the first iteration. | |
> */ | |
4855,4856c3908 | |
< | |
< ret = (left_disknr) ? 0 : 1; | |
--- | |
> ret = 0; | |
4862c3914 | |
< | |
--- | |
> /* Fix the right offset for 2a and 7. */ | |
4865c3917 | |
< | |
--- | |
> /* Fix the left offset for all behind 2a and 2b */ | |
4868a3921,3923 | |
> /* | |
> * Check if we have the same extent. | |
> */ | |
4875a3931,3933 | |
> /* | |
> * Go to the next extent. | |
> */ | |
4895a3954,3957 | |
> /* | |
> * We're now behind the left extent (treat as unchanged) or at the end | |
> * of the right side (treat as changed). | |
> */ | |
4901,4904d3962 | |
< out: | |
< btrfs_free_path(path); | |
< return ret; | |
< } | |
4906,4945d3963 | |
< static int get_last_extent(struct send_ctx *sctx, u64 offset) | |
< { | |
< struct btrfs_path *path; | |
< struct btrfs_root *root = sctx->send_root; | |
< struct btrfs_file_extent_item *fi; | |
< struct btrfs_key key; | |
< u64 extent_end; | |
< u8 type; | |
< int ret; | |
< | |
< path = alloc_path_for_send(); | |
< if (!path) | |
< return -ENOMEM; | |
< | |
< sctx->cur_inode_last_extent = 0; | |
< | |
< key.objectid = sctx->cur_ino; | |
< key.type = BTRFS_EXTENT_DATA_KEY; | |
< key.offset = offset; | |
< ret = btrfs_search_slot_for_read(root, &key, path, 0, 1); | |
< if (ret < 0) | |
< goto out; | |
< ret = 0; | |
< btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); | |
< if (key.objectid != sctx->cur_ino || key.type != BTRFS_EXTENT_DATA_KEY) | |
< goto out; | |
< | |
< fi = btrfs_item_ptr(path->nodes[0], path->slots[0], | |
< struct btrfs_file_extent_item); | |
< type = btrfs_file_extent_type(path->nodes[0], fi); | |
< if (type == BTRFS_FILE_EXTENT_INLINE) { | |
< u64 size = btrfs_file_extent_inline_len(path->nodes[0], | |
< path->slots[0], fi); | |
< extent_end = ALIGN(key.offset + size, | |
< sctx->send_root->sectorsize); | |
< } else { | |
< extent_end = key.offset + | |
< btrfs_file_extent_num_bytes(path->nodes[0], fi); | |
< } | |
< sctx->cur_inode_last_extent = extent_end; | |
4951,4994d3968 | |
< static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path, | |
< struct btrfs_key *key) | |
< { | |
< struct btrfs_file_extent_item *fi; | |
< u64 extent_end; | |
< u8 type; | |
< int ret = 0; | |
< | |
< if (sctx->cur_ino != key->objectid || !need_send_hole(sctx)) | |
< return 0; | |
< | |
< if (sctx->cur_inode_last_extent == (u64)-1) { | |
< ret = get_last_extent(sctx, key->offset - 1); | |
< if (ret) | |
< return ret; | |
< } | |
< | |
< fi = btrfs_item_ptr(path->nodes[0], path->slots[0], | |
< struct btrfs_file_extent_item); | |
< type = btrfs_file_extent_type(path->nodes[0], fi); | |
< if (type == BTRFS_FILE_EXTENT_INLINE) { | |
< u64 size = btrfs_file_extent_inline_len(path->nodes[0], | |
< path->slots[0], fi); | |
< extent_end = ALIGN(key->offset + size, | |
< sctx->send_root->sectorsize); | |
< } else { | |
< extent_end = key->offset + | |
< btrfs_file_extent_num_bytes(path->nodes[0], fi); | |
< } | |
< | |
< if (path->slots[0] == 0 && | |
< sctx->cur_inode_last_extent < key->offset) { | |
< | |
< ret = get_last_extent(sctx, key->offset - 1); | |
< if (ret) | |
< return ret; | |
< } | |
< | |
< if (sctx->cur_inode_last_extent < key->offset) | |
< ret = send_hole(sctx, key->offset); | |
< sctx->cur_inode_last_extent = extent_end; | |
< return ret; | |
< } | |
< | |
4999d3972 | |