diff options
Diffstat (limited to 'fs/cifs/smb2misc.c')
-rw-r--r-- | fs/cifs/smb2misc.c | 42 |
1 files changed, 32 insertions, 10 deletions
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 5668fb7d94e5..289915f0915d 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -729,19 +729,35 @@ smb2_cancelled_close_fid(struct work_struct *work) { struct close_cancelled_open *cancelled = container_of(work, struct close_cancelled_open, work); + struct cifs_tcon *tcon = cancelled->tcon; + int rc; + + if (cancelled->mid) + cifs_tcon_dbg(VFS, "Close unmatched open for MID:%llx\n", + cancelled->mid); + else + cifs_tcon_dbg(VFS, "Close interrupted close\n"); - cifs_dbg(VFS, "Close unmatched open\n"); + rc = SMB2_close(0, tcon, cancelled->fid.persistent_fid, + cancelled->fid.volatile_fid); + if (rc) + cifs_tcon_dbg(VFS, "Close cancelled mid failed rc:%d\n", rc); - SMB2_close(0, cancelled->tcon, cancelled->fid.persistent_fid, - cancelled->fid.volatile_fid); - cifs_put_tcon(cancelled->tcon); + cifs_put_tcon(tcon); kfree(cancelled); } -/* Caller should already has an extra reference to @tcon */ +/* + * Caller should already has an extra reference to @tcon + * This function is used to queue work to close a handle to prevent leaks + * on the server. + * We handle two cases. If an open was interrupted after we sent the + * SMB2_CREATE to the server but before we processed the reply, and second + * if a close was interrupted before we sent the SMB2_CLOSE to the server. + */ static int -__smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid, - __u64 volatile_fid) +__smb2_handle_cancelled_cmd(struct cifs_tcon *tcon, __u16 cmd, __u64 mid, + __u64 persistent_fid, __u64 volatile_fid) { struct close_cancelled_open *cancelled; @@ -752,6 +768,8 @@ __smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid, cancelled->fid.persistent_fid = persistent_fid; cancelled->fid.volatile_fid = volatile_fid; cancelled->tcon = tcon; + cancelled->cmd = cmd; + cancelled->mid = mid; INIT_WORK(&cancelled->work, smb2_cancelled_close_fid); WARN_ON(queue_work(cifsiod_wq, &cancelled->work) == false); @@ -769,7 +787,8 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid, tcon->tc_count++; spin_unlock(&cifs_tcp_ses_lock); - rc = __smb2_handle_cancelled_close(tcon, persistent_fid, volatile_fid); + rc = __smb2_handle_cancelled_cmd(tcon, SMB2_CLOSE_HE, 0, + persistent_fid, volatile_fid); if (rc) cifs_put_tcon(tcon); @@ -793,8 +812,11 @@ smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server) if (!tcon) return -ENOENT; - rc = __smb2_handle_cancelled_close(tcon, rsp->PersistentFileId, - rsp->VolatileFileId); + rc = __smb2_handle_cancelled_cmd(tcon, + le16_to_cpu(sync_hdr->Command), + le64_to_cpu(sync_hdr->MessageId), + rsp->PersistentFileId, + rsp->VolatileFileId); if (rc) cifs_put_tcon(tcon); |