Re: [PATCH] Btrfs: RENAME_EXCHANGE semantic for renameat2()

2015-04-02 Thread Filipe David Manana
On Thu, Apr 2, 2015 at 4:56 AM, Davide Italiano  wrote:
> Signed-off-by: Davide Italiano 

Hi, only skimmed through it, a few small comments below.
I haven't surely tested it as well (I assume you ran all xfstests from
the generic group).
Thanks.

> ---
>  fs/btrfs/inode.c | 190 
> ++-
>  1 file changed, 189 insertions(+), 1 deletion(-)
>
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index d2e732d..49b0867 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -8890,6 +8890,190 @@ static int btrfs_getattr(struct vfsmount *mnt,
> return 0;
>  }
>
> +static int btrfs_cross_rename(struct inode *old_dir, struct dentry 
> *old_dentry,
> + struct inode *new_dir, struct dentry 
> *new_dentry)
> +{
> +   struct btrfs_trans_handle *trans;
> +   struct btrfs_root *root = BTRFS_I(old_dir)->root;
> +   struct btrfs_root *dest = BTRFS_I(new_dir)->root;
> +   struct inode *new_inode = new_dentry->d_inode;
> +   struct inode *old_inode = old_dentry->d_inode;
> +   struct timespec ctime = CURRENT_TIME;
> +   u64 old_ino = btrfs_ino(old_inode);
> +   u64 new_ino = btrfs_ino(new_inode);
> +   u64 old_idx = 0;
> +   u64 new_idx = 0;
> +   u64 root_objectid;
> +   int ret;
> +
> +   /* we only allow rename subvolume link between subvolumes */
> +   if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest)
> +   return -EXDEV;
> +
> +   /* close the racy window with snapshot create/destroy ioctl */
> +   if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
> +   down_read(&root->fs_info->subvol_sem);
> +   if (new_ino == BTRFS_FIRST_FREE_OBJECTID)
> +   down_read(&dest->fs_info->subvol_sem);
> +
> +   /*
> +* We want to reserve the absolute worst case amount of items.  So if
> +* both inodes are subvols and we need to unlink them then that would
> +* require 4 item modifications, but if they are both normal inodes it
> +* would require 5 item modifications, so we'll assume their normal
> +* inodes.  So 5 * 2 is 10, plus 2 for the new links, so 12 total 
> items
> +* should cover the worst case number of items we'll modify.
> +*/
> +   trans = btrfs_start_transaction(root, 12);
> +   if (IS_ERR(trans)) {
> +ret = PTR_ERR(trans);
> +goto out_notrans;
> +}
> +
> +   /*
> +* We need to find a free sequence number both in the source and
> +* in the destination directory for the exchange.
> +*/
> +   ret = btrfs_set_inode_index(new_dir, &old_idx);
> +   if (ret)
> +   goto out_fail;
> +   ret = btrfs_set_inode_index(old_dir, &new_idx);
> +   if (ret)
> +   goto out_fail;
> +
> +   BTRFS_I(old_inode)->dir_index = 0ULL;
> +   BTRFS_I(new_inode)->dir_index = 0ULL;
> +
> +   /* Reference for the source. */
> +   if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) {
> +   /* force full log commit if subvolume involved. */
> +   btrfs_set_log_full_commit(root->fs_info, trans);
> +   } else {
> +   ret = btrfs_insert_inode_ref(trans, dest,
> +new_dentry->d_name.name,
> +new_dentry->d_name.len,
> +old_ino,
> +btrfs_ino(new_dir), old_idx);
> +   if (ret)
> +   goto out_fail;
> +   btrfs_pin_log_trans(root);
> +   }
> +
> +   /* And now for the dest. */
> +   if (unlikely(new_ino == BTRFS_FIRST_FREE_OBJECTID)) {
> +   /* force full log commit if subvolume involved. */
> +   btrfs_set_log_full_commit(dest->fs_info, trans);
> +   } else {
> +   ret = btrfs_insert_inode_ref(trans, root,
> +old_dentry->d_name.name,
> +old_dentry->d_name.len,
> +new_ino,
> +btrfs_ino(old_dir), new_idx);
> +   if (ret)
> +   goto out_fail;
> +   btrfs_pin_log_trans(dest);
> +   }
> +
> +   /*
> +* Update i-node version and ctime/mtime.
> +*/
> +   inode_inc_iversion(old_dir);
> +   inode_inc_iversion(new_dir);
> +   inode_inc_iversion(old_inode);
> +   inode_inc_iversion(new_inode);
> +   old_dir->i_ctime = old_dir->i_mtime = ctime;
> +   new_dir->i_ctime = new_dir->i_mtime = ctime;
> +   old_inode->i_ctime = ctime;
> +   new_inode->i_ctime = ctime;
> +
> +   if (old_dentry->d_parent != new_dentry->d_parent) {
> +   btrfs_record_unlink_dir(trans, old_dir, old_inode, 1);
> +   btrfs

[PATCH] Btrfs: RENAME_EXCHANGE semantic for renameat2()

2015-04-01 Thread Davide Italiano
Signed-off-by: Davide Italiano 
---
 fs/btrfs/inode.c | 190 ++-
 1 file changed, 189 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index d2e732d..49b0867 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -8890,6 +8890,190 @@ static int btrfs_getattr(struct vfsmount *mnt,
return 0;
 }
 
+static int btrfs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+   struct btrfs_trans_handle *trans;
+   struct btrfs_root *root = BTRFS_I(old_dir)->root;
+   struct btrfs_root *dest = BTRFS_I(new_dir)->root;
+   struct inode *new_inode = new_dentry->d_inode;
+   struct inode *old_inode = old_dentry->d_inode;
+   struct timespec ctime = CURRENT_TIME;
+   u64 old_ino = btrfs_ino(old_inode);
+   u64 new_ino = btrfs_ino(new_inode);
+   u64 old_idx = 0;
+   u64 new_idx = 0;
+   u64 root_objectid;
+   int ret;
+
+   /* we only allow rename subvolume link between subvolumes */
+   if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest)
+   return -EXDEV;
+
+   /* close the racy window with snapshot create/destroy ioctl */
+   if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
+   down_read(&root->fs_info->subvol_sem);
+   if (new_ino == BTRFS_FIRST_FREE_OBJECTID)
+   down_read(&dest->fs_info->subvol_sem);
+
+   /*
+* We want to reserve the absolute worst case amount of items.  So if
+* both inodes are subvols and we need to unlink them then that would
+* require 4 item modifications, but if they are both normal inodes it
+* would require 5 item modifications, so we'll assume their normal
+* inodes.  So 5 * 2 is 10, plus 2 for the new links, so 12 total items
+* should cover the worst case number of items we'll modify.
+*/
+   trans = btrfs_start_transaction(root, 12);
+   if (IS_ERR(trans)) {
+ret = PTR_ERR(trans);
+goto out_notrans;
+}
+
+   /*
+* We need to find a free sequence number both in the source and
+* in the destination directory for the exchange.
+*/
+   ret = btrfs_set_inode_index(new_dir, &old_idx);
+   if (ret)
+   goto out_fail;
+   ret = btrfs_set_inode_index(old_dir, &new_idx);
+   if (ret)
+   goto out_fail;
+
+   BTRFS_I(old_inode)->dir_index = 0ULL;
+   BTRFS_I(new_inode)->dir_index = 0ULL;
+
+   /* Reference for the source. */
+   if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) {
+   /* force full log commit if subvolume involved. */
+   btrfs_set_log_full_commit(root->fs_info, trans);
+   } else {
+   ret = btrfs_insert_inode_ref(trans, dest,
+new_dentry->d_name.name,
+new_dentry->d_name.len,
+old_ino,
+btrfs_ino(new_dir), old_idx);
+   if (ret)
+   goto out_fail;
+   btrfs_pin_log_trans(root);
+   }
+
+   /* And now for the dest. */
+   if (unlikely(new_ino == BTRFS_FIRST_FREE_OBJECTID)) {
+   /* force full log commit if subvolume involved. */
+   btrfs_set_log_full_commit(dest->fs_info, trans);
+   } else {
+   ret = btrfs_insert_inode_ref(trans, root,
+old_dentry->d_name.name,
+old_dentry->d_name.len,
+new_ino,
+btrfs_ino(old_dir), new_idx);
+   if (ret)
+   goto out_fail;
+   btrfs_pin_log_trans(dest);
+   }
+
+   /*
+* Update i-node version and ctime/mtime.
+*/
+   inode_inc_iversion(old_dir);
+   inode_inc_iversion(new_dir);
+   inode_inc_iversion(old_inode);
+   inode_inc_iversion(new_inode);
+   old_dir->i_ctime = old_dir->i_mtime = ctime;
+   new_dir->i_ctime = new_dir->i_mtime = ctime;
+   old_inode->i_ctime = ctime;
+   new_inode->i_ctime = ctime;
+
+   if (old_dentry->d_parent != new_dentry->d_parent) {
+   btrfs_record_unlink_dir(trans, old_dir, old_inode, 1);
+   btrfs_record_unlink_dir(trans, new_dir, new_inode, 1);
+   }
+
+   /* src is a subvolume */
+   if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) {
+   root_objectid = BTRFS_I(old_inode)->root->root_key.objectid;
+   ret = btrfs_unlink_subvol(trans, root, old_dir,
+ root_objectid,
+ old_dentry->d_name.name,
+