NAK: [PATCH 1/3] CIFS: Close open handle after interrupted close

Krzysztof Kozlowski krzysztof.kozlowski at canonical.com
Fri Mar 12 14:36:46 UTC 2021


On 12/03/2021 15:26, Tim Gardner wrote:
> From: Pavel Shilovsky <pshilov at microsoft.com>
> 
> BugLink: https://bugs.launchpad.net/bugs/1918714
> 
> If Close command is interrupted before sending a request
> to the server the client ends up leaking an open file
> handle. This wastes server resources and can potentially
> block applications that try to remove the file or any
> directory containing this file.
> 
> Fix this by putting the close command into a worker queue,
> so another thread retries it later.
> 
> Cc: Stable <stable at vger.kernel.org>
> Tested-by: Frank Sorenson <sorenson at redhat.com>
> Reviewed-by: Ronnie Sahlberg <lsahlber at redhat.com>
> Signed-off-by: Pavel Shilovsky <pshilov at microsoft.com>
> Signed-off-by: Steve French <stfrench at microsoft.com>
> (backported from commit 9150c3adbf24d77cfba37f03639d4a908ca4ac25)
> [ fs/cifs/smb2pdu.c has had significant changes, so the part of this
> patch affecting fs/cifs/smb2pdu.c was pieced in where the logic looked
> correct ]
> Signed-off-by: Tim Gardner <tim.gardner at canonical.com>
> ---
> 
> v2 - ran scripts/checkpatch.pl and corrected formatting errors.
> 
>  fs/cifs/smb2misc.c  | 59 ++++++++++++++++++++++++++++++++++-----------
>  fs/cifs/smb2pdu.c   | 11 +++++++--
>  fs/cifs/smb2proto.h |  3 +++
>  3 files changed, 57 insertions(+), 16 deletions(-)
> 
> diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
> index 0c6e5450ff76..d15ace6151d9 100644
> --- a/fs/cifs/smb2misc.c
> +++ b/fs/cifs/smb2misc.c
> @@ -674,34 +674,65 @@ smb2_cancelled_close_fid(struct work_struct *work)
>  	kfree(cancelled);
>  }
>  
> +/* Caller should already has an extra reference to @tcon */
> +static int
> +__smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
> +			      __u64 volatile_fid)
> +{
> +	struct close_cancelled_open *cancelled;
> +
> +	cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL);
> +	if (!cancelled)
> +		return -ENOMEM;
> +
> +	cancelled->fid.persistent_fid = persistent_fid;
> +	cancelled->fid.volatile_fid = volatile_fid;
> +	cancelled->tcon = tcon;
> +	INIT_WORK(&cancelled->work, smb2_cancelled_close_fid);
> +	WARN_ON(queue_work(cifsiod_wq, &cancelled->work) == false);
> +
> +	return 0;
> +}
> +
> +int
> +smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
> +			    __u64 volatile_fid)
> +{
> +	int rc;
> +
> +	cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count);
> +	spin_lock(&cifs_tcp_ses_lock);
> +	tcon->tc_count++;
> +	spin_unlock(&cifs_tcp_ses_lock);
> +
> +	rc = __smb2_handle_cancelled_close(tcon, persistent_fid, volatile_fid);
> +	if (rc)
> +		cifs_put_tcon(tcon);
> +
> +	return rc;
> +}
> +
>  int
>  smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server)
>  {
>  	struct smb2_sync_hdr *sync_hdr = get_sync_hdr(buffer);
>  	struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer;
>  	struct cifs_tcon *tcon;
> -	struct close_cancelled_open *cancelled;
> +	int rc;
>  
>  	if (sync_hdr->Command != SMB2_CREATE ||
>  	    sync_hdr->Status != STATUS_SUCCESS)
>  		return 0;
>  
> -	cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL);
> -	if (!cancelled)
> -		return -ENOMEM;
> -
>  	tcon = smb2_find_smb_tcon(server, sync_hdr->SessionId,
>  				  sync_hdr->TreeId);
> -	if (!tcon) {
> -		kfree(cancelled);
> +	if (!tcon)
>  		return -ENOENT;
> -	}
>  
> -	cancelled->fid.persistent_fid = rsp->PersistentFileId;
> -	cancelled->fid.volatile_fid = rsp->VolatileFileId;
> -	cancelled->tcon = tcon;
> -	INIT_WORK(&cancelled->work, smb2_cancelled_close_fid);
> -	queue_work(cifsiod_wq, &cancelled->work);
> +	rc = __smb2_handle_cancelled_close(tcon, rsp->PersistentFileId,
> +					   rsp->VolatileFileId);
> +	if (rc)
> +		cifs_put_tcon(tcon);
>  
> -	return 0;
> +	return rc;
>  }
> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
> index ab1df4311a6d..04e1cb66baf8 100644
> --- a/fs/cifs/smb2pdu.c
> +++ b/fs/cifs/smb2pdu.c
> @@ -2133,9 +2133,17 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
>  	rsp = (struct smb2_close_rsp *)rsp_iov.iov_base;
>  
>  	if (rc != 0) {
> +		/* retry close in a worker thread if this one is interrupted */
> +		if (rc == -EINTR) {
> +			int tmp_rc = smb2_handle_cancelled_close(tcon, persistent_fid,
> +							volatile_fid);
> +			if (tmp_rc)
> +				cifs_dbg(VFS, "handle cancelled close fid 0x%llx returned error %d\n",
> +					persistent_fid, tmp_rc);
> +		}
>  		cifs_stats_fail_inc(tcon, SMB2_CLOSE_HE);
>  		goto close_exit;
> -	}
> +		}
>
Still not good here. The closing bracket should stay as it was.

Best regards,
Krzysztof



More information about the kernel-team mailing list