mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-24 03:08:51 +03:00
zfs_rename: support RENAME_* flags
Implement support for Linux's RENAME_* flags (for renameat2). Aside from being quite useful for userspace (providing race-free ways to exchange paths and implement mv --no-clobber), they are used by overlayfs and are thus required in order to use overlayfs-on-ZFS. In order for us to represent the new renameat2(2) flags in the ZIL, we create two new transaction types for the two flags which need transactional-level support (RENAME_EXCHANGE and RENAME_WHITEOUT). RENAME_NOREPLACE does not need any ZIL support because we know that if the operation succeeded before creating the ZIL entry, there was no file to be clobbered and thus it can be treated as a regular TX_RENAME. Reviewed-by: Ryan Moeller <ryan@iXsystems.com> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Pavel Snajdr <snajpa@snajpa.net> Signed-off-by: Aleksa Sarai <cyphar@cyphar.com> Closes #12209 Closes #14070
This commit is contained in:
committed by
Brian Behlendorf
parent
e015d6cc0b
commit
dbf6108b4d
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/zfs_ctldir.h>
|
||||
#include <sys/zfs_vfsops.h>
|
||||
#include <sys/zfs_vnops.h>
|
||||
@@ -498,35 +499,42 @@ static int
|
||||
#ifdef HAVE_IOPS_RENAME_USERNS
|
||||
zpl_rename2(struct user_namespace *user_ns, struct inode *sdip,
|
||||
struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry,
|
||||
unsigned int flags)
|
||||
unsigned int rflags)
|
||||
#else
|
||||
zpl_rename2(struct inode *sdip, struct dentry *sdentry,
|
||||
struct inode *tdip, struct dentry *tdentry, unsigned int flags)
|
||||
struct inode *tdip, struct dentry *tdentry, unsigned int rflags)
|
||||
#endif
|
||||
{
|
||||
cred_t *cr = CRED();
|
||||
vattr_t *wo_vap = NULL;
|
||||
int error;
|
||||
fstrans_cookie_t cookie;
|
||||
#ifndef HAVE_IOPS_RENAME_USERNS
|
||||
zuserns_t *user_ns = NULL;
|
||||
#endif
|
||||
|
||||
/* We don't have renameat2(2) support */
|
||||
if (flags)
|
||||
return (-EINVAL);
|
||||
|
||||
crhold(cr);
|
||||
if (rflags & RENAME_WHITEOUT) {
|
||||
wo_vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
|
||||
zpl_vap_init(wo_vap, sdip, S_IFCHR, cr, user_ns);
|
||||
wo_vap->va_rdev = makedevice(0, 0);
|
||||
}
|
||||
|
||||
cookie = spl_fstrans_mark();
|
||||
error = -zfs_rename(ITOZ(sdip), dname(sdentry), ITOZ(tdip),
|
||||
dname(tdentry), cr, 0, user_ns);
|
||||
dname(tdentry), cr, 0, rflags, wo_vap, user_ns);
|
||||
spl_fstrans_unmark(cookie);
|
||||
if (wo_vap)
|
||||
kmem_free(wo_vap, sizeof (vattr_t));
|
||||
crfree(cr);
|
||||
ASSERT3S(error, <=, 0);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
#if !defined(HAVE_RENAME_WANTS_FLAGS) && !defined(HAVE_IOPS_RENAME_USERNS)
|
||||
#if !defined(HAVE_IOPS_RENAME_USERNS) && \
|
||||
!defined(HAVE_RENAME_WANTS_FLAGS) && \
|
||||
!defined(HAVE_RENAME2)
|
||||
static int
|
||||
zpl_rename(struct inode *sdip, struct dentry *sdentry,
|
||||
struct inode *tdip, struct dentry *tdentry)
|
||||
@@ -745,7 +753,12 @@ const struct inode_operations zpl_inode_operations = {
|
||||
#endif /* CONFIG_FS_POSIX_ACL */
|
||||
};
|
||||
|
||||
#ifdef HAVE_RENAME2_OPERATIONS_WRAPPER
|
||||
const struct inode_operations_wrapper zpl_dir_inode_operations = {
|
||||
.ops = {
|
||||
#else
|
||||
const struct inode_operations zpl_dir_inode_operations = {
|
||||
#endif
|
||||
.create = zpl_create,
|
||||
.lookup = zpl_lookup,
|
||||
.link = zpl_link,
|
||||
@@ -754,7 +767,9 @@ const struct inode_operations zpl_dir_inode_operations = {
|
||||
.mkdir = zpl_mkdir,
|
||||
.rmdir = zpl_rmdir,
|
||||
.mknod = zpl_mknod,
|
||||
#if defined(HAVE_RENAME_WANTS_FLAGS) || defined(HAVE_IOPS_RENAME_USERNS)
|
||||
#ifdef HAVE_RENAME2
|
||||
.rename2 = zpl_rename2,
|
||||
#elif defined(HAVE_RENAME_WANTS_FLAGS) || defined(HAVE_IOPS_RENAME_USERNS)
|
||||
.rename = zpl_rename2,
|
||||
#else
|
||||
.rename = zpl_rename,
|
||||
@@ -776,6 +791,10 @@ const struct inode_operations zpl_dir_inode_operations = {
|
||||
#endif /* HAVE_SET_ACL */
|
||||
.get_acl = zpl_get_acl,
|
||||
#endif /* CONFIG_FS_POSIX_ACL */
|
||||
#ifdef HAVE_RENAME2_OPERATIONS_WRAPPER
|
||||
},
|
||||
.rename2 = zpl_rename2,
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct inode_operations zpl_symlink_inode_operations = {
|
||||
|
||||
Reference in New Issue
Block a user