Skip to content

Instantly share code, notes, and snippets.

@barcharcraz
Created April 12, 2018 15:50
Show Gist options
  • Save barcharcraz/0678e3180615d627d7aa4769e07c274b to your computer and use it in GitHub Desktop.
Save barcharcraz/0678e3180615d627d7aa4769e07c274b to your computer and use it in GitHub Desktop.
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
< struct clone_root *found_clone = NULL;
5000a3974
> struct clone_root *found_clone = NULL;
5011,5031c3985
< goto out_hole;
< }
< } else {
< struct btrfs_file_extent_item *ei;
< u8 type;
<
< ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
< struct btrfs_file_extent_item);
< type = btrfs_file_extent_type(path->nodes[0], ei);
< if (type == BTRFS_FILE_EXTENT_PREALLOC ||
< type == BTRFS_FILE_EXTENT_REG) {
<
< if (type == BTRFS_FILE_EXTENT_PREALLOC) {
< ret = 0;
< goto out;
< }
<
< if (btrfs_file_extent_disk_bytenr(path->nodes[0], ei) == 0) {
< ret = 0;
< goto out;
< }
---
> goto out;
5041,5044c3995
< if (ret)
< goto out;
< out_hole:
< ret = maybe_send_hole(sctx, path, key);
---
>
5067,5070d4017
< ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
< if (ret < 0)
< goto out;
<
5072,5083c4019,4024
< 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;
5085a4027,4028
> eb = path->nodes[0];
> slot = path->slots[0];
5098c4041,4042
< path->slots[0]++;
---
> btrfs_release_path(path);
> key.offset = found_key.offset + 1;
5106,5108c4050
< static int process_recorded_refs_if_needed(struct send_ctx *sctx, int at_end,
< int *pending_move,
< int *refs_processed)
---
> static int process_recorded_refs_if_needed(struct send_ctx *sctx, int at_end)
5120c4062
< ret = process_recorded_refs(sctx, pending_move);
---
> ret = process_recorded_refs(sctx);
5124,5153c4066,4071
< *refs_processed = 1;
< out:
< return ret;
< }
<
< #ifdef MY_DEF_HERE
<
< static int syno_attribute_handler(struct send_ctx *sctx)
< {
< int ret = 0;
< __le32 archive_bit_le32 = 0;
< struct fs_path *p = NULL;
< struct btrfs_root *root = sctx->send_root;
< struct btrfs_fs_info *fs_info = root->fs_info;
< struct inode *inode = NULL;
< struct btrfs_key key;
<
< if (sctx->cur_inode_archive) {
< 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)) {
< ret = PTR_ERR(inode);
< goto out;
< }
< if (sctx->cur_inode_archive) {
< archive_bit_le32 = cpu_to_le32(inode->i_archive_bit);
< }
---
> /*
> * We have processed the refs and thus need to advance send_progress.
> * Now, calls to get_cur_xxx will take the updated refs of the current
> * inode into account.
> */
> sctx->send_progress = sctx->cur_ino + 1;
5155,5188d4072
< iput(inode);
< if (ret < 0) {
< goto out;
< }
< }
< if (sctx->cur_inode_archive) {
< p = fs_path_alloc();
< if (!p) {
< ret = -ENOMEM;
< goto out;
< }
< ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p);
< if (ret < 0)
< goto out;
< if (sctx->cur_inode_archive) {
< #ifdef MY_DEF_HERE
< if (sctx->phase == SEND_PHASE_COMPUTE_DATA_SIZE) {
< sctx->total_data_size += sizeof(archive_bit_le32);
< ret = write_calculate_size(sctx);
< if (ret < 0) {
< goto out;
< }
< } else {
< #endif
< ret = send_set_xattr(sctx, p, XATTR_SYNO_PREFIX XATTR_SYNO_ARCHIVE_BIT,
< strlen(XATTR_SYNO_PREFIX XATTR_SYNO_ARCHIVE_BIT),
< (const char *)&archive_bit_le32, sizeof(archive_bit_le32));
< if (ret < 0)
< goto out;
< #ifdef MY_DEF_HERE
< }
< #endif
< }
< }
5190d4073
< fs_path_free(p);
5193d4075
< #endif
5206,5207d4087
< int pending_move = 0;
< int refs_processed = 0;
5209,5210c4089
< ret = process_recorded_refs_if_needed(sctx, at_end, &pending_move,
< &refs_processed);
---
> ret = process_recorded_refs_if_needed(sctx, at_end);
5214,5216d4092
< if (refs_processed && !pending_move)
< sctx->send_progress = sctx->cur_ino + 1;
<
5222,5226d4097
< #ifdef MY_DEF_HERE
< if (sctx->phase == SEND_PHASE_COMPUTE_DATA_SIZE)
< goto truncate_inode;
< #endif
<
5249,5251d4119
< #ifdef MY_DEF_HERE
< truncate_inode:
< #endif
5253,5267d4120
< if (need_send_hole(sctx)) {
< if (sctx->cur_inode_last_extent == (u64)-1 ||
< sctx->cur_inode_last_extent <
< sctx->cur_inode_size) {
< ret = get_last_extent(sctx, (u64)-1);
< if (ret)
< goto out;
< }
< if (sctx->cur_inode_last_extent <
< sctx->cur_inode_size) {
< ret = send_hole(sctx, sctx->cur_inode_size);
< if (ret)
< goto out;
< }
< }
5287,5288c4140,4144
< #ifdef MY_DEF_HERE
< ret = syno_attribute_handler(sctx);
---
> /*
> * Need to send that every time, no matter if it actually changed
> * between the two trees as we have done changes to the inode before.
> */
> ret = send_utimes(sctx, sctx->cur_ino, sctx->cur_inode_gen);
5291,5307d4146
< #endif
<
< #ifdef MY_DEF_HERE
< if (sctx->phase != SEND_PHASE_COMPUTE_DATA_SIZE &&
< !is_waiting_for_move(sctx, sctx->cur_ino)) {
< #else
< if (!is_waiting_for_move(sctx, sctx->cur_ino)) {
< #endif
< ret = apply_children_dir_moves(sctx);
< if (ret)
< goto out;
<
< sctx->send_progress = sctx->cur_ino + 1;
< ret = send_utimes(sctx, sctx->cur_ino, sctx->cur_inode_gen);
< if (ret < 0)
< goto out;
< }
5322a4162,4165
> ret = close_cur_inode_file(sctx);
> if (ret < 0)
> goto out;
>
5325,5328d4167
< sctx->cur_inode_last_extent = (u64)-1;
< #ifdef MY_DEF_HERE
< sctx->cur_inode_archive = 0;
< #endif
5329a4169,4173
> /*
> * Set send_progress to current inode. This will tell all get_cur_xxx
> * functions that the current inode's refs are not updated yet. Later,
> * when process_recorded_refs is finished, it is set to cur_ino + 1.
> */
5353a4198,4202
> /*
> * The cur_ino = root dir case is special here. We can't treat
> * the inode as deleted+reused because it would generate a
> * stream that tries to delete/mkdir the root dir.
> */
5367,5372d4215
< sctx->cur_inode_rdev = btrfs_inode_rdev(
< sctx->left_path->nodes[0], left_ii);
< #ifdef MY_DEF_HERE
< if (sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID &&
< sctx->phase != SEND_PHASE_COMPUTE_DATA_SIZE)
< #else
5374d4216
< #endif
5385c4227,4233
<
---
> /*
> * We need to do some special handling in case the inode was
> * reported as changed with a changed generation number. This
> * means that the original inode was deleted and new inode
> * reused the same inum. So we have to treat the old inode as
> * deleted and the new one as new.
> */
5387,5390c4235,4237
<
< #ifdef MY_DEF_HERE
< if (sctx->phase != SEND_PHASE_COMPUTE_DATA_SIZE) {
< #endif
---
> /*
> * First, process the inode as if it was deleted.
> */
5402,5404d4248
< #ifdef MY_DEF_HERE
< }
< #endif
5405a4250,4252
> /*
> * Now process the inode as if it was new.
> */
5413,5417d4259
< sctx->cur_inode_rdev = btrfs_inode_rdev(
< sctx->left_path->nodes[0], left_ii);
< #ifdef MY_DEF_HERE
< if (sctx->phase != SEND_PHASE_COMPUTE_DATA_SIZE) {
< #endif
5420a4263
>
5424,5427c4267,4270
< #ifdef MY_DEF_HERE
< }
< #endif
<
---
> /*
> * Advance send_progress now as we did not get into
> * process_recorded_refs_if_needed in the new_gen case.
> */
5430,5442c4273,4276
< #ifdef MY_DEF_HERE
< if (sctx->phase == SEND_PHASE_COMPUTE_DATA_SIZE) {
< if (S_ISREG(sctx->cur_inode_mode)) {
< sctx->total_data_size += sctx->cur_inode_size;
< ret = write_calculate_size(sctx);
< if (ret < 0) {
< goto out;
< }
< }
<
< } else {
< #endif
<
---
> /*
> * Now process all extents and xattrs of the inode as if
> * they were all new.
> */
5449,5451d4282
< #ifdef MY_DEF_HERE
< }
< #endif
5467a4299,4308
> /*
> * We have to process new refs before deleted refs, but compare_trees gives us
> * the new and deleted refs mixed. To fix this, we record the new/deleted refs
> * first and later process them in process_recorded_refs.
> * For the cur_inode_new_gen case, we skip recording completely because
> * changed_inode did already initiate processing of refs. The reason for this is
> * that in this case, compare_tree actually compares the refs of 2 different
> * inodes. To fix this, process_all_refs is used in changed_inode to handle all
> * refs of the right tree as deleted and all refs of the left tree as new.
> */
5475,5481d4315
< #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
<
5494a4329,4333
> /*
> * Process new/deleted/changed xattrs. We skip processing in the
> * cur_inode_new_gen case because changed_inode did already initiate processing
> * of xattrs. The reason is the same as in changed_ref
> */
5502,5508d4340
< #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
<
5520a4353,4357
> /*
> * Process new/deleted/changed extents. We skip processing in the
> * cur_inode_new_gen case because changed_inode did already initiate processing
> * of extents. The reason is the same as in changed_ref
> */
5537,5593c4374,4377
< static int dir_changed(struct send_ctx *sctx, u64 dir)
< {
< u64 orig_gen, new_gen;
< int ret;
<
< ret = get_inode_info(sctx->send_root, dir, NULL, &new_gen, NULL, NULL,
< NULL, NULL);
< if (ret)
< return ret;
<
< ret = get_inode_info(sctx->parent_root, dir, NULL, &orig_gen, NULL,
< NULL, NULL, NULL);
< if (ret)
< return ret;
<
< return (orig_gen != new_gen) ? 1 : 0;
< }
<
< static int compare_refs(struct send_ctx *sctx, struct btrfs_path *path,
< struct btrfs_key *key)
< {
< struct btrfs_inode_extref *extref;
< struct extent_buffer *leaf;
< u64 dirid = 0, last_dirid = 0;
< unsigned long ptr;
< u32 item_size;
< u32 cur_offset = 0;
< int ref_name_len;
< int ret = 0;
<
< if (key->type == BTRFS_INODE_REF_KEY) {
< dirid = key->offset;
<
< ret = dir_changed(sctx, dirid);
< goto out;
< }
<
< leaf = path->nodes[0];
< item_size = btrfs_item_size_nr(leaf, path->slots[0]);
< ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
< while (cur_offset < item_size) {
< extref = (struct btrfs_inode_extref *)(ptr +
< cur_offset);
< dirid = btrfs_inode_extref_parent(leaf, extref);
< ref_name_len = btrfs_inode_extref_name_len(leaf, extref);
< cur_offset += ref_name_len + sizeof(*extref);
< if (dirid == last_dirid)
< continue;
< ret = dir_changed(sctx, dirid);
< if (ret)
< break;
< last_dirid = dirid;
< }
< out:
< return ret;
< }
<
---
> /*
> * Updates compare related fields in sctx and simply forwards to the actual
> * changed_xxx functions.
> */
5605,5626d4388
< if (result == BTRFS_COMPARE_TREE_SAME) {
< if (key->type == BTRFS_INODE_REF_KEY ||
< key->type == BTRFS_INODE_EXTREF_KEY) {
< #ifdef MY_DEF_HERE
< if (sctx->phase == SEND_PHASE_COMPUTE_DATA_SIZE) {
< return 0;
< }
< #endif
< ret = compare_refs(sctx, left_path, key);
< if (!ret)
< return 0;
< if (ret < 0)
< return ret;
< } else if (key->type == BTRFS_EXTENT_DATA_KEY) {
< return maybe_send_hole(sctx, left_path, key);
< } else {
< return 0;
< }
< result = BTRFS_COMPARE_TREE_CHANGED;
< ret = 0;
< }
<
5634a4397
> /* Ignore non-FS objects */
5655a4419
> struct btrfs_trans_handle *trans = NULL;
5661a4426,4427
> u64 start_ctransid;
> u64 ctransid;
5666a4433,4436
> spin_lock(&send_root->root_item_lock);
> start_ctransid = btrfs_root_ctransid(&send_root->root_item);
> spin_unlock(&send_root->root_item_lock);
>
5670a4441,4469
> join_trans:
> /*
> * We need to make sure the transaction does not get committed
> * while we do anything on commit roots. Join a transaction to prevent
> * this.
> */
> trans = btrfs_join_transaction(send_root);
> if (IS_ERR(trans)) {
> ret = PTR_ERR(trans);
> trans = NULL;
> goto out;
> }
>
> /*
> * Make sure the tree has not changed after re-joining. We detect this
> * by comparing start_ctransid and ctransid. They should always match.
> */
> spin_lock(&send_root->root_item_lock);
> ctransid = btrfs_root_ctransid(&send_root->root_item);
> spin_unlock(&send_root->root_item_lock);
>
> if (ctransid != start_ctransid) {
> WARN(1, KERN_WARNING "btrfs: the root that you're trying to "
> "send was modified in between. This is "
> "probably a bug.\n");
> ret = -EIO;
> goto out;
> }
>
5677a4477,4489
> /*
> * When someone want to commit while we iterate, end the
> * joined transaction and rejoin.
> */
> if (btrfs_should_end_transaction(trans, send_root)) {
> ret = btrfs_end_transaction(trans, send_root);
> trans = NULL;
> if (ret < 0)
> goto out;
> btrfs_release_path(path);
> goto join_trans;
> }
>
5705,5715c4517
< return ret;
< }
<
< #ifdef MY_DEF_HERE
< static int compute_total_data_size(struct send_ctx *sctx)
< {
< int ret;
<
< if (sctx->parent_root) {
< ret = btrfs_compare_trees(sctx->send_root, sctx->parent_root,
< changed_cb, sctx);
---
> if (trans) {
5717,5719c4519,4521
< ret = finish_inode_if_needed(sctx, 1);
< } else {
< ret = full_send_tree(sctx);
---
> ret = btrfs_end_transaction(trans, send_root);
> else
> btrfs_end_transaction(trans, send_root);
5721d4522
<
5724d4524
< #endif
5754a4555,4559
> if (!ret)
> ret = close_cur_inode_file(sctx);
> else
> close_cur_inode_file(sctx);
>
5759,5770d4563
< static void btrfs_root_dec_send_in_progress(struct btrfs_root* root)
< {
< spin_lock(&root->root_item_lock);
< root->send_in_progress--;
<
< if (root->send_in_progress < 0)
< btrfs_err(root->fs_info,
< "send_in_progres unbalanced %d root %llu",
< root->send_in_progress, root->root_key.objectid);
< spin_unlock(&root->root_item_lock);
< }
<
5782,5784d4574
< int clone_sources_to_rollback = 0;
< int sort_clone_roots = 0;
< int index;
5792,5802d4581
< spin_lock(&send_root->root_item_lock);
< send_root->send_in_progress++;
< spin_unlock(&send_root->root_item_lock);
<
< WARN_ON(send_root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE);
<
< if (!btrfs_root_readonly(send_root)) {
< ret = -EPERM;
< goto out;
< }
<
5811,5812c4590,4591
< sizeof(*arg->clone_sources) *
< arg->clone_sources_count)) {
---
> sizeof(*arg->clone_sources *
> arg->clone_sources_count))) {
5841,5857c4620
< sctx->send_root = send_root;
< #ifdef MY_DEF_HERE
< sctx->subvol_flags = BTRFS_I(file_inode(mnt_file))->flags;
< #endif
< #ifdef MY_DEF_HERE
< sctx->total_data_size = arg->total_data_size;
< do_gettimeofday(&sctx->write_timeval);
< #endif
< #ifdef MY_DEF_HERE
< sctx->skip_cmd_count = arg->skip_cmd_count;
< sctx->current_cmd_pos = 0;
< #endif
<
< if (btrfs_root_dead(sctx->send_root)) {
< ret = -EPERM;
< goto out;
< }
---
> sctx->mnt = mnt_file->f_path.mnt;
5858a4622
> sctx->send_root = send_root;
5874,5877d4637
< sctx->pending_dir_moves = RB_ROOT;
< sctx->waiting_dir_moves = RB_ROOT;
< sctx->orphan_dirs = RB_ROOT;
<
5905,5907d4664
<
< index = srcu_read_lock(&fs_info->subvol_srcu);
<
5909,5911c4666,4667
< if (IS_ERR(clone_root)) {
< srcu_read_unlock(&fs_info->subvol_srcu, index);
< ret = PTR_ERR(clone_root);
---
> if (!clone_root) {
> ret = -EINVAL;
5914,5919c4670,4671
< spin_lock(&clone_root->root_item_lock);
< if (!btrfs_root_readonly(clone_root) ||
< btrfs_root_dead(clone_root)) {
< spin_unlock(&clone_root->root_item_lock);
< srcu_read_unlock(&fs_info->subvol_srcu, index);
< ret = -EPERM;
---
> if (IS_ERR(clone_root)) {
> ret = PTR_ERR(clone_root);
5922,5925d4673
< clone_root->send_in_progress++;
< spin_unlock(&clone_root->root_item_lock);
< srcu_read_unlock(&fs_info->subvol_srcu, index);
<
5927d4674
< clone_sources_to_rollback = i + 1;
5937,5939d4683
<
< index = srcu_read_lock(&fs_info->subvol_srcu);
<
5941,5953c4685,4686
< if (IS_ERR(sctx->parent_root)) {
< srcu_read_unlock(&fs_info->subvol_srcu, index);
< ret = PTR_ERR(sctx->parent_root);
< goto out;
< }
<
< spin_lock(&sctx->parent_root->root_item_lock);
< sctx->parent_root->send_in_progress++;
< if (!btrfs_root_readonly(sctx->parent_root) ||
< btrfs_root_dead(sctx->parent_root)) {
< spin_unlock(&sctx->parent_root->root_item_lock);
< srcu_read_unlock(&fs_info->subvol_srcu, index);
< ret = -EPERM;
---
> if (!sctx->parent_root) {
> ret = -EINVAL;
5956,5958d4688
< spin_unlock(&sctx->parent_root->root_item_lock);
<
< srcu_read_unlock(&fs_info->subvol_srcu, index);
5960a4691,4695
> /*
> * Clones from send_root are allowed, but only if the clone source
> * is behind the current send position. This is checked while searching
> * for possible clone sources.
> */
5962a4698
> /* We do a bsearch later */
5966d4701
< sort_clone_roots = 1;
5968,5986d4702
< current->journal_info = (void *)BTRFS_SEND_TRANS_STUB;
<
< #ifdef MY_DEF_HERE
< g_verbose = arg->g_verbose;
< if (sctx->flags & BTRFS_SEND_FLAG_CALCULATE_DATA_SIZE) {
< sctx->phase = SEND_PHASE_COMPUTE_DATA_SIZE;
< ret = compute_total_data_size(sctx);
< if (ret < 0)
< goto out;
< arg->total_data_size = sctx->total_data_size;
< if (copy_to_user(arg_, arg, sizeof(*arg))) {
< ret = -EFAULT;
< goto out;
< }
< } else {
< sctx->phase = SEND_PHASE_STREAM_CHANGES;
< ret = send_subvol(sctx);
< }
< #else
5988,5989d4703
< #endif
< current->journal_info = NULL;
6003,6054d4716
< WARN_ON(sctx && !ret && !RB_EMPTY_ROOT(&sctx->pending_dir_moves));
< while (sctx && !RB_EMPTY_ROOT(&sctx->pending_dir_moves)) {
< struct rb_node *n;
< struct pending_dir_move *pm;
<
< n = rb_first(&sctx->pending_dir_moves);
< pm = rb_entry(n, struct pending_dir_move, node);
< while (!list_empty(&pm->list)) {
< struct pending_dir_move *pm2;
<
< pm2 = list_first_entry(&pm->list,
< struct pending_dir_move, list);
< free_pending_move(sctx, pm2);
< }
< free_pending_move(sctx, pm);
< }
<
< WARN_ON(sctx && !ret && !RB_EMPTY_ROOT(&sctx->waiting_dir_moves));
< while (sctx && !RB_EMPTY_ROOT(&sctx->waiting_dir_moves)) {
< struct rb_node *n;
< struct waiting_dir_move *dm;
<
< n = rb_first(&sctx->waiting_dir_moves);
< dm = rb_entry(n, struct waiting_dir_move, node);
< rb_erase(&dm->node, &sctx->waiting_dir_moves);
< kfree(dm);
< }
<
< WARN_ON(sctx && !ret && !RB_EMPTY_ROOT(&sctx->orphan_dirs));
< while (sctx && !RB_EMPTY_ROOT(&sctx->orphan_dirs)) {
< struct rb_node *n;
< struct orphan_dir_info *odi;
<
< n = rb_first(&sctx->orphan_dirs);
< odi = rb_entry(n, struct orphan_dir_info, node);
< free_orphan_dir_info(sctx, odi);
< }
<
< if (sort_clone_roots) {
< for (i = 0; i < sctx->clone_roots_cnt; i++)
< btrfs_root_dec_send_in_progress(
< sctx->clone_roots[i].root);
< } else {
< for (i = 0; sctx && i < clone_sources_to_rollback; i++)
< btrfs_root_dec_send_in_progress(
< sctx->clone_roots[i].root);
<
< btrfs_root_dec_send_in_progress(send_root);
< }
< if (sctx && !IS_ERR_OR_NULL(sctx->parent_root))
< btrfs_root_dec_send_in_progress(sctx->parent_root);
<
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment