All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Pádraig Brady" <P@draigBrady.com>
To: Linux API <linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: RFC: renameat(): Add a RENAME_REMOVE flag to unlink hardlinks
Date: Fri, 21 Nov 2014 14:17:37 +0000	[thread overview]
Message-ID: <546F4981.8080907@draigBrady.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 438 bytes --]

If 'a' and 'b' are hardlinks, then the command `mv a b & mv b a`
can result in both being removed as mv needs to emulate the
move with an unlink of the source file.  This can only be done
without races in the kernel and so mv was recently changed
to not allow this operation at all.  mv could safely reintroduce
this feature by leveraging a new flag for renameat() for which
an illustrative/untested patch is attached.

thanks,
Pádraig.

[-- Attachment #2: renameat_REMOVE.patch --]
[-- Type: text/x-patch, Size: 2618 bytes --]

>From 26d552617b00b3ffcd3b4646467cab5cb02f33ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <P@draigBrady.com>
Date: Fri, 21 Nov 2014 14:09:54 +0000
Subject: [PATCH] renameat: Add RENAME_REMOVE flag to unlink source if hardlink
 to dest

This operation can't be done in userspace with unlink without races,
as overlapping rename operations could remove both hardlinks.
---
 Documentation/filesystems/vfs.txt |  1 +
 fs/namei.c                        | 11 +++++++----
 include/uapi/linux/fs.h           |  1 +
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 20bf204..2daa41a 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -430,6 +430,7 @@ otherwise noted.
 	(2) RENAME_EXCHANGE: exchange source and target.  Both must
 	exist; this is checked by the VFS.  Unlike plain rename,
 	source and target may be of different type.
+	(4) RENAME_REMOVE: unlink source even if a hardlink to dest.
 
   readlink: called by the readlink(2) system call. Only required if
 	you want to support reading symbolic links
diff --git a/fs/namei.c b/fs/namei.c
index db5fe86..caed596 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4074,8 +4074,10 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	bool new_is_dir = false;
 	unsigned max_links = new_dir->i_sb->s_max_links;
 
-	if (source == target)
-		return 0;
+	if (source == target) {
+		if (old_dentry == new_dentry || !(flags & RENAME_REMOVE))
+			return 0;
+        }
 
 	error = may_delete(old_dir, old_dentry, is_dir);
 	if (error)
@@ -4210,10 +4212,11 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
 	bool should_retry = false;
 	int error;
 
-	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
+	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE |
+		      RENAME_WHITEOUT | RENAME_REMOVE))
 		return -EINVAL;
 
-	if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) &&
+	if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT | RENAME_REMOVE)) &&
 	    (flags & RENAME_EXCHANGE))
 		return -EINVAL;
 
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index 3735fa0..601d901 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -38,6 +38,7 @@
 #define RENAME_NOREPLACE	(1 << 0)	/* Don't overwrite target */
 #define RENAME_EXCHANGE		(1 << 1)	/* Exchange source and dest */
 #define RENAME_WHITEOUT		(1 << 2)	/* Whiteout source */
+#define RENAME_REMOVE		(1 << 3)	/* Remove source hardlink */
 
 struct fstrim_range {
 	__u64 start;
-- 
2.1.0


             reply	other threads:[~2014-11-21 14:17 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-21 14:17 Pádraig Brady [this message]
     [not found] ` <546F4981.8080907-V8g9lnOeT5ydJdNcDFJN0w@public.gmane.org>
2014-11-21 18:09   ` RFC: renameat(): Add a RENAME_REMOVE flag to unlink hardlinks Andy Lutomirski
     [not found]     ` <CALCETrXvVxvG+s39v+NMdvfkeb8YjbYjb6UXgDFg5ifYOjeKsA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-11-21 18:39       ` Pádraig Brady
2014-11-21 19:55         ` Andy Lutomirski
2014-11-21 20:48           ` Pádraig Brady
2014-11-21 21:18             ` Eric Blake
     [not found]               ` <546FAC18.5020200-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2014-11-21 21:29                 ` Andy Lutomirski
     [not found]                   ` <CALCETrUByDgug68FP=cnj-iwSXvbEEHp=S4a=WhQPFmuKc2pNw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-11-21 22:20                     ` Pádraig Brady
     [not found]                       ` <546FBAC6.6020407-V8g9lnOeT5ydJdNcDFJN0w@public.gmane.org>
2014-11-21 22:30                         ` Al Viro
2014-11-21 22:40                           ` Andy Lutomirski
     [not found]                             ` <CALCETrW0c1UzkVQgEE_je5BtVhdWRmNaYk4HCQk+t6AWvpC-FA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-11-22  1:29                               ` Pádraig Brady
     [not found]                                 ` <546FE6E1.7040703-V8g9lnOeT5ydJdNcDFJN0w@public.gmane.org>
2014-11-22  1:31                                   ` Andy Lutomirski
2014-11-22  1:50                                   ` Al Viro
     [not found]                                     ` <20141122015010.GW7996-3bDd1+5oDREiFSDQTTA3OLVCufUGDwFn@public.gmane.org>
2014-11-22  1:51                                       ` Andy Lutomirski
2014-11-22  1:57                                         ` Al Viro

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=546F4981.8080907@draigBrady.com \
    --to=p@draigbrady.com \
    --cc=linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.