Re: [PATCH] Btrfs: RENAME_EXCHANGE semantic for renameat2()
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()
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, +