return ret;
  }
  
 +static long btrfs_ioctl_quota_ctl(struct btrfs_root *root, void __user *arg)
 +{
 +      struct btrfs_ioctl_quota_ctl_args *sa;
 +      struct btrfs_trans_handle *trans = NULL;
 +      int ret;
 +      int err;
 +
 +      if (!capable(CAP_SYS_ADMIN))
 +              return -EPERM;
 +
 +      if (root->fs_info->sb->s_flags & MS_RDONLY)
 +              return -EROFS;
 +
 +      sa = memdup_user(arg, sizeof(*sa));
 +      if (IS_ERR(sa))
 +              return PTR_ERR(sa);
 +
 +      if (sa->cmd != BTRFS_QUOTA_CTL_RESCAN) {
 +              trans = btrfs_start_transaction(root, 2);
 +              if (IS_ERR(trans)) {
 +                      ret = PTR_ERR(trans);
 +                      goto out;
 +              }
 +      }
 +
 +      switch (sa->cmd) {
 +      case BTRFS_QUOTA_CTL_ENABLE:
 +              ret = btrfs_quota_enable(trans, root->fs_info);
 +              break;
 +      case BTRFS_QUOTA_CTL_DISABLE:
 +              ret = btrfs_quota_disable(trans, root->fs_info);
 +              break;
 +      case BTRFS_QUOTA_CTL_RESCAN:
 +              ret = btrfs_quota_rescan(root->fs_info);
 +              break;
 +      default:
 +              ret = -EINVAL;
 +              break;
 +      }
 +
 +      if (copy_to_user(arg, sa, sizeof(*sa)))
 +              ret = -EFAULT;
 +
 +      if (trans) {
 +              err = btrfs_commit_transaction(trans, root);
 +              if (err && !ret)
 +                      ret = err;
 +      }
 +
 +out:
 +      kfree(sa);
 +      return ret;
 +}
 +
 +static long btrfs_ioctl_qgroup_assign(struct btrfs_root *root, void __user *arg)
 +{
 +      struct btrfs_ioctl_qgroup_assign_args *sa;
 +      struct btrfs_trans_handle *trans;
 +      int ret;
 +      int err;
 +
 +      if (!capable(CAP_SYS_ADMIN))
 +              return -EPERM;
 +
 +      if (root->fs_info->sb->s_flags & MS_RDONLY)
 +              return -EROFS;
 +
 +      sa = memdup_user(arg, sizeof(*sa));
 +      if (IS_ERR(sa))
 +              return PTR_ERR(sa);
 +
 +      trans = btrfs_join_transaction(root);
 +      if (IS_ERR(trans)) {
 +              ret = PTR_ERR(trans);
 +              goto out;
 +      }
 +
 +      /* FIXME: check if the IDs really exist */
 +      if (sa->assign) {
 +              ret = btrfs_add_qgroup_relation(trans, root->fs_info,
 +                                              sa->src, sa->dst);
 +      } else {
 +              ret = btrfs_del_qgroup_relation(trans, root->fs_info,
 +                                              sa->src, sa->dst);
 +      }
 +
 +      err = btrfs_end_transaction(trans, root);
 +      if (err && !ret)
 +              ret = err;
 +
 +out:
 +      kfree(sa);
 +      return ret;
 +}
 +
 +static long btrfs_ioctl_qgroup_create(struct btrfs_root *root, void __user *arg)
 +{
 +      struct btrfs_ioctl_qgroup_create_args *sa;
 +      struct btrfs_trans_handle *trans;
 +      int ret;
 +      int err;
 +
 +      if (!capable(CAP_SYS_ADMIN))
 +              return -EPERM;
 +
 +      if (root->fs_info->sb->s_flags & MS_RDONLY)
 +              return -EROFS;
 +
 +      sa = memdup_user(arg, sizeof(*sa));
 +      if (IS_ERR(sa))
 +              return PTR_ERR(sa);
 +
 +      trans = btrfs_join_transaction(root);
 +      if (IS_ERR(trans)) {
 +              ret = PTR_ERR(trans);
 +              goto out;
 +      }
 +
 +      /* FIXME: check if the IDs really exist */
 +      if (sa->create) {
 +              ret = btrfs_create_qgroup(trans, root->fs_info, sa->qgroupid,
 +                                        NULL);
 +      } else {
 +              ret = btrfs_remove_qgroup(trans, root->fs_info, sa->qgroupid);
 +      }
 +
 +      err = btrfs_end_transaction(trans, root);
 +      if (err && !ret)
 +              ret = err;
 +
 +out:
 +      kfree(sa);
 +      return ret;
 +}
 +
 +static long btrfs_ioctl_qgroup_limit(struct btrfs_root *root, void __user *arg)
 +{
 +      struct btrfs_ioctl_qgroup_limit_args *sa;
 +      struct btrfs_trans_handle *trans;
 +      int ret;
 +      int err;
 +      u64 qgroupid;
 +
 +      if (!capable(CAP_SYS_ADMIN))
 +              return -EPERM;
 +
 +      if (root->fs_info->sb->s_flags & MS_RDONLY)
 +              return -EROFS;
 +
 +      sa = memdup_user(arg, sizeof(*sa));
 +      if (IS_ERR(sa))
 +              return PTR_ERR(sa);
 +
 +      trans = btrfs_join_transaction(root);
 +      if (IS_ERR(trans)) {
 +              ret = PTR_ERR(trans);
 +              goto out;
 +      }
 +
 +      qgroupid = sa->qgroupid;
 +      if (!qgroupid) {
 +              /* take the current subvol as qgroup */
 +              qgroupid = root->root_key.objectid;
 +      }
 +
 +      /* FIXME: check if the IDs really exist */
 +      ret = btrfs_limit_qgroup(trans, root->fs_info, qgroupid, &sa->lim);
 +
 +      err = btrfs_end_transaction(trans, root);
 +      if (err && !ret)
 +              ret = err;
 +
 +out:
 +      kfree(sa);
 +      return ret;
 +}
 +
+ static long btrfs_ioctl_set_received_subvol(struct file *file,
+                                           void __user *arg)
+ {
+       struct btrfs_ioctl_received_subvol_args *sa = NULL;
+       struct inode *inode = fdentry(file)->d_inode;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_root_item *root_item = &root->root_item;
+       struct btrfs_trans_handle *trans;
+       struct timespec ct = CURRENT_TIME;
+       int ret = 0;
+ 
+       ret = mnt_want_write_file(file);
+       if (ret < 0)
+               return ret;
+ 
+       down_write(&root->fs_info->subvol_sem);
+ 
+       if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) {
+               ret = -EINVAL;
+               goto out;
+       }
+ 
+       if (btrfs_root_readonly(root)) {
+               ret = -EROFS;
+               goto out;
+       }
+ 
+       if (!inode_owner_or_capable(inode)) {
+               ret = -EACCES;
+               goto out;
+       }
+ 
+       sa = memdup_user(arg, sizeof(*sa));
+       if (IS_ERR(sa)) {
+               ret = PTR_ERR(sa);
+               sa = NULL;
+               goto out;
+       }
+ 
+       trans = btrfs_start_transaction(root, 1);
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               trans = NULL;
+               goto out;
+       }
+ 
+       sa->rtransid = trans->transid;
+       sa->rtime.sec = ct.tv_sec;
+       sa->rtime.nsec = ct.tv_nsec;
+ 
+       memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE);
+       btrfs_set_root_stransid(root_item, sa->stransid);
+       btrfs_set_root_rtransid(root_item, sa->rtransid);
+       root_item->stime.sec = cpu_to_le64(sa->stime.sec);
+       root_item->stime.nsec = cpu_to_le32(sa->stime.nsec);
+       root_item->rtime.sec = cpu_to_le64(sa->rtime.sec);
+       root_item->rtime.nsec = cpu_to_le32(sa->rtime.nsec);
+ 
+       ret = btrfs_update_root(trans, root->fs_info->tree_root,
+                               &root->root_key, &root->root_item);
+       if (ret < 0) {
+               btrfs_end_transaction(trans, root);
+               trans = NULL;
+               goto out;
+       } else {
+               ret = btrfs_commit_transaction(trans, root);
+               if (ret < 0)
+                       goto out;
+       }
+ 
+       ret = copy_to_user(arg, sa, sizeof(*sa));
+       if (ret)
+               ret = -EFAULT;
+ 
+ out:
+       kfree(sa);
+       up_write(&root->fs_info->subvol_sem);
+       mnt_drop_write_file(file);
+       return ret;
+ }
+ 
  long btrfs_ioctl(struct file *file, unsigned int
                cmd, unsigned long arg)
  {
                return btrfs_ioctl_balance_ctl(root, arg);
        case BTRFS_IOC_BALANCE_PROGRESS:
                return btrfs_ioctl_balance_progress(root, argp);
+       case BTRFS_IOC_SET_RECEIVED_SUBVOL:
+               return btrfs_ioctl_set_received_subvol(file, argp);
+       case BTRFS_IOC_SEND:
+               return btrfs_ioctl_send(file, argp);
        case BTRFS_IOC_GET_DEV_STATS:
 -              return btrfs_ioctl_get_dev_stats(root, argp, 0);
 -      case BTRFS_IOC_GET_AND_RESET_DEV_STATS:
 -              return btrfs_ioctl_get_dev_stats(root, argp, 1);
 +              return btrfs_ioctl_get_dev_stats(root, argp);
 +      case BTRFS_IOC_QUOTA_CTL:
 +              return btrfs_ioctl_quota_ctl(root, argp);
 +      case BTRFS_IOC_QGROUP_ASSIGN:
 +              return btrfs_ioctl_qgroup_assign(root, argp);
 +      case BTRFS_IOC_QGROUP_CREATE:
 +              return btrfs_ioctl_qgroup_create(root, argp);
 +      case BTRFS_IOC_QGROUP_LIMIT:
 +              return btrfs_ioctl_qgroup_limit(root, argp);
        }
  
        return -ENOTTY;
 
        __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */
  };
  
 +#define BTRFS_QUOTA_CTL_ENABLE        1
 +#define BTRFS_QUOTA_CTL_DISABLE       2
 +#define BTRFS_QUOTA_CTL_RESCAN        3
 +struct btrfs_ioctl_quota_ctl_args {
 +      __u64 cmd;
 +      __u64 status;
 +};
 +
 +struct btrfs_ioctl_qgroup_assign_args {
 +      __u64 assign;
 +      __u64 src;
 +      __u64 dst;
 +};
 +
 +struct btrfs_ioctl_qgroup_create_args {
 +      __u64 create;
 +      __u64 qgroupid;
 +};
+ struct btrfs_ioctl_timespec {
+       __u64 sec;
+       __u32 nsec;
+ };
+ 
+ struct btrfs_ioctl_received_subvol_args {
+       char    uuid[BTRFS_UUID_SIZE];  /* in */
+       __u64   stransid;               /* in */
+       __u64   rtransid;               /* out */
+       struct btrfs_ioctl_timespec stime; /* in */
+       struct btrfs_ioctl_timespec rtime; /* out */
+       __u64   flags;                  /* in */
+       __u64   reserved[16];           /* in */
+ };
+ 
+ struct btrfs_ioctl_send_args {
+       __s64 send_fd;                  /* in */
+       __u64 clone_sources_count;      /* in */
+       __u64 __user *clone_sources;    /* in */
+       __u64 parent_root;              /* in */
+       __u64 flags;                    /* in */
+       __u64 reserved[4];              /* in */
+ };
  
  #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
                                   struct btrfs_ioctl_vol_args)
                                        struct btrfs_ioctl_ino_path_args)
  #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
                                        struct btrfs_ioctl_ino_path_args)
+ #define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \
+                               struct btrfs_ioctl_received_subvol_args)
+ #define BTRFS_IOC_SEND _IOW(BTRFS_IOCTL_MAGIC, 38, struct btrfs_ioctl_send_args)
 +#define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \
 +                                   struct btrfs_ioctl_vol_args)
 +#define BTRFS_IOC_QUOTA_CTL _IOWR(BTRFS_IOCTL_MAGIC, 40, \
 +                             struct btrfs_ioctl_quota_ctl_args)
 +#define BTRFS_IOC_QGROUP_ASSIGN _IOW(BTRFS_IOCTL_MAGIC, 41, \
 +                             struct btrfs_ioctl_qgroup_assign_args)
 +#define BTRFS_IOC_QGROUP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 42, \
 +                             struct btrfs_ioctl_qgroup_create_args)
 +#define BTRFS_IOC_QGROUP_LIMIT _IOR(BTRFS_IOCTL_MAGIC, 43, \
 +                             struct btrfs_ioctl_qgroup_limit_args)
  #define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \
                                      struct btrfs_ioctl_get_dev_stats)
 -#define BTRFS_IOC_GET_AND_RESET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 53, \
 -                                      struct btrfs_ioctl_get_dev_stats)
 -
  #endif