[PATCH 1/3] CIFS: Close open handle after interrupted close
Tim Gardner
tim.gardner at canonical.com
Fri Mar 12 13:32:28 UTC 2021
On 3/12/21 3:32 AM, Krzysztof Kozlowski wrote:
> On 11/03/2021 19:18, 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>
>> ---
>>
>> fs/cifs/smb2misc.c | 59 ++++++++++++++++++++++++++++++++++-----------
>> fs/cifs/smb2pdu.c | 9 ++++++-
>> fs/cifs/smb2proto.h | 3 +++
>> 3 files changed, 56 insertions(+), 15 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..03e4725390d4 100644
>> --- a/fs/cifs/smb2pdu.c
>> +++ b/fs/cifs/smb2pdu.c
>> @@ -2133,6 +2133,14 @@ 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);
>> + }
>
> Hi Tim,
>
> The context looks good but you have here mismatched indentation.
>
Is that an ACK, or do you want me to fix the indentation ? Which line in
particular do you think is wrong ?
rtg
-----------
Tim Gardner
Canonical, Inc
More information about the kernel-team
mailing list