Re: [PATCH] nfsd: Prevent truncation of an unlinked inode from blocking access to its directory

J. Bruce Fields
2021-05-14T15:09:43Z

On Fri, May 14, 2021 at 11:58:29AM +0800, Nick Huang wrote:
> From: Yu Hsiang Huang <nickhuang@synology.com>
>
> Truncation of an unlinked inode may take a long time for I/O waiting, and
> it doesn't have to prevent access to the directory. Thus, let truncation
> occur outside the directory's mutex, just like do_unlinkat() does.

Makes sense to me, thanks. I'll queue it up for 5.14.

Just out of curiosity: was this found just by inspection, or were you
hitting this in a real workload? I'd be interested in what it took to
reproduce if so.

--b.

>
> Signed-off-by: Yu Hsiang Huang <nickhuang@synology.com>
> Signed-off-by: Bing Jing Chang <bingjingc@synology.com>
> Signed-off-by: Robbie Ko <robbieko@synology.com>
> ---
> fs/nfsd/vfs.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> index 15adf1f6ab21..39948f130712 100644
> --- a/fs/nfsd/vfs.c
> +++ b/fs/nfsd/vfs.c
> @@ -1859,6 +1859,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
> {
> struct dentry *dentry, *rdentry;
> struct inode *dirp;
> + struct inode *rinode;
> __be32 err;
> int host_err;
>
> @@ -1887,6 +1888,8 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
> host_err = -ENOENT;
> goto out_drop_write;
> }
> + rinode = d_inode(rdentry);
> + ihold(rinode);
>
> if (!type)
> type = d_inode(rdentry)->i_mode & S_IFMT;
> @@ -1902,6 +1905,8 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
> if (!host_err)
> host_err = commit_metadata(fhp);
> dput(rdentry);
> + fh_unlock(fhp);
> + iput(rinode); /* truncate the inode here */
>
> out_drop_write:
> fh_drop_write(fhp);
> --
> 2.25.1