From: Miklos Szeredi <miklos@szeredi.hu>
To: viro@ZenIV.linux.org.uk
Cc: torvalds@linux-foundation.org, linux-fsdevel@vger.kernel.org,
linux-kernel@vger.kernel.org, hch@infradead.org,
akpm@linux-foundation.org, dhowells@redhat.com, zab@redhat.com,
jack@suse.cz, luto@amacapital.net, mszeredi@suse.cz
Subject: [PATCH 11/11] ext4: add cross rename support
Date: Wed, 8 Jan 2014 23:10:15 +0100 [thread overview]
Message-ID: <1389219015-10980-12-git-send-email-miklos@szeredi.hu> (raw)
In-Reply-To: <1389219015-10980-1-git-send-email-miklos@szeredi.hu>
From: Miklos Szeredi <mszeredi@suse.cz>
Implement RENAME_EXCHANGE flag in renameat2 syscall.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
fs/ext4/namei.c | 121 ++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 87 insertions(+), 34 deletions(-)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 7147d08a43a2..e4513ba7ed99 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3005,6 +3005,8 @@ struct ext4_renament {
struct inode *dir;
struct dentry *dentry;
struct inode *inode;
+ bool is_dir;
+ int dir_nlink_delta;
/* entry for "dentry" */
struct buffer_head *bh;
@@ -3136,6 +3138,14 @@ static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent)
}
}
+static void ext4_update_dir_count(handle_t *handle, struct ext4_renament *ent)
+{
+ if (ent->dir_nlink_delta == -1)
+ ext4_dec_count(handle, ent->dir);
+ else if (ent->dir_nlink_delta == 1)
+ ext4_inc_count(handle, ent->dir);
+}
+
/*
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
@@ -3161,7 +3171,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
};
int retval;
- if (flags & ~RENAME_NOREPLACE)
+ if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
return -EOPNOTSUPP;
dquot_initialize(old.dir);
@@ -3169,10 +3179,11 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
/* Initialize quotas before so that eventual writes go
* in separate transaction */
- if (new.inode)
+ if (!(flags & RENAME_EXCHANGE) && new.inode)
dquot_initialize(new.inode);
- old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
+ old.bh = ext4_find_entry(old.dir, &old.dentry->d_name,
+ &old.de, &old.inlined);
/*
* Check for inode number is _not_ due to possible IO errors.
* We might rmdir the source, keep it as pwd of some process
@@ -3185,18 +3196,22 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
&new.de, &new.inlined);
- if (new.bh) {
- if (!new.inode) {
- brelse(new.bh);
- new.bh = NULL;
+ if (!(flags & RENAME_EXCHANGE)) {
+ if (new.bh) {
+ if (!new.inode) {
+ brelse(new.bh);
+ new.bh = NULL;
+ }
}
+ if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC))
+ ext4_alloc_da_blocks(old.inode);
+ } else if (!new.bh || le32_to_cpu(new.de->inode) != new.inode->i_ino) {
+ goto end_rename;
}
- if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC))
- ext4_alloc_da_blocks(old.inode);
handle = ext4_journal_start(old.dir, EXT4_HT_DIR,
(2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) +
- EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2));
+ 2 * EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2));
if (IS_ERR(handle))
return PTR_ERR(handle);
@@ -3204,28 +3219,61 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
ext4_handle_sync(handle);
if (S_ISDIR(old.inode->i_mode)) {
- if (new.inode) {
+ old.is_dir = true;
+ if (!(flags & RENAME_EXCHANGE) && new.inode) {
retval = -ENOTEMPTY;
if (!empty_dir(new.inode))
goto end_rename;
- } else {
- retval = -EMLINK;
- if (new.dir != old.dir && EXT4_DIR_LINK_MAX(new.dir))
- goto end_rename;
+
+ /*
+ * Overwriting a directory needs to decrement nlink of
+ * old parent (even if not cross directory rename).
+ */
+ old.dir_nlink_delta = -1;
}
retval = ext4_rename_dir_prepare(handle, &old);
if (retval)
goto end_rename;
}
+ if (new.inode && S_ISDIR(new.inode->i_mode)) {
+ new.is_dir = true;
+ if (flags & RENAME_EXCHANGE) {
+ retval = ext4_rename_dir_prepare(handle, &new);
+ if (retval)
+ goto end_rename;
+ }
+ }
+
+ /*
+ * Other than the special case of overwring a directory, parents' nlink
+ * only needs to be modified if this is a cross directory rename.
+ */
+ if (old.dir != new.dir && old.is_dir != new.is_dir) {
+ old.dir_nlink_delta = old.is_dir ? -1 : 1;
+ new.dir_nlink_delta = -old.dir_nlink_delta;
+ retval = -EMLINK;
+ if ((old.dir_nlink_delta > 0 && EXT4_DIR_LINK_MAX(old.dir)) ||
+ (new.dir_nlink_delta > 0 && EXT4_DIR_LINK_MAX(new.dir)))
+ goto end_rename;
+ }
+
if (!new.bh) {
retval = ext4_add_entry(handle, new.dentry, old.inode);
if (retval)
goto end_rename;
} else {
+ u8 new_file_type = new.de->file_type;
retval = ext4_setent(handle, &new,
old.inode->i_ino, old.de->file_type);
if (retval)
goto end_rename;
+
+ if (flags & RENAME_EXCHANGE) {
+ retval = ext4_setent(handle, &old,
+ new.inode->i_ino, new_file_type);
+ if (retval)
+ goto end_rename;
+ }
}
/*
@@ -3235,35 +3283,40 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
old.inode->i_ctime = ext4_current_time(old.inode);
ext4_mark_inode_dirty(handle, old.inode);
- /*
- * ok, that's it
- */
- ext4_rename_delete(handle, &old);
+ if (!(flags & RENAME_EXCHANGE)) {
+ /*
+ * ok, that's it
+ */
+ ext4_rename_delete(handle, &old);
- if (new.inode) {
- ext4_dec_count(handle, new.inode);
- new.inode->i_ctime = ext4_current_time(new.inode);
+ old.dir->i_ctime = old.dir->i_mtime = ext4_current_time(old.dir);
+ ext4_update_dx_flag(old.dir);
}
- old.dir->i_ctime = old.dir->i_mtime = ext4_current_time(old.dir);
- ext4_update_dx_flag(old.dir);
if (old.dir_bh) {
retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
if (retval)
goto end_rename;
-
- ext4_dec_count(handle, old.dir);
- if (new.inode) {
+ }
+ if (new.dir_bh) {
+ retval = ext4_rename_dir_finish(handle, &new, old.dir->i_ino);
+ if (retval)
+ goto end_rename;
+ }
+ ext4_update_dir_count(handle, &old);
+ ext4_update_dir_count(handle, &new);
+ if (!new.inode)
+ ext4_update_dx_flag(new.dir);
+ if (new.dir_nlink_delta || !new.inode)
+ ext4_mark_inode_dirty(handle, new.dir);
+ ext4_mark_inode_dirty(handle, old.dir);
+ if (!(flags & RENAME_EXCHANGE) && new.inode) {
+ ext4_dec_count(handle, new.inode);
+ new.inode->i_ctime = ext4_current_time(new.inode);
+ if (S_ISDIR(old.inode->i_mode)) {
/* checked empty_dir above, can't have another parent,
* ext4_dec_count() won't work for many-linked dirs */
clear_nlink(new.inode);
- } else {
- ext4_inc_count(handle, new.dir);
- ext4_update_dx_flag(new.dir);
- ext4_mark_inode_dirty(handle, new.dir);
}
- }
- ext4_mark_inode_dirty(handle, old.dir);
- if (new.inode) {
ext4_mark_inode_dirty(handle, new.inode);
if (!new.inode->i_nlink)
ext4_orphan_add(handle, new.inode);
--
1.8.1.4
next prev parent reply other threads:[~2014-01-08 22:10 UTC|newest]
Thread overview: 73+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-01-08 22:10 [PATCH 00/11] cross rename v3 Miklos Szeredi
2014-01-08 22:10 ` [PATCH 01/11] vfs: add d_is_dir() Miklos Szeredi
2014-01-08 22:10 ` [PATCH 02/11] vfs: rename: move d_move() up Miklos Szeredi
2014-01-08 22:10 ` [PATCH 03/11] vfs: rename: use common code for dir and non-dir Miklos Szeredi
2014-01-08 22:10 ` [PATCH 04/11] vfs: add renameat2 syscall Miklos Szeredi
2014-01-14 22:11 ` Tetsuo Handa
2014-01-15 10:30 ` Miklos Szeredi
2014-01-15 13:50 ` Miklos Szeredi
2014-01-18 10:40 ` Tetsuo Handa
2014-01-08 22:10 ` [PATCH 05/11] vfs: add RENAME_NOREPLACE flag Miklos Szeredi
2014-01-15 18:19 ` J. Bruce Fields
2014-01-15 18:26 ` Andy Lutomirski
2014-01-15 23:33 ` J. Bruce Fields
2014-01-16 10:45 ` Miklos Szeredi
2014-01-15 18:35 ` Miklos Szeredi
2014-01-15 23:31 ` J. Bruce Fields
2014-01-08 22:10 ` [PATCH 06/11] security: add flags to rename hooks Miklos Szeredi
2014-01-08 22:10 ` [PATCH 07/11] vfs: add cross-rename Miklos Szeredi
2014-01-13 7:52 ` Jan Kara
2014-01-14 10:31 ` Miklos Szeredi
2014-01-14 12:47 ` Jan Kara
2014-01-08 22:10 ` [PATCH 08/11] ext4: rename: create ext4_renament structure for local vars Miklos Szeredi
2014-01-08 22:10 ` [PATCH 09/11] ext4: rename: move EMLINK check up Miklos Szeredi
2014-01-08 22:10 ` [PATCH 10/11] ext4: rename: split out helper functions Miklos Szeredi
2014-01-08 22:10 ` Miklos Szeredi [this message]
2014-01-13 12:25 ` [PATCH 11/11] ext4: add cross rename support Jan Kara
2014-01-14 10:35 ` Miklos Szeredi
2014-01-15 18:23 ` J. Bruce Fields
2014-01-15 18:31 ` Miklos Szeredi
2014-01-16 10:54 ` Miklos Szeredi
2014-01-16 14:48 ` J. Bruce Fields
2014-01-17 10:53 ` Michael Kerrisk (man-pages)
2014-01-17 14:41 ` Miklos Szeredi
[not found] ` <20140117144126.GG24171-nYI/l+Q8b4r16c5iV7KQqR1Qg9XOENNVk/YoNI2nt5o@public.gmane.org>
2014-04-19 9:08 ` Michael Kerrisk (man-pages)
2014-04-19 12:08 ` Tetsuo Handa
2014-04-23 14:24 ` Miklos Szeredi
2014-04-24 11:20 ` [PATCH (for 3.15) 0/5] Fix cross rename race window for LSM Tetsuo Handa
2014-04-24 11:22 ` [PATCH (for 3.15) 1/5] LSM: Pass the rename flags to each LSM module Tetsuo Handa
2014-04-25 20:49 ` Casey Schaufler
2014-04-24 11:23 ` [PATCH (for 3.15) 2/5] SELinux: Handle the rename flags Tetsuo Handa
2014-04-24 11:24 ` [PATCH (for 3.15) 3/5] AppArmor: " Tetsuo Handa
2014-04-24 11:25 ` [PATCH (for 3.15) 4/5] TOMOYO: " Tetsuo Handa
2014-04-24 11:26 ` [PATCH (for 3.15) 5/5] LSM: Remove duplicated rename handling Tetsuo Handa
2014-05-01 11:58 ` [PATCH (for 3.15) 0/5] Fix cross rename race window for LSM Tetsuo Handa
2014-05-05 5:49 ` Tetsuo Handa
2014-05-11 15:53 ` Tetsuo Handa
2014-05-12 13:21 ` [PATCH (for 3.15) 0/5] Fix cross rename regressions " Tetsuo Handa
2014-05-12 13:22 ` [PATCH (for 3.15) 1/5] LSM: Pass the rename flags to each LSM module Tetsuo Handa
2014-05-19 12:19 ` John Johansen
2014-05-12 13:23 ` [PATCH (for 3.15) 2/5] SELinux: Handle the rename flags Tetsuo Handa
2014-05-12 13:24 ` [PATCH (for 3.15) 3/5] AppArmor: " Tetsuo Handa
2014-05-19 12:28 ` John Johansen
2014-05-12 13:25 ` [PATCH (for 3.15) 4/5] TOMOYO: " Tetsuo Handa
2014-05-12 13:25 ` [PATCH (for 3.15) 5/5] LSM: Remove duplicated rename handling Tetsuo Handa
2014-05-19 12:34 ` John Johansen
2014-04-23 14:21 ` [PATCH 11/11] ext4: add cross rename support Miklos Szeredi
[not found] ` <CAJfpegsdUwxHOGxhiLtkMHzB==UGzbj+rAVOJGX4nb6z1Urzpw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-04-23 19:01 ` Michael Kerrisk (man-pages)
2014-01-17 22:08 ` J. Bruce Fields
2014-01-18 6:49 ` Miklos Szeredi
2014-01-18 16:27 ` J. Bruce Fields
2014-01-20 11:39 ` Miklos Szeredi
2014-01-20 11:50 ` Michael Kerrisk (man-pages)
2014-01-13 12:46 ` [PATCH 00/11] cross rename v3 Tetsuo Handa
2014-01-13 17:08 ` Miklos Szeredi
2014-01-13 22:03 ` Tetsuo Handa
2014-01-14 9:58 ` Miklos Szeredi
2014-01-14 13:03 ` Tetsuo Handa
2014-01-14 20:10 ` John Johansen
2014-01-14 20:53 ` Tetsuo Handa
2014-01-15 10:10 ` Miklos Szeredi
-- strict thread matches above, loose matches on Subject: below --
2013-11-20 13:01 [PATCH 00/11] cross rename v2 Miklos Szeredi
2013-11-20 13:01 ` [PATCH 11/11] ext4: add cross rename support Miklos Szeredi
2013-11-26 9:51 ` Jan Kara
2013-11-26 13:47 ` Miklos Szeredi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1389219015-10980-12-git-send-email-miklos@szeredi.hu \
--to=miklos@szeredi.hu \
--cc=akpm@linux-foundation.org \
--cc=dhowells@redhat.com \
--cc=hch@infradead.org \
--cc=jack@suse.cz \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@amacapital.net \
--cc=mszeredi@suse.cz \
--cc=torvalds@linux-foundation.org \
--cc=viro@ZenIV.linux.org.uk \
--cc=zab@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).