diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-05-01 10:43:44 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-05-01 10:43:44 -0700 |
commit | 26c009dffca89b0f8fe7facc41d1ccf88a66825a (patch) | |
tree | f143502f054a95eef7c48816e7bfa970a14cd6e4 /fs/cifs | |
parent | ed9a65e575cc3c52a7f130d824671fe48a72da0c (diff) | |
parent | 9be11a69315e26363a4de8930bc50d0901a96775 (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.h | 4 | ||||
-rw-r--r-- | fs/cifs/connect.c | 8 | ||||
-rw-r--r-- | fs/cifs/file.c | 16 | ||||
-rw-r--r-- | fs/cifs/misc.c | 8 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 115 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 20 |
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; |