Re: [RFC PATCH 6/6] btrfs: add chattr support for send/receive

2018-05-16 Thread Omar Sandoval
On Tue, May 08, 2018 at 10:06:51PM -0400, Howard McLauchlan wrote:
> From: Howard McLauchlan 
> 
> Presently btrfs send/receive does not propagate inode attribute flags;
> all chattr operations are effectively discarded upon transmission.
> 
> This patch adds kernel support for inode attribute flags. Userspace
> support can be found under the commit:
> 
> btrfs-progs: add chattr support for send/receive
> 
> An associated xfstest can be found at:
> 
> btrfs: add verify chattr support for send/receive test
> 
> These changes are only enabled for send stream version 2
> 
> Signed-off-by: Howard McLauchlan 
> ---
>  fs/btrfs/ctree.h |   2 +
>  fs/btrfs/ioctl.c |   2 +-
>  fs/btrfs/send.c  | 181 ---
>  fs/btrfs/send.h  |   4 +-
>  4 files changed, 159 insertions(+), 30 deletions(-)
> 
> diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> index 2771cc56a622..0a2359144b18 100644
> --- a/fs/btrfs/ctree.h
> +++ b/fs/btrfs/ctree.h
> @@ -1461,6 +1461,8 @@ struct btrfs_map_token {
>   unsigned long offset;
>  };
>  
> +unsigned int btrfs_flags_to_ioctl(unsigned int flags);
> +
>  #define BTRFS_BYTES_TO_BLKS(fs_info, bytes) \
>   ((bytes) >> (fs_info)->sb->s_blocksize_bits)
>  
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index 632e26d6f7ce..36ce1e589f9e 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -106,7 +106,7 @@ static unsigned int btrfs_mask_flags(umode_t mode, 
> unsigned int flags)
>  /*
>   * Export inode flags to the format expected by the FS_IOC_GETFLAGS ioctl.
>   */
> -static unsigned int btrfs_flags_to_ioctl(unsigned int flags)
> +unsigned int btrfs_flags_to_ioctl(unsigned int flags)
>  {
>   unsigned int iflags = 0;
>  
> diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
> index c8ea1ccaa3d8..fa7db1474a7f 100644
> --- a/fs/btrfs/send.c
> +++ b/fs/btrfs/send.c
> @@ -108,6 +108,13 @@ struct send_ctx {
>   u64 cur_inode_last_extent;
>   u64 cur_inode_next_write_offset;
>  
> + /*
> +  * state for chattr purposes
> +  */
> + u64 cur_inode_flip_flags;
> + u64 cur_inode_receive_flags;
> + int receive_flags_valid;

I'd use bool here (and change the places that set it to use true or
false).

> +
>   u64 send_progress;
>   u64 total_data_size;
>  
> @@ -815,7 +822,7 @@ static int send_rmdir(struct send_ctx *sctx, struct 
> fs_path *path)
>   */
>  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)
> +   u64 *gid, u64 *rdev, u64 *flags)
>  {
>   int ret;
>   struct btrfs_inode_item *ii;
> @@ -845,6 +852,8 @@ static int __get_inode_info(struct btrfs_root *root, 
> struct btrfs_path *path,
>   *gid = btrfs_inode_gid(path->nodes[0], ii);
>   if (rdev)
>   *rdev = btrfs_inode_rdev(path->nodes[0], ii);
> + if (flags)
> + *flags = btrfs_inode_flags(path->nodes[0], ii);
>  
>   return ret;
>  }
> @@ -852,7 +861,7 @@ static int __get_inode_info(struct btrfs_root *root, 
> struct btrfs_path *path,
>  static int get_inode_info(struct btrfs_root *root,
> u64 ino, u64 *size, u64 *gen,
> u64 *mode, u64 *uid, u64 *gid,
> -   u64 *rdev)
> +   u64 *rdev, u64 *flags)
>  {
>   struct btrfs_path *path;
>   int ret;
> @@ -861,7 +870,7 @@ static int get_inode_info(struct btrfs_root *root,
>   if (!path)
>   return -ENOMEM;
>   ret = __get_inode_info(root, path, ino, size, gen, mode, uid, gid,
> -rdev);
> +rdev, flags);
>   btrfs_free_path(path);
>   return ret;
>  }
> @@ -1250,7 +1259,7 @@ static int __iterate_backrefs(u64 ino, u64 offset, u64 
> root, void *ctx_)
>* accept clones from these extents.
>*/
>   ret = __get_inode_info(found->root, bctx->path, ino, &i_size, NULL, 
> NULL,
> -NULL, NULL, NULL);
> +NULL, NULL, NULL, NULL);
>   btrfs_release_path(bctx->path);
>   if (ret < 0)
>   return ret;
> @@ -1610,7 +1619,7 @@ static int get_cur_inode_state(struct send_ctx *sctx, 
> u64 ino, u64 gen)
>   u64 right_gen;
>  
>   ret = get_inode_info(sctx->send_root, ino, NULL, &left_gen, NULL, NULL,
> - NULL, NULL);
> + NULL, NULL, NULL);
>   if (ret < 0 && ret != -ENOENT)
>   goto out;
>   left_ret = ret;
> @@ -1619,7 +1628,7 @@ static int get_cur_inode_state(struct send_ctx *sctx, 
> u64 ino, u64 gen)
>   right_ret = -ENOENT;
>   } else {
>   ret = get_inode_info(sctx->parent_root, ino, NULL, &right_gen,
> - NULL, NULL, NULL, NULL);
> + NULL, NULL, N

[RFC PATCH 6/6] btrfs: add chattr support for send/receive

2018-05-08 Thread Howard McLauchlan
From: Howard McLauchlan 

Presently btrfs send/receive does not propagate inode attribute flags;
all chattr operations are effectively discarded upon transmission.

This patch adds kernel support for inode attribute flags. Userspace
support can be found under the commit:

btrfs-progs: add chattr support for send/receive

An associated xfstest can be found at:

btrfs: add verify chattr support for send/receive test

These changes are only enabled for send stream version 2

Signed-off-by: Howard McLauchlan 
---
 fs/btrfs/ctree.h |   2 +
 fs/btrfs/ioctl.c |   2 +-
 fs/btrfs/send.c  | 181 ---
 fs/btrfs/send.h  |   4 +-
 4 files changed, 159 insertions(+), 30 deletions(-)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 2771cc56a622..0a2359144b18 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1461,6 +1461,8 @@ struct btrfs_map_token {
unsigned long offset;
 };
 
+unsigned int btrfs_flags_to_ioctl(unsigned int flags);
+
 #define BTRFS_BYTES_TO_BLKS(fs_info, bytes) \
((bytes) >> (fs_info)->sb->s_blocksize_bits)
 
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 632e26d6f7ce..36ce1e589f9e 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -106,7 +106,7 @@ static unsigned int btrfs_mask_flags(umode_t mode, unsigned 
int flags)
 /*
  * Export inode flags to the format expected by the FS_IOC_GETFLAGS ioctl.
  */
-static unsigned int btrfs_flags_to_ioctl(unsigned int flags)
+unsigned int btrfs_flags_to_ioctl(unsigned int flags)
 {
unsigned int iflags = 0;
 
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index c8ea1ccaa3d8..fa7db1474a7f 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -108,6 +108,13 @@ struct send_ctx {
u64 cur_inode_last_extent;
u64 cur_inode_next_write_offset;
 
+   /*
+* state for chattr purposes
+*/
+   u64 cur_inode_flip_flags;
+   u64 cur_inode_receive_flags;
+   int receive_flags_valid;
+
u64 send_progress;
u64 total_data_size;
 
@@ -815,7 +822,7 @@ static int send_rmdir(struct send_ctx *sctx, struct fs_path 
*path)
  */
 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)
+ u64 *gid, u64 *rdev, u64 *flags)
 {
int ret;
struct btrfs_inode_item *ii;
@@ -845,6 +852,8 @@ static int __get_inode_info(struct btrfs_root *root, struct 
btrfs_path *path,
*gid = btrfs_inode_gid(path->nodes[0], ii);
if (rdev)
*rdev = btrfs_inode_rdev(path->nodes[0], ii);
+   if (flags)
+   *flags = btrfs_inode_flags(path->nodes[0], ii);
 
return ret;
 }
@@ -852,7 +861,7 @@ static int __get_inode_info(struct btrfs_root *root, struct 
btrfs_path *path,
 static int get_inode_info(struct btrfs_root *root,
  u64 ino, u64 *size, u64 *gen,
  u64 *mode, u64 *uid, u64 *gid,
- u64 *rdev)
+ u64 *rdev, u64 *flags)
 {
struct btrfs_path *path;
int ret;
@@ -861,7 +870,7 @@ static int get_inode_info(struct btrfs_root *root,
if (!path)
return -ENOMEM;
ret = __get_inode_info(root, path, ino, size, gen, mode, uid, gid,
-  rdev);
+  rdev, flags);
btrfs_free_path(path);
return ret;
 }
@@ -1250,7 +1259,7 @@ static int __iterate_backrefs(u64 ino, u64 offset, u64 
root, void *ctx_)
 * accept clones from these extents.
 */
ret = __get_inode_info(found->root, bctx->path, ino, &i_size, NULL, 
NULL,
-  NULL, NULL, NULL);
+  NULL, NULL, NULL, NULL);
btrfs_release_path(bctx->path);
if (ret < 0)
return ret;
@@ -1610,7 +1619,7 @@ static int get_cur_inode_state(struct send_ctx *sctx, u64 
ino, u64 gen)
u64 right_gen;
 
ret = get_inode_info(sctx->send_root, ino, NULL, &left_gen, NULL, NULL,
-   NULL, NULL);
+   NULL, NULL, NULL);
if (ret < 0 && ret != -ENOENT)
goto out;
left_ret = ret;
@@ -1619,7 +1628,7 @@ static int get_cur_inode_state(struct send_ctx *sctx, u64 
ino, u64 gen)
right_ret = -ENOENT;
} else {
ret = get_inode_info(sctx->parent_root, ino, NULL, &right_gen,
-   NULL, NULL, NULL, NULL);
+   NULL, NULL, NULL, NULL, NULL);
if (ret < 0 && ret != -ENOENT)
goto out;
right_ret = ret;
@@ -1788,7 +1797,7 @@ static int get_first_ref(struct btrfs_root *root, u64 ino,
 
if (dir_gen) {
ret = get_inode_info(root, parent_dir, NULL, dir_