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 <pshilov@microsoft.com> Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Родитель
e0fc5b1153
Коммит
d919131935
|
@ -1061,7 +1061,7 @@ cap_unix(struct cifs_ses *ses)
|
|||
struct cached_fid {
|
||||
bool is_valid:1; /* Do we have a useable root fid */
|
||||
bool file_all_info_is_valid:1;
|
||||
|
||||
bool has_lease:1;
|
||||
struct kref refcount;
|
||||
struct cifs_fid *fid;
|
||||
struct mutex fid_mutex;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "cifsproto.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "smb2proto.h"
|
||||
#include "fscache.h"
|
||||
#include "smbdirect.h"
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
|
@ -112,6 +113,8 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
|
|||
|
||||
mutex_lock(&tcon->crfid.fid_mutex);
|
||||
tcon->crfid.is_valid = false;
|
||||
/* cached handle is not valid, so SMB2_CLOSE won't be sent below */
|
||||
close_shroot_lease_locked(&tcon->crfid);
|
||||
memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
|
||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||
|
||||
|
|
|
@ -616,6 +616,7 @@ smb2_close_cached_fid(struct kref *ref)
|
|||
cfid->fid->volatile_fid);
|
||||
cfid->is_valid = false;
|
||||
cfid->file_all_info_is_valid = false;
|
||||
cfid->has_lease = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -626,13 +627,28 @@ void close_shroot(struct cached_fid *cfid)
|
|||
mutex_unlock(&cfid->fid_mutex);
|
||||
}
|
||||
|
||||
void close_shroot_lease_locked(struct cached_fid *cfid)
|
||||
{
|
||||
if (cfid->has_lease) {
|
||||
cfid->has_lease = false;
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
}
|
||||
}
|
||||
|
||||
void close_shroot_lease(struct cached_fid *cfid)
|
||||
{
|
||||
mutex_lock(&cfid->fid_mutex);
|
||||
close_shroot_lease_locked(cfid);
|
||||
mutex_unlock(&cfid->fid_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
smb2_cached_lease_break(struct work_struct *work)
|
||||
{
|
||||
struct cached_fid *cfid = container_of(work,
|
||||
struct cached_fid, lease_break);
|
||||
|
||||
close_shroot(cfid);
|
||||
close_shroot_lease(cfid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -773,6 +789,7 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
|||
/* BB TBD check to see if oplock level check can be removed below */
|
||||
if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
|
||||
kref_get(&tcon->crfid.refcount);
|
||||
tcon->crfid.has_lease = true;
|
||||
smb2_parse_contexts(server, o_rsp,
|
||||
&oparms.fid->epoch,
|
||||
oparms.fid->lease_key, &oplock, NULL);
|
||||
|
|
|
@ -1847,8 +1847,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
|
|||
if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
|
||||
return 0;
|
||||
|
||||
if (tcon->crfid.is_valid)
|
||||
close_shroot(&tcon->crfid);
|
||||
close_shroot_lease(&tcon->crfid);
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, (void **) &req,
|
||||
&total_len);
|
||||
|
|
|
@ -70,6 +70,8 @@ extern int smb3_handle_read_data(struct TCP_Server_Info *server,
|
|||
extern int open_shroot(unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_fid *pfid);
|
||||
extern void close_shroot(struct cached_fid *cfid);
|
||||
extern void close_shroot_lease(struct cached_fid *cfid);
|
||||
extern void close_shroot_lease_locked(struct cached_fid *cfid);
|
||||
extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
|
||||
struct smb2_file_all_info *src);
|
||||
extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
|
Загрузка…
Ссылка в новой задаче