cifs: add lease tracking to the cached root fid
Use a read lease for the cached root fid so that we can detect when the content of the directory changes (via a break) at which time we close the handle. On next access to the root the handle will be reopened and cached again. Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
2fbb56446f
commit
a93864d939
|
@ -883,6 +883,14 @@ cap_unix(struct cifs_ses *ses)
|
||||||
return ses->server->vals->cap_unix & ses->capabilities;
|
return ses->server->vals->cap_unix & ses->capabilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct cached_fid {
|
||||||
|
bool is_valid:1; /* Do we have a useable root fid */
|
||||||
|
struct cifs_fid *fid;
|
||||||
|
struct mutex fid_mutex;
|
||||||
|
struct cifs_tcon *tcon;
|
||||||
|
struct work_struct lease_break;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* there is one of these for each connection to a resource on a particular
|
* there is one of these for each connection to a resource on a particular
|
||||||
* session
|
* session
|
||||||
|
@ -987,9 +995,7 @@ struct cifs_tcon {
|
||||||
struct fscache_cookie *fscache; /* cookie for share */
|
struct fscache_cookie *fscache; /* cookie for share */
|
||||||
#endif
|
#endif
|
||||||
struct list_head pending_opens; /* list of incomplete opens */
|
struct list_head pending_opens; /* list of incomplete opens */
|
||||||
bool valid_root_fid:1; /* Do we have a useable root fid */
|
struct cached_fid crfid; /* Cached root fid */
|
||||||
struct mutex prfid_mutex; /* prevents reopen race after dead ses*/
|
|
||||||
struct cifs_fid *prfid; /* handle to the directory at top of share */
|
|
||||||
/* BB add field for back pointer to sb struct(s)? */
|
/* BB add field for back pointer to sb struct(s)? */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -552,6 +552,7 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
|
||||||
struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
|
struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
|
||||||
void cifs_aio_ctx_release(struct kref *refcount);
|
void cifs_aio_ctx_release(struct kref *refcount);
|
||||||
int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
|
int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
|
||||||
|
void smb2_cached_lease_break(struct work_struct *work);
|
||||||
|
|
||||||
int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
|
int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
|
||||||
struct sdesc **sdesc);
|
struct sdesc **sdesc);
|
||||||
|
|
|
@ -107,10 +107,10 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
|
||||||
}
|
}
|
||||||
spin_unlock(&tcon->open_file_lock);
|
spin_unlock(&tcon->open_file_lock);
|
||||||
|
|
||||||
mutex_lock(&tcon->prfid_mutex);
|
mutex_lock(&tcon->crfid.fid_mutex);
|
||||||
tcon->valid_root_fid = false;
|
tcon->crfid.is_valid = false;
|
||||||
memset(tcon->prfid, 0, sizeof(struct cifs_fid));
|
memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
|
||||||
mutex_unlock(&tcon->prfid_mutex);
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BB Add call to invalidate_inodes(sb) for all superblocks mounted
|
* BB Add call to invalidate_inodes(sb) for all superblocks mounted
|
||||||
|
|
|
@ -117,8 +117,9 @@ tconInfoAlloc(void)
|
||||||
INIT_LIST_HEAD(&ret_buf->openFileList);
|
INIT_LIST_HEAD(&ret_buf->openFileList);
|
||||||
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
||||||
spin_lock_init(&ret_buf->open_file_lock);
|
spin_lock_init(&ret_buf->open_file_lock);
|
||||||
mutex_init(&ret_buf->prfid_mutex);
|
mutex_init(&ret_buf->crfid.fid_mutex);
|
||||||
ret_buf->prfid = kzalloc(sizeof(struct cifs_fid), GFP_KERNEL);
|
ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid),
|
||||||
|
GFP_KERNEL);
|
||||||
#ifdef CONFIG_CIFS_STATS
|
#ifdef CONFIG_CIFS_STATS
|
||||||
spin_lock_init(&ret_buf->stat_lock);
|
spin_lock_init(&ret_buf->stat_lock);
|
||||||
#endif
|
#endif
|
||||||
|
@ -136,7 +137,7 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
|
||||||
atomic_dec(&tconInfoAllocCount);
|
atomic_dec(&tconInfoAllocCount);
|
||||||
kfree(buf_to_free->nativeFileSystem);
|
kfree(buf_to_free->nativeFileSystem);
|
||||||
kzfree(buf_to_free->password);
|
kzfree(buf_to_free->password);
|
||||||
kfree(buf_to_free->prfid);
|
kfree(buf_to_free->crfid.fid);
|
||||||
kfree(buf_to_free);
|
kfree(buf_to_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -492,10 +492,11 @@ cifs_ses_oplock_break(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct smb2_lease_break_work *lw = container_of(work,
|
struct smb2_lease_break_work *lw = container_of(work,
|
||||||
struct smb2_lease_break_work, lease_break);
|
struct smb2_lease_break_work, lease_break);
|
||||||
int rc;
|
int rc = 0;
|
||||||
|
|
||||||
rc = SMB2_lease_break(0, tlink_tcon(lw->tlink), lw->lease_key,
|
rc = SMB2_lease_break(0, tlink_tcon(lw->tlink), lw->lease_key,
|
||||||
lw->lease_state);
|
lw->lease_state);
|
||||||
|
|
||||||
cifs_dbg(FYI, "Lease release rc %d\n", rc);
|
cifs_dbg(FYI, "Lease release rc %d\n", rc);
|
||||||
cifs_put_tlink(lw->tlink);
|
cifs_put_tlink(lw->tlink);
|
||||||
kfree(lw);
|
kfree(lw);
|
||||||
|
@ -561,6 +562,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
|
||||||
|
|
||||||
open->oplock = lease_state;
|
open->oplock = lease_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,6 +605,18 @@ smb2_is_valid_lease_break(char *buffer)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
spin_unlock(&tcon->open_file_lock);
|
spin_unlock(&tcon->open_file_lock);
|
||||||
|
|
||||||
|
if (tcon->crfid.is_valid &&
|
||||||
|
!memcmp(rsp->LeaseKey,
|
||||||
|
tcon->crfid.fid->lease_key,
|
||||||
|
SMB2_LEASE_KEY_SIZE)) {
|
||||||
|
INIT_WORK(&tcon->crfid.lease_break,
|
||||||
|
smb2_cached_lease_break);
|
||||||
|
queue_work(cifsiod_wq,
|
||||||
|
&tcon->crfid.lease_break);
|
||||||
|
spin_unlock(&cifs_tcp_ses_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,6 +323,21 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
|
||||||
}
|
}
|
||||||
#endif /* STATS2 */
|
#endif /* STATS2 */
|
||||||
|
|
||||||
|
void
|
||||||
|
smb2_cached_lease_break(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct cached_fid *cfid = container_of(work,
|
||||||
|
struct cached_fid, lease_break);
|
||||||
|
mutex_lock(&cfid->fid_mutex);
|
||||||
|
if (cfid->is_valid) {
|
||||||
|
cifs_dbg(FYI, "clear cached root file handle\n");
|
||||||
|
SMB2_close(0, cfid->tcon, cfid->fid->persistent_fid,
|
||||||
|
cfid->fid->volatile_fid);
|
||||||
|
cfid->is_valid = false;
|
||||||
|
}
|
||||||
|
mutex_unlock(&cfid->fid_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open the directory at the root of a share
|
* Open the directory at the root of a share
|
||||||
*/
|
*/
|
||||||
|
@ -331,13 +346,13 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
||||||
struct cifs_open_parms oparams;
|
struct cifs_open_parms oparams;
|
||||||
int rc;
|
int rc;
|
||||||
__le16 srch_path = 0; /* Null - since an open of top of share */
|
__le16 srch_path = 0; /* Null - since an open of top of share */
|
||||||
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
u8 oplock = SMB2_OPLOCK_LEVEL_II;
|
||||||
|
|
||||||
mutex_lock(&tcon->prfid_mutex);
|
mutex_lock(&tcon->crfid.fid_mutex);
|
||||||
if (tcon->valid_root_fid) {
|
if (tcon->crfid.is_valid) {
|
||||||
cifs_dbg(FYI, "found a cached root file handle\n");
|
cifs_dbg(FYI, "found a cached root file handle\n");
|
||||||
memcpy(pfid, tcon->prfid, sizeof(struct cifs_fid));
|
memcpy(pfid, tcon->crfid.fid, sizeof(struct cifs_fid));
|
||||||
mutex_unlock(&tcon->prfid_mutex);
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,10 +365,11 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
||||||
|
|
||||||
rc = SMB2_open(xid, &oparams, &srch_path, &oplock, NULL, NULL, NULL);
|
rc = SMB2_open(xid, &oparams, &srch_path, &oplock, NULL, NULL, NULL);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
memcpy(tcon->prfid, pfid, sizeof(struct cifs_fid));
|
memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid));
|
||||||
tcon->valid_root_fid = true;
|
tcon->crfid.tcon = tcon;
|
||||||
|
tcon->crfid.is_valid = true;
|
||||||
}
|
}
|
||||||
mutex_unlock(&tcon->prfid_mutex);
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,7 +452,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
struct cifs_open_parms oparms;
|
struct cifs_open_parms oparms;
|
||||||
struct cifs_fid fid;
|
struct cifs_fid fid;
|
||||||
|
|
||||||
if ((*full_path == 0) && tcon->valid_root_fid)
|
if ((*full_path == 0) && tcon->crfid.is_valid)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
||||||
|
|
Loading…
Reference in New Issue