Re: [RFC PATCH v3 1/2] fs: add AT_REPLACE flag for linkat() which replaces the target

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Apr 23, 2018 at 11:19:41PM -0700, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@xxxxxx>
> 
> One of the most common uses of temporary files is the classic atomic
> replacement pattern, i.e.,
> 
> - write temporary file
> - fsync temporary file
> - rename temporary file over real file
> - fsync parent directory
> 
> Now, we have O_TMPFILE, which gives us a much better way to create
> temporary files, but it's not possible to use it for this pattern.
> 
> This patch introduces an AT_REPLACE flag which allows linkat() to
> replace the target file. Now, the temporary file in the pattern above
> can be a proper O_TMPFILE. Even without O_TMPFILE, this is a new
> primitive which might be useful in other contexts.
> 
> The implementation on the VFS side mimics sys_renameat2().
> 
> Cc: Xi Wang <xi@xxxxxxxxxxxxxxxxx>
> Signed-off-by: Omar Sandoval <osandov@xxxxxx>
> ---
>  fs/ecryptfs/inode.c        |   2 +-
>  fs/namei.c                 | 181 +++++++++++++++++++++++++++++--------
>  fs/nfsd/vfs.c              |   2 +-
>  fs/overlayfs/overlayfs.h   |   2 +-
>  include/linux/fs.h         |   3 +-
>  include/uapi/linux/fcntl.h |   1 +
>  6 files changed, 150 insertions(+), 41 deletions(-)
> 
> diff --git a/fs/namei.c b/fs/namei.c
> index 186bd2464fd5..2cc2b1deaa12 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -4149,6 +4149,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
>   * @dir:	new parent
>   * @new_dentry:	where to create the new link
>   * @delegated_inode: returns inode needing a delegation break
> + * @flags:      link flags
>   *
>   * The caller must hold dir->i_mutex
>   *
> @@ -4162,16 +4163,26 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
>   * be appropriate for callers that expect the underlying filesystem not
>   * to be NFS exported.
>   */
> -int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
> +int vfs_link(struct dentry *old_dentry, struct inode *dir,
> +	     struct dentry *new_dentry, struct inode **delegated_inode,
> +	     unsigned int flags)
>  {
>  	struct inode *inode = old_dentry->d_inode;
> +	struct inode *target = new_dentry->d_inode;
>  	unsigned max_links = dir->i_sb->s_max_links;
>  	int error;
>  
>  	if (!inode)
>  		return -ENOENT;
>  
> -	error = may_create(dir, new_dentry);
> +	if (target) {
> +		if (flags & AT_REPLACE)

This needs an

	if (inode == target)
		return 0;
		
I'll fix this in v4.

> +			error = may_delete(dir, new_dentry, d_is_dir(old_dentry));
> +		else
> +			error = -EEXIST;
> +	} else {
> +		error = may_create(dir, new_dentry);
> +	}
>  	if (error)
>  		return error;
>  



[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux