[lvc-project] [PATCH 5.10/5.15 1/1] fuse: don't increment nlink in link()

Fedor Pchelkin pchelkin at ispras.ru
Fri Jun 20 12:49:41 MSK 2025


On Wed, 18. Jun 14:44, d.privalov wrote:
> From: Miklos Szeredi <mszeredi at redhat.com>
> 
> commit 97f044f690bac2b094bfb7fb2d177ef946c85880 upstream.
> 
> The fuse_iget() call in create_new_entry() already updated the inode with
> all the new attributes and incremented the attribute version.
> 
> Incrementing the nlink will result in the wrong count.  This wasn't noticed
> because the attributes were invalidated right after this.
> 
> Updating ctime is still needed for the writeback case when the ctime is not
> refreshed.
> 
> Signed-off-by: Miklos Szeredi <mszeredi at redhat.com>

Проведённую нетривиальную адаптацию стоит кратко описывать, чтобы у
читателей патча формировалось представление, по каким причинам были
выбраны те или иные решения.

> Signed-off-by: Dmitriy Privalov <d.privalov at omp.ru>
> ---
>  fs/fuse/dir.c | 29 ++++++++++-------------------
>  1 file changed, 10 insertions(+), 19 deletions(-)
> 
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index 4488a53a192d..7055fdc1b8ce 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -807,7 +807,7 @@ void fuse_flush_time_update(struct inode *inode)
>  	mapping_set_error(inode->i_mapping, err);
>  }
>  
> -void fuse_update_ctime(struct inode *inode)
> +static void fuse_update_ctime_in_cache(struct inode *inode)
>  {
>  	if (!IS_NOCMTIME(inode)) {
>  		inode->i_ctime = current_time(inode);
> @@ -816,6 +816,12 @@ void fuse_update_ctime(struct inode *inode)
>  	}
>  }
>  
> +void fuse_update_ctime(struct inode *inode)
> +{
> +	fuse_invalidate_attr(inode);
> +	fuse_update_ctime_in_cache(inode);
> +}

В других местах вызова fuse_update_ctime() в контексте 5.10 будет дважды
вызываться fuse_invalidate_attr(), что как бы не то чтобы что-то
серьёзное, но указывает на не до конца продуманную адаптацию.

Стоит в целом проанализировать мёрдж
- cdd39b0539c4 ("Merge tag 'fuse-update-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse")

и возможно рассмотреть патчи для предварительного переноса
- 371e8fd02969 ("fuse: move fuse_invalidate_attr() into fuse_update_ctime()")
- cefd1b83275d ("fuse: decrement nlink on overwriting rename")

> +
>  static int fuse_unlink(struct inode *dir, struct dentry *entry)
>  {
>  	int err;
> @@ -986,25 +992,10 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
>  	args.in_args[1].size = newent->d_name.len + 1;
>  	args.in_args[1].value = newent->d_name.name;
>  	err = create_new_entry(fm, &args, newdir, newent, inode->i_mode);
> -	/* Contrary to "normal" filesystems it can happen that link
> -	   makes two "logical" inodes point to the same "physical"
> -	   inode.  We invalidate the attributes of the old one, so it
> -	   will reflect changes in the backing inode (link count,
> -	   etc.)
> -	*/
> -	if (!err) {
> -		struct fuse_inode *fi = get_fuse_inode(inode);
> -
> -		spin_lock(&fi->lock);
> -		fi->attr_version = atomic64_inc_return(&fm->fc->attr_version);
> -		if (likely(inode->i_nlink < UINT_MAX))
> -			inc_nlink(inode);
> -		spin_unlock(&fi->lock);
> -		fuse_invalidate_attr(inode);
> -		fuse_update_ctime(inode);
> -	} else if (err == -EINTR) {
> +	if (!err)
> +		fuse_update_ctime_in_cache(inode);
> +	else if (err == -EINTR)
>  		fuse_invalidate_attr(inode);
> -	}
>  	return err;
>  }
>  
> -- 
> 2.34.1



More information about the lvc-project mailing list