All of lore.kernel.org
 help / color / mirror / Atom feed
From: Omar Sandoval <osandov@osandov.com>
To: linux-fsdevel@vger.kernel.org, Al Viro <viro@zeniv.linux.org.uk>
Cc: kernel-team@fb.com
Subject: [RFC PATCH man-pages] link.2: Document new AT_LINK_REPLACE flag
Date: Tue, 28 Jan 2020 15:18:57 -0800	[thread overview]
Message-ID: <8480e876e2810afb0485a080ce1cef182f86967f.1580253342.git.osandov@fb.com> (raw)
In-Reply-To: <cover.1580251857.git.osandov@fb.com>

From: Omar Sandoval <osandov@fb.com>

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 man2/link.2 | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 191 insertions(+)

diff --git a/man2/link.2 b/man2/link.2
index 649ba00c7..0097e3071 100644
--- a/man2/link.2
+++ b/man2/link.2
@@ -174,6 +174,60 @@ like this:
 linkat(AT_FDCWD, "/proc/self/fd/<fd>", newdirfd,
        newname, AT_SYMLINK_FOLLOW);
 .EE
+.TP
+.BR AT_LINK_REPLACE " (since Linux 5.7)"
+If
+.I newpath
+exists, replace it atomically.
+There is no point at which another process attempting to access
+.I newpath
+will find it missing.
+If
+.I newpath
+exists but the operation fails,
+the original entry specified by
+.I newpath
+will remain in place.
+This does not guarantee data integrity;
+see EXAMPLE below for how to use this for crash-safe file replacement with
+.BR O_TMPFILE .
+.IP
+If
+.I newpath
+is replaced,
+any other hard links referring to the original file are unaffected.
+Open file descriptors for
+.I newpath
+are also unaffected.
+.IP
+.I newpath
+must not be a directory.
+.IP
+If the entry specified by
+.I newpath
+refers to the file specified by
+.I oldpath,
+.BR linkat ()
+does nothing and returns a success status.
+Note that this comparison does not follow mounts on
+.IR newpath .
+.IP
+Otherwise,
+.I newpath
+must not be a mount point in the local namespace.
+If it is a mount point in another namespace and the operation succeeds,
+all mounts are detached from
+.I newpath
+in all namespaces, as is the case for
+.BR rename (2),
+.BR rmdir (2),
+and
+.BR unlink (2).
+.IP
+If
+.I newpath
+refers to a symbolic link,
+the link will be replaced.
 .in
 .PP
 Before kernel 2.6.18, the
@@ -293,10 +347,34 @@ or
 .I newdirfd
 is not a valid file descriptor.
 .TP
+.B EBUSY
+.B AT_LINK_REPLACE
+was specified in
+.IR flags ,
+.I newpath
+does not refer to the file specified by
+.IR oldpath ,
+and
+.I newpath
+is in use by the system
+(for example, it is a mount point in the local namespace).
+.TP
 .B EINVAL
 An invalid flag value was specified in
 .IR flags .
 .TP
+.B EINVAL
+The filesystem does not support one of the flags in
+.IR flags .
+.TP
+.B EISDIR
+.B AT_LINK_REPLACE
+was specified in
+.I flags
+and
+.I newpath
+refers to an existing directory.
+.TP
 .B ENOENT
 .B AT_EMPTY_PATH
 was specified in
@@ -344,6 +422,31 @@ was specified in
 is an empty string, and
 .IR olddirfd
 refers to a directory.
+.TP
+.B EPERM
+.B AT_LINK_REPLACE
+was specified in
+.I flags
+and
+.I newpath
+refers to an immutable or append-only file
+or a file in an immutable or append-only directory.
+(See
+.BR ioctl_iflags (2).)
+.TP
+.BR EPERM " or " EACCES
+.B AT_LINK_REPLACE
+was specified in
+.IR flags ,
+the directory containing
+.I newpath
+has the sticky bit
+.RB ( S_ISVTX )
+set, and the process's effective UID is neither the UID of the file to
+be deleted nor that of the directory containing it, and
+the process is not privileged (Linux: does not have the
+.B CAP_FOWNER
+capability).
 .SH VERSIONS
 .BR linkat ()
 was added to Linux in kernel 2.6.16;
@@ -421,6 +524,94 @@ performs the link creation and dies before it can say so.
 Use
 .BR stat (2)
 to find out if the link got created.
+.SH EXAMPLE
+The following program demonstrates the use of
+.BR linkat ()
+with
+.B AT_LINK_REPLACE
+and
+.BR open (2)
+with
+.B O_TMPFILE
+for crash-safe file replacement.
+.SS Example output
+.in +4n
+.EX
+$ \fBecho bar > foo\fP
+$ \fB./replace foo\fP
+$ \fBcat foo\fP
+hello, world
+.EE
+.in
+.SS Program source (replace.c)
+.EX
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+int
+main(int argc, char *argv[])
+{
+	char *path, *dirc, *basec, *dir, *base;
+	int fd, dirfd;
+
+	if (argc != 2) {
+		fprintf(stderr, "usage: %s PATH\en", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	path = argv[1];
+
+	dirc = strdup(path);
+	basec = strdup(path);
+	if (!dirc || !basec) {
+		perror("strdup");
+		exit(EXIT_FAILURE);
+	}
+	dir = dirname(dirc);
+	base = basename(basec);
+
+	/* Open the parent directory. */
+	dirfd = open(dir, O_DIRECTORY | O_RDONLY);
+	if (dirfd == -1) {
+		perror("open");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Open a temporary file, write data to it, and persist it. */
+	fd = open(dir, O_TMPFILE | O_RDWR, 0644);
+	if (fd == -1) {
+		perror("open");
+		exit(EXIT_FAILURE);
+	}
+	if (write(fd, "hello, world\en", 13) == -1) {
+		perror("write");
+		exit(EXIT_FAILURE);
+	}
+	if (fsync(fd) == -1) {
+		perror("fsync");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Replace the original file and persist the directory. */
+	if (linkat(fd, "", dirfd, base, AT_EMPTY_PATH | AT_LINK_REPLACE) == -1) {
+		perror("linkat");
+		exit(EXIT_FAILURE);
+	}
+	if (fsync(dirfd) == -1) {
+		perror("fsync");
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
+.EE
 .SH SEE ALSO
 .BR ln (1),
 .BR open (2),
-- 
2.25.0


WARNING: multiple messages have this Message-ID (diff)
From: Omar Sandoval <osandov@osandov.com>
To: linux-fsdevel@vger.kernel.org, Al Viro <viro@zeniv.linux.org.uk>
Cc: kernel-team@fb.com, linux-api@vger.kernel.org,
	David Howells <dhowells@redhat.com>,
	Amir Goldstein <amir73il@gmail.com>,
	Xi Wang <xi@cs.washington.edu>
Subject: [RFC PATCH man-pages] link.2: Document new AT_LINK_REPLACE flag
Date: Wed, 29 Jan 2020 00:58:28 -0800	[thread overview]
Message-ID: <8480e876e2810afb0485a080ce1cef182f86967f.1580253342.git.osandov@fb.com> (raw)
Message-ID: <20200129085828.clyLJDo23Je-QfO63wBkJ_kqsndrZ3VOITeuKibTR8Q@z> (raw)
In-Reply-To: <cover.1580251857.git.osandov@fb.com>

From: Omar Sandoval <osandov@fb.com>

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 man2/link.2 | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 191 insertions(+)

diff --git a/man2/link.2 b/man2/link.2
index 649ba00c7..0097e3071 100644
--- a/man2/link.2
+++ b/man2/link.2
@@ -174,6 +174,60 @@ like this:
 linkat(AT_FDCWD, "/proc/self/fd/<fd>", newdirfd,
        newname, AT_SYMLINK_FOLLOW);
 .EE
+.TP
+.BR AT_LINK_REPLACE " (since Linux 5.7)"
+If
+.I newpath
+exists, replace it atomically.
+There is no point at which another process attempting to access
+.I newpath
+will find it missing.
+If
+.I newpath
+exists but the operation fails,
+the original entry specified by
+.I newpath
+will remain in place.
+This does not guarantee data integrity;
+see EXAMPLE below for how to use this for crash-safe file replacement with
+.BR O_TMPFILE .
+.IP
+If
+.I newpath
+is replaced,
+any other hard links referring to the original file are unaffected.
+Open file descriptors for
+.I newpath
+are also unaffected.
+.IP
+.I newpath
+must not be a directory.
+.IP
+If the entry specified by
+.I newpath
+refers to the file specified by
+.I oldpath,
+.BR linkat ()
+does nothing and returns a success status.
+Note that this comparison does not follow mounts on
+.IR newpath .
+.IP
+Otherwise,
+.I newpath
+must not be a mount point in the local namespace.
+If it is a mount point in another namespace and the operation succeeds,
+all mounts are detached from
+.I newpath
+in all namespaces, as is the case for
+.BR rename (2),
+.BR rmdir (2),
+and
+.BR unlink (2).
+.IP
+If
+.I newpath
+refers to a symbolic link,
+the link will be replaced.
 .in
 .PP
 Before kernel 2.6.18, the
@@ -293,10 +347,34 @@ or
 .I newdirfd
 is not a valid file descriptor.
 .TP
+.B EBUSY
+.B AT_LINK_REPLACE
+was specified in
+.IR flags ,
+.I newpath
+does not refer to the file specified by
+.IR oldpath ,
+and
+.I newpath
+is in use by the system
+(for example, it is a mount point in the local namespace).
+.TP
 .B EINVAL
 An invalid flag value was specified in
 .IR flags .
 .TP
+.B EINVAL
+The filesystem does not support one of the flags in
+.IR flags .
+.TP
+.B EISDIR
+.B AT_LINK_REPLACE
+was specified in
+.I flags
+and
+.I newpath
+refers to an existing directory.
+.TP
 .B ENOENT
 .B AT_EMPTY_PATH
 was specified in
@@ -344,6 +422,31 @@ was specified in
 is an empty string, and
 .IR olddirfd
 refers to a directory.
+.TP
+.B EPERM
+.B AT_LINK_REPLACE
+was specified in
+.I flags
+and
+.I newpath
+refers to an immutable or append-only file
+or a file in an immutable or append-only directory.
+(See
+.BR ioctl_iflags (2).)
+.TP
+.BR EPERM " or " EACCES
+.B AT_LINK_REPLACE
+was specified in
+.IR flags ,
+the directory containing
+.I newpath
+has the sticky bit
+.RB ( S_ISVTX )
+set, and the process's effective UID is neither the UID of the file to
+be deleted nor that of the directory containing it, and
+the process is not privileged (Linux: does not have the
+.B CAP_FOWNER
+capability).
 .SH VERSIONS
 .BR linkat ()
 was added to Linux in kernel 2.6.16;
@@ -421,6 +524,94 @@ performs the link creation and dies before it can say so.
 Use
 .BR stat (2)
 to find out if the link got created.
+.SH EXAMPLE
+The following program demonstrates the use of
+.BR linkat ()
+with
+.B AT_LINK_REPLACE
+and
+.BR open (2)
+with
+.B O_TMPFILE
+for crash-safe file replacement.
+.SS Example output
+.in +4n
+.EX
+$ \fBecho bar > foo\fP
+$ \fB./replace foo\fP
+$ \fBcat foo\fP
+hello, world
+.EE
+.in
+.SS Program source (replace.c)
+.EX
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+int
+main(int argc, char *argv[])
+{
+	char *path, *dirc, *basec, *dir, *base;
+	int fd, dirfd;
+
+	if (argc != 2) {
+		fprintf(stderr, "usage: %s PATH\en", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	path = argv[1];
+
+	dirc = strdup(path);
+	basec = strdup(path);
+	if (!dirc || !basec) {
+		perror("strdup");
+		exit(EXIT_FAILURE);
+	}
+	dir = dirname(dirc);
+	base = basename(basec);
+
+	/* Open the parent directory. */
+	dirfd = open(dir, O_DIRECTORY | O_RDONLY);
+	if (dirfd == -1) {
+		perror("open");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Open a temporary file, write data to it, and persist it. */
+	fd = open(dir, O_TMPFILE | O_RDWR, 0644);
+	if (fd == -1) {
+		perror("open");
+		exit(EXIT_FAILURE);
+	}
+	if (write(fd, "hello, world\en", 13) == -1) {
+		perror("write");
+		exit(EXIT_FAILURE);
+	}
+	if (fsync(fd) == -1) {
+		perror("fsync");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Replace the original file and persist the directory. */
+	if (linkat(fd, "", dirfd, base, AT_EMPTY_PATH | AT_LINK_REPLACE) == -1) {
+		perror("linkat");
+		exit(EXIT_FAILURE);
+	}
+	if (fsync(dirfd) == -1) {
+		perror("fsync");
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
+.EE
 .SH SEE ALSO
 .BR ln (1),
 .BR open (2),
-- 
2.25.0


  parent reply	other threads:[~2020-01-28 23:19 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-28 23:18 [RFC PATCH v4 0/4] fs: add flag to linkat() for replacing destination Omar Sandoval
2020-01-29  8:58 ` Omar Sandoval
2020-01-28 23:18 ` [RFC PATCH xfstests] generic: add smoke test for AT_LINK_REPLACE Omar Sandoval
2020-01-29  8:58   ` Omar Sandoval
2020-01-29  7:02   ` Zorro Lang
2020-02-23 14:46   ` Eryu Guan
2020-01-28 23:18 ` Omar Sandoval [this message]
2020-01-29  8:58   ` [RFC PATCH man-pages] link.2: Document new AT_LINK_REPLACE flag Omar Sandoval
2020-01-28 23:18 ` [RFC PATCH xfsprogs] xfs_io: add support for linkat() AT_LINK_REPLACE Omar Sandoval
2020-01-29  8:58   ` Omar Sandoval
2020-01-30  4:42   ` Zorro Lang
2020-01-28 23:19 ` [RFC PATCH v4 1/4] fs: add flags argument to i_op->link() Omar Sandoval
2020-01-29  8:58   ` Omar Sandoval
2020-01-28 23:19 ` [RFC PATCH v4 2/4] fs: add AT_LINK_REPLACE flag for linkat() which replaces the target Omar Sandoval
2020-01-29  8:58   ` Omar Sandoval
2020-01-28 23:19 ` [RFC PATCH v4 3/4] Btrfs: fix inode reference count leak in btrfs_link() error path Omar Sandoval
2020-01-29  8:58   ` Omar Sandoval
2020-01-28 23:19 ` [RFC PATCH v4 4/4] Btrfs: add support for linkat() AT_REPLACE Omar Sandoval
2020-01-29  8:58   ` Omar Sandoval
2020-01-29  8:58 ` [RFC PATCH xfstests] generic: add smoke test for AT_LINK_REPLACE Omar Sandoval
     [not found] ` <cover.1580251857.git.osandov-b10kYP2dOMg@public.gmane.org>
2020-01-29  8:58   ` Omar Sandoval
2020-01-29  8:58   ` [RFC PATCH man-pages] link.2: Document new AT_LINK_REPLACE flag Omar Sandoval
2020-01-29  8:58   ` [RFC PATCH xfsprogs] xfs_io: add support for linkat() AT_LINK_REPLACE Omar Sandoval
2020-01-29  8:58   ` [RFC PATCH v4 0/4] fs: add flag to linkat() for replacing destination Omar Sandoval
2020-01-29  8:58   ` [RFC PATCH v4 1/4] fs: add flags argument to i_op->link() Omar Sandoval
2020-01-29  8:58   ` [RFC PATCH v4 2/4] fs: add AT_LINK_REPLACE flag for linkat() which replaces the target Omar Sandoval
2020-01-29  8:58   ` [RFC PATCH v4 3/4] Btrfs: fix inode reference count leak in btrfs_link() error path Omar Sandoval
2020-01-29  8:58   ` [RFC PATCH v4 4/4] Btrfs: add support for linkat() AT_REPLACE Omar Sandoval
2020-01-31 13:48 ` [RFC PATCH v4 1/4] fs: add flags argument to i_op->link() David Howells
2020-01-31 20:24   ` Omar Sandoval
2020-01-31 20:24     ` Omar Sandoval

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=8480e876e2810afb0485a080ce1cef182f86967f.1580253342.git.osandov@fb.com \
    --to=osandov@osandov.com \
    --cc=kernel-team@fb.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    /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.