Skip to content

Commit d919131

Browse files
piastrysmfrench
authored andcommitted
CIFS: Close cached root handle only if it has a lease
SMB2_tdis() checks if a root handle is valid in order to decide whether it needs to close the handle or not. However if another thread has reference for the handle, it may end up with putting the reference twice. The extra reference that we want to put during the tree disconnect is the reference that has a directory lease. So, track the fact that we have a directory lease and close the handle only in that case. Signed-off-by: Pavel Shilovsky <[email protected]> Reviewed-by: Ronnie Sahlberg <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent e0fc5b1 commit d919131

File tree

5 files changed

+25
-4
lines changed

5 files changed

+25
-4
lines changed

fs/cifs/cifsglob.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ cap_unix(struct cifs_ses *ses)
10611061
struct cached_fid {
10621062
bool is_valid:1; /* Do we have a useable root fid */
10631063
bool file_all_info_is_valid:1;
1064-
1064+
bool has_lease:1;
10651065
struct kref refcount;
10661066
struct cifs_fid *fid;
10671067
struct mutex fid_mutex;

fs/cifs/cifssmb.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "cifsproto.h"
4343
#include "cifs_unicode.h"
4444
#include "cifs_debug.h"
45+
#include "smb2proto.h"
4546
#include "fscache.h"
4647
#include "smbdirect.h"
4748
#ifdef CONFIG_CIFS_DFS_UPCALL
@@ -112,6 +113,8 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
112113

113114
mutex_lock(&tcon->crfid.fid_mutex);
114115
tcon->crfid.is_valid = false;
116+
/* cached handle is not valid, so SMB2_CLOSE won't be sent below */
117+
close_shroot_lease_locked(&tcon->crfid);
115118
memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
116119
mutex_unlock(&tcon->crfid.fid_mutex);
117120

fs/cifs/smb2ops.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@ smb2_close_cached_fid(struct kref *ref)
616616
cfid->fid->volatile_fid);
617617
cfid->is_valid = false;
618618
cfid->file_all_info_is_valid = false;
619+
cfid->has_lease = false;
619620
}
620621
}
621622

@@ -626,13 +627,28 @@ void close_shroot(struct cached_fid *cfid)
626627
mutex_unlock(&cfid->fid_mutex);
627628
}
628629

630+
void close_shroot_lease_locked(struct cached_fid *cfid)
631+
{
632+
if (cfid->has_lease) {
633+
cfid->has_lease = false;
634+
kref_put(&cfid->refcount, smb2_close_cached_fid);
635+
}
636+
}
637+
638+
void close_shroot_lease(struct cached_fid *cfid)
639+
{
640+
mutex_lock(&cfid->fid_mutex);
641+
close_shroot_lease_locked(cfid);
642+
mutex_unlock(&cfid->fid_mutex);
643+
}
644+
629645
void
630646
smb2_cached_lease_break(struct work_struct *work)
631647
{
632648
struct cached_fid *cfid = container_of(work,
633649
struct cached_fid, lease_break);
634650

635-
close_shroot(cfid);
651+
close_shroot_lease(cfid);
636652
}
637653

638654
/*
@@ -773,6 +789,7 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
773789
/* BB TBD check to see if oplock level check can be removed below */
774790
if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
775791
kref_get(&tcon->crfid.refcount);
792+
tcon->crfid.has_lease = true;
776793
smb2_parse_contexts(server, o_rsp,
777794
&oparms.fid->epoch,
778795
oparms.fid->lease_key, &oplock, NULL);

fs/cifs/smb2pdu.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1847,8 +1847,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
18471847
if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
18481848
return 0;
18491849

1850-
if (tcon->crfid.is_valid)
1851-
close_shroot(&tcon->crfid);
1850+
close_shroot_lease(&tcon->crfid);
18521851

18531852
rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, (void **) &req,
18541853
&total_len);

fs/cifs/smb2proto.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ extern int smb3_handle_read_data(struct TCP_Server_Info *server,
7070
extern int open_shroot(unsigned int xid, struct cifs_tcon *tcon,
7171
struct cifs_fid *pfid);
7272
extern void close_shroot(struct cached_fid *cfid);
73+
extern void close_shroot_lease(struct cached_fid *cfid);
74+
extern void close_shroot_lease_locked(struct cached_fid *cfid);
7375
extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
7476
struct smb2_file_all_info *src);
7577
extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,

0 commit comments

Comments
 (0)