summaryrefslogtreecommitdiff
path: root/fs/cifs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-05-01 10:43:44 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2023-05-01 10:43:44 -0700
commit26c009dffca89b0f8fe7facc41d1ccf88a66825a (patch)
treef143502f054a95eef7c48816e7bfa970a14cd6e4 /fs/cifs
parented9a65e575cc3c52a7f130d824671fe48a72da0c (diff)
parent9be11a69315e26363a4de8930bc50d0901a96775 (diff)
Merge tag '6.4-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French: - deferred close fix for an important case when cached file should be closed immediately - two fixes for missing locks - eight minor cleanup * tag '6.4-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6: cifs: update internal module version number for cifs.ko smb3: move some common open context structs to smbfs_common smb3: make query_on_disk_id open context consistent and move to common code SMB3.1.1: add new tree connect ShareFlags cifs: missing lock when updating session status SMB3: Close deferred file handles in case of handle lease break SMB3: Add missing locks to protect deferred close file list cifs: Avoid a cast in add_lease_context() cifs: Simplify SMB2_open_init() cifs: Simplify SMB2_open_init() cifs: Simplify SMB2_open_init()
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsfs.h4
-rw-r--r--fs/cifs/connect.c8
-rw-r--r--fs/cifs/file.c16
-rw-r--r--fs/cifs/misc.c8
-rw-r--r--fs/cifs/smb2pdu.c115
-rw-r--r--fs/cifs/smb2pdu.h20
6 files changed, 61 insertions, 110 deletions
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 415176b2cf32..74cd6fafb33e 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -162,6 +162,6 @@ extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */
/* when changing internal version - update following two lines at same time */
-#define SMB3_PRODUCT_BUILD 41
-#define CIFS_VERSION "2.42"
+#define SMB3_PRODUCT_BUILD 43
+#define CIFS_VERSION "2.43"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 1cbb90587995..7bfef741f758 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1916,18 +1916,22 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
/* ses_count can never go negative */
WARN_ON(ses->ses_count < 0);
+ spin_lock(&ses->ses_lock);
if (ses->ses_status == SES_GOOD)
ses->ses_status = SES_EXITING;
- cifs_free_ipc(ses);
-
if (ses->ses_status == SES_EXITING && server->ops->logoff) {
+ spin_unlock(&ses->ses_lock);
+ cifs_free_ipc(ses);
xid = get_xid();
rc = server->ops->logoff(xid, ses);
if (rc)
cifs_server_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
__func__, rc);
_free_xid(xid);
+ } else {
+ spin_unlock(&ses->ses_lock);
+ cifs_free_ipc(ses);
}
spin_lock(&cifs_tcp_ses_lock);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index b33d2e7b0f98..c5fcefdfd797 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -4882,6 +4882,8 @@ void cifs_oplock_break(struct work_struct *work)
struct TCP_Server_Info *server = tcon->ses->server;
int rc = 0;
bool purge_cache = false;
+ struct cifs_deferred_close *dclose;
+ bool is_deferred = false;
wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS,
TASK_UNINTERRUPTIBLE);
@@ -4918,6 +4920,20 @@ void cifs_oplock_break(struct work_struct *work)
oplock_break_ack:
/*
+ * When oplock break is received and there are no active
+ * file handles but cached, then schedule deferred close immediately.
+ * So, new open will not use cached handle.
+ */
+ spin_lock(&CIFS_I(inode)->deferred_lock);
+ is_deferred = cifs_is_deferred_close(cfile, &dclose);
+ spin_unlock(&CIFS_I(inode)->deferred_lock);
+
+ if (!CIFS_CACHE_HANDLE(cinode) && is_deferred &&
+ cfile->deferred_close_scheduled && delayed_work_pending(&cfile->deferred)) {
+ cifs_close_deferred_file(cinode);
+ }
+
+ /*
* releasing stale oplock after recent reconnect of smb session using
* a now incorrect file handle is not a data integrity issue but do
* not bother sending an oplock release if session to server still is
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 7f085ed2d866..cd914be905b2 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -749,7 +749,9 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
list_for_each_entry(cfile, &cifs_inode->openFileList, flist) {
if (delayed_work_pending(&cfile->deferred)) {
if (cancel_delayed_work(&cfile->deferred)) {
+ spin_lock(&cifs_inode->deferred_lock);
cifs_del_deferred_close(cfile);
+ spin_unlock(&cifs_inode->deferred_lock);
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
if (tmp_list == NULL)
@@ -762,7 +764,7 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
spin_unlock(&cifs_inode->open_file_lock);
list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
- _cifsFileInfo_put(tmp_list->cfile, true, false);
+ _cifsFileInfo_put(tmp_list->cfile, false, false);
list_del(&tmp_list->list);
kfree(tmp_list);
}
@@ -780,7 +782,9 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
list_for_each_entry(cfile, &tcon->openFileList, tlist) {
if (delayed_work_pending(&cfile->deferred)) {
if (cancel_delayed_work(&cfile->deferred)) {
+ spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
cifs_del_deferred_close(cfile);
+ spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
if (tmp_list == NULL)
@@ -815,7 +819,9 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)
if (strstr(full_path, path)) {
if (delayed_work_pending(&cfile->deferred)) {
if (cancel_delayed_work(&cfile->deferred)) {
+ spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
cifs_del_deferred_close(cfile);
+ spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
if (tmp_list == NULL)
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 366f0c3b799b..0521aa1da644 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -821,7 +821,6 @@ create_posix_buf(umode_t mode)
static int
add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
{
- struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;
iov[num].iov_base = create_posix_buf(mode);
@@ -830,11 +829,6 @@ add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
if (iov[num].iov_base == NULL)
return -ENOMEM;
iov[num].iov_len = sizeof(struct create_posix);
- if (!req->CreateContextsOffset)
- req->CreateContextsOffset = cpu_to_le32(
- sizeof(struct smb2_create_req) +
- iov[num - 1].iov_len);
- le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_posix));
*num_iovec = num + 1;
return 0;
}
@@ -2069,7 +2063,7 @@ create_reconnect_durable_buf(struct cifs_fid *fid)
static void
parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf)
{
- struct create_on_disk_id *pdisk_id = (struct create_on_disk_id *)cc;
+ struct create_disk_id_rsp *pdisk_id = (struct create_disk_id_rsp *)cc;
cifs_dbg(FYI, "parse query id context 0x%llx 0x%llx\n",
pdisk_id->DiskFileId, pdisk_id->VolumeId);
@@ -2172,10 +2166,11 @@ smb2_parse_contexts(struct TCP_Server_Info *server,
}
static int
-add_lease_context(struct TCP_Server_Info *server, struct kvec *iov,
+add_lease_context(struct TCP_Server_Info *server,
+ struct smb2_create_req *req,
+ struct kvec *iov,
unsigned int *num_iovec, u8 *lease_key, __u8 *oplock)
{
- struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;
iov[num].iov_base = server->ops->create_lease_buf(lease_key, *oplock);
@@ -2183,12 +2178,6 @@ add_lease_context(struct TCP_Server_Info *server, struct kvec *iov,
return -ENOMEM;
iov[num].iov_len = server->vals->create_lease_size;
req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
- if (!req->CreateContextsOffset)
- req->CreateContextsOffset = cpu_to_le32(
- sizeof(struct smb2_create_req) +
- iov[num - 1].iov_len);
- le32_add_cpu(&req->CreateContextsLength,
- server->vals->create_lease_size);
*num_iovec = num + 1;
return 0;
}
@@ -2267,18 +2256,12 @@ static int
add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec,
struct cifs_open_parms *oparms)
{
- struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;
iov[num].iov_base = create_durable_v2_buf(oparms);
if (iov[num].iov_base == NULL)
return -ENOMEM;
iov[num].iov_len = sizeof(struct create_durable_v2);
- if (!req->CreateContextsOffset)
- req->CreateContextsOffset =
- cpu_to_le32(sizeof(struct smb2_create_req) +
- iov[1].iov_len);
- le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable_v2));
*num_iovec = num + 1;
return 0;
}
@@ -2287,7 +2270,6 @@ static int
add_durable_reconnect_v2_context(struct kvec *iov, unsigned int *num_iovec,
struct cifs_open_parms *oparms)
{
- struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;
/* indicate that we don't need to relock the file */
@@ -2297,12 +2279,6 @@ add_durable_reconnect_v2_context(struct kvec *iov, unsigned int *num_iovec,
if (iov[num].iov_base == NULL)
return -ENOMEM;
iov[num].iov_len = sizeof(struct create_durable_handle_reconnect_v2);
- if (!req->CreateContextsOffset)
- req->CreateContextsOffset =
- cpu_to_le32(sizeof(struct smb2_create_req) +
- iov[1].iov_len);
- le32_add_cpu(&req->CreateContextsLength,
- sizeof(struct create_durable_handle_reconnect_v2));
*num_iovec = num + 1;
return 0;
}
@@ -2311,7 +2287,6 @@ static int
add_durable_context(struct kvec *iov, unsigned int *num_iovec,
struct cifs_open_parms *oparms, bool use_persistent)
{
- struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;
if (use_persistent) {
@@ -2331,11 +2306,6 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec,
if (iov[num].iov_base == NULL)
return -ENOMEM;
iov[num].iov_len = sizeof(struct create_durable);
- if (!req->CreateContextsOffset)
- req->CreateContextsOffset =
- cpu_to_le32(sizeof(struct smb2_create_req) +
- iov[1].iov_len);
- le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable));
*num_iovec = num + 1;
return 0;
}
@@ -2369,18 +2339,12 @@ create_twarp_buf(__u64 timewarp)
static int
add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp)
{
- struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;
iov[num].iov_base = create_twarp_buf(timewarp);
if (iov[num].iov_base == NULL)
return -ENOMEM;
iov[num].iov_len = sizeof(struct crt_twarp_ctxt);
- if (!req->CreateContextsOffset)
- req->CreateContextsOffset = cpu_to_le32(
- sizeof(struct smb2_create_req) +
- iov[num - 1].iov_len);
- le32_add_cpu(&req->CreateContextsLength, sizeof(struct crt_twarp_ctxt));
*num_iovec = num + 1;
return 0;
}
@@ -2503,7 +2467,6 @@ create_sd_buf(umode_t mode, bool set_owner, unsigned int *len)
static int
add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode, bool set_owner)
{
- struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;
unsigned int len = 0;
@@ -2511,11 +2474,6 @@ add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode, bool set
if (iov[num].iov_base == NULL)
return -ENOMEM;
iov[num].iov_len = len;
- if (!req->CreateContextsOffset)
- req->CreateContextsOffset = cpu_to_le32(
- sizeof(struct smb2_create_req) +
- iov[num - 1].iov_len);
- le32_add_cpu(&req->CreateContextsLength, len);
*num_iovec = num + 1;
return 0;
}
@@ -2546,18 +2504,12 @@ create_query_id_buf(void)
static int
add_query_id_context(struct kvec *iov, unsigned int *num_iovec)
{
- struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;
iov[num].iov_base = create_query_id_buf();
if (iov[num].iov_base == NULL)
return -ENOMEM;
iov[num].iov_len = sizeof(struct crt_query_id_ctxt);
- if (!req->CreateContextsOffset)
- req->CreateContextsOffset = cpu_to_le32(
- sizeof(struct smb2_create_req) +
- iov[num - 1].iov_len);
- le32_add_cpu(&req->CreateContextsLength, sizeof(struct crt_query_id_ctxt));
*num_iovec = num + 1;
return 0;
}
@@ -2720,6 +2672,9 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
rc = add_posix_context(iov, &n_iov, mode);
if (rc)
goto err_free_req;
+ req->CreateContextsOffset = cpu_to_le32(
+ sizeof(struct smb2_create_req) +
+ iov[1].iov_len);
pc_buf = iov[n_iov-1].iov_base;
}
@@ -2857,21 +2812,13 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
(oparms->create_options & CREATE_NOT_FILE))
req->RequestedOplockLevel = *oplock; /* no srv lease support */
else {
- rc = add_lease_context(server, iov, &n_iov,
+ rc = add_lease_context(server, req, iov, &n_iov,
oparms->fid->lease_key, oplock);
if (rc)
return rc;
}
if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) {
- /* need to set Next field of lease context if we request it */
- if (server->capabilities & SMB2_GLOBAL_CAP_LEASING) {
- struct create_context *ccontext =
- (struct create_context *)iov[n_iov-1].iov_base;
- ccontext->Next =
- cpu_to_le32(server->vals->create_lease_size);
- }
-
rc = add_durable_context(iov, &n_iov, oparms,
tcon->use_persistent);
if (rc)
@@ -2879,13 +2826,6 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
}
if (tcon->posix_extensions) {
- if (n_iov > 2) {
- struct create_context *ccontext =
- (struct create_context *)iov[n_iov-1].iov_base;
- ccontext->Next =
- cpu_to_le32(iov[n_iov-1].iov_len);
- }
-
rc = add_posix_context(iov, &n_iov, oparms->mode);
if (rc)
return rc;
@@ -2893,13 +2833,6 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
if (tcon->snapshot_time) {
cifs_dbg(FYI, "adding snapshot context\n");
- if (n_iov > 2) {
- struct create_context *ccontext =
- (struct create_context *)iov[n_iov-1].iov_base;
- ccontext->Next =
- cpu_to_le32(iov[n_iov-1].iov_len);
- }
-
rc = add_twarp_context(iov, &n_iov, tcon->snapshot_time);
if (rc)
return rc;
@@ -2923,12 +2856,6 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
set_owner = false;
if (set_owner | set_mode) {
- if (n_iov > 2) {
- struct create_context *ccontext =
- (struct create_context *)iov[n_iov-1].iov_base;
- ccontext->Next = cpu_to_le32(iov[n_iov-1].iov_len);
- }
-
cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode);
rc = add_sd_context(iov, &n_iov, oparms->mode, set_owner);
if (rc)
@@ -2936,12 +2863,30 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
}
}
+ add_query_id_context(iov, &n_iov);
+
if (n_iov > 2) {
- struct create_context *ccontext =
- (struct create_context *)iov[n_iov-1].iov_base;
- ccontext->Next = cpu_to_le32(iov[n_iov-1].iov_len);
+ /*
+ * We have create contexts behind iov[1] (the file
+ * name), point at them from the main create request
+ */
+ req->CreateContextsOffset = cpu_to_le32(
+ sizeof(struct smb2_create_req) +
+ iov[1].iov_len);
+ req->CreateContextsLength = 0;
+
+ for (unsigned int i = 2; i < (n_iov-1); i++) {
+ struct kvec *v = &iov[i];
+ size_t len = v->iov_len;
+ struct create_context *cctx =
+ (struct create_context *)v->iov_base;
+
+ cctx->Next = cpu_to_le32(len);
+ le32_add_cpu(&req->CreateContextsLength, len);
+ }
+ le32_add_cpu(&req->CreateContextsLength,
+ iov[n_iov-1].iov_len);
}
- add_query_id_context(iov, &n_iov);
rqst->rq_nvec = n_iov;
return 0;
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 2114e8a0c63a..220994d0a0f7 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -132,17 +132,6 @@ struct share_redirect_error_context_rsp {
#define SMB2_LEASE_HANDLE_CACHING_HE 0x02
#define SMB2_LEASE_WRITE_CACHING_HE 0x04
-struct create_durable {
- struct create_context ccontext;
- __u8 Name[8];
- union {
- __u8 Reserved[16];
- struct {
- __u64 PersistentFileId;
- __u64 VolatileFileId;
- } Fid;
- } Data;
-} __packed;
/* See MS-SMB2 2.2.13.2.11 */
/* Flags */
@@ -170,15 +159,6 @@ struct durable_reconnect_context_v2 {
__le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
} __packed;
-/* See MS-SMB2 2.2.14.2.9 */
-struct create_on_disk_id {
- struct create_context ccontext;
- __u8 Name[8];
- __le64 DiskFileId;
- __le64 VolumeId;
- __u32 Reserved[4];
-} __packed;
-
/* See MS-SMB2 2.2.14.2.12 */
struct durable_reconnect_context_v2_rsp {
__le32 Timeout;