Commit 45db3ab7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '6.9-rc7-ksmbd-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:
 "Five ksmbd server fixes, all also for stable

   - Three fixes related to SMB3 leases (fixes two xfstests, and a
     locking issue)

   - Unitialized variable fix

   - Socket creation fix when bindv6only is set"

* tag '6.9-rc7-ksmbd-fixes' of git://git.samba.org/ksmbd:
  ksmbd: do not grant v2 lease if parent lease key and epoch are not set
  ksmbd: use rwsem instead of rwlock for lease break
  ksmbd: avoid to send duplicate lease break notifications
  ksmbd: off ipv6only for both ipv4/ipv6 binding
  ksmbd: fix uninitialized symbol 'share' in smb2_tree_connect()
parents 065a057a 691aae4f
...@@ -207,9 +207,9 @@ static void opinfo_add(struct oplock_info *opinfo) ...@@ -207,9 +207,9 @@ static void opinfo_add(struct oplock_info *opinfo)
{ {
struct ksmbd_inode *ci = opinfo->o_fp->f_ci; struct ksmbd_inode *ci = opinfo->o_fp->f_ci;
write_lock(&ci->m_lock); down_write(&ci->m_lock);
list_add_rcu(&opinfo->op_entry, &ci->m_op_list); list_add_rcu(&opinfo->op_entry, &ci->m_op_list);
write_unlock(&ci->m_lock); up_write(&ci->m_lock);
} }
static void opinfo_del(struct oplock_info *opinfo) static void opinfo_del(struct oplock_info *opinfo)
...@@ -221,9 +221,9 @@ static void opinfo_del(struct oplock_info *opinfo) ...@@ -221,9 +221,9 @@ static void opinfo_del(struct oplock_info *opinfo)
lease_del_list(opinfo); lease_del_list(opinfo);
write_unlock(&lease_list_lock); write_unlock(&lease_list_lock);
} }
write_lock(&ci->m_lock); down_write(&ci->m_lock);
list_del_rcu(&opinfo->op_entry); list_del_rcu(&opinfo->op_entry);
write_unlock(&ci->m_lock); up_write(&ci->m_lock);
} }
static unsigned long opinfo_count(struct ksmbd_file *fp) static unsigned long opinfo_count(struct ksmbd_file *fp)
...@@ -526,21 +526,18 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci, ...@@ -526,21 +526,18 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
* Compare lease key and client_guid to know request from same owner * Compare lease key and client_guid to know request from same owner
* of same client * of same client
*/ */
read_lock(&ci->m_lock); down_read(&ci->m_lock);
list_for_each_entry(opinfo, &ci->m_op_list, op_entry) { list_for_each_entry(opinfo, &ci->m_op_list, op_entry) {
if (!opinfo->is_lease || !opinfo->conn) if (!opinfo->is_lease || !opinfo->conn)
continue; continue;
read_unlock(&ci->m_lock);
lease = opinfo->o_lease; lease = opinfo->o_lease;
ret = compare_guid_key(opinfo, client_guid, lctx->lease_key); ret = compare_guid_key(opinfo, client_guid, lctx->lease_key);
if (ret) { if (ret) {
m_opinfo = opinfo; m_opinfo = opinfo;
/* skip upgrading lease about breaking lease */ /* skip upgrading lease about breaking lease */
if (atomic_read(&opinfo->breaking_cnt)) { if (atomic_read(&opinfo->breaking_cnt))
read_lock(&ci->m_lock);
continue; continue;
}
/* upgrading lease */ /* upgrading lease */
if ((atomic_read(&ci->op_count) + if ((atomic_read(&ci->op_count) +
...@@ -570,9 +567,8 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci, ...@@ -570,9 +567,8 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
lease_none_upgrade(opinfo, lctx->req_state); lease_none_upgrade(opinfo, lctx->req_state);
} }
} }
read_lock(&ci->m_lock);
} }
read_unlock(&ci->m_lock); up_read(&ci->m_lock);
return m_opinfo; return m_opinfo;
} }
...@@ -613,13 +609,23 @@ static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level) ...@@ -613,13 +609,23 @@ static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level)
if (opinfo->op_state == OPLOCK_CLOSING) if (opinfo->op_state == OPLOCK_CLOSING)
return -ENOENT; return -ENOENT;
else if (!opinfo->is_lease && opinfo->level <= req_op_level) else if (opinfo->level <= req_op_level) {
return 1; if (opinfo->is_lease &&
opinfo->o_lease->state !=
(SMB2_LEASE_HANDLE_CACHING_LE |
SMB2_LEASE_READ_CACHING_LE))
return 1;
}
} }
if (!opinfo->is_lease && opinfo->level <= req_op_level) { if (opinfo->level <= req_op_level) {
wake_up_oplock_break(opinfo); if (opinfo->is_lease &&
return 1; opinfo->o_lease->state !=
(SMB2_LEASE_HANDLE_CACHING_LE |
SMB2_LEASE_READ_CACHING_LE)) {
wake_up_oplock_break(opinfo);
return 1;
}
} }
return 0; return 0;
} }
...@@ -887,7 +893,6 @@ static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level) ...@@ -887,7 +893,6 @@ static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level)
struct lease *lease = brk_opinfo->o_lease; struct lease *lease = brk_opinfo->o_lease;
atomic_inc(&brk_opinfo->breaking_cnt); atomic_inc(&brk_opinfo->breaking_cnt);
err = oplock_break_pending(brk_opinfo, req_op_level); err = oplock_break_pending(brk_opinfo, req_op_level);
if (err) if (err)
return err < 0 ? err : 0; return err < 0 ? err : 0;
...@@ -1105,7 +1110,7 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, ...@@ -1105,7 +1110,7 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
if (!p_ci) if (!p_ci)
return; return;
read_lock(&p_ci->m_lock); down_read(&p_ci->m_lock);
list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) { list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) {
if (opinfo->conn == NULL || !opinfo->is_lease) if (opinfo->conn == NULL || !opinfo->is_lease)
continue; continue;
...@@ -1123,13 +1128,11 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, ...@@ -1123,13 +1128,11 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
continue; continue;
} }
read_unlock(&p_ci->m_lock);
oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE); oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
opinfo_conn_put(opinfo); opinfo_conn_put(opinfo);
read_lock(&p_ci->m_lock);
} }
} }
read_unlock(&p_ci->m_lock); up_read(&p_ci->m_lock);
ksmbd_inode_put(p_ci); ksmbd_inode_put(p_ci);
} }
...@@ -1150,7 +1153,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp) ...@@ -1150,7 +1153,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
if (!p_ci) if (!p_ci)
return; return;
read_lock(&p_ci->m_lock); down_read(&p_ci->m_lock);
list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) { list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) {
if (opinfo->conn == NULL || !opinfo->is_lease) if (opinfo->conn == NULL || !opinfo->is_lease)
continue; continue;
...@@ -1164,13 +1167,11 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp) ...@@ -1164,13 +1167,11 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
atomic_dec(&opinfo->conn->r_count); atomic_dec(&opinfo->conn->r_count);
continue; continue;
} }
read_unlock(&p_ci->m_lock);
oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE); oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
opinfo_conn_put(opinfo); opinfo_conn_put(opinfo);
read_lock(&p_ci->m_lock);
} }
} }
read_unlock(&p_ci->m_lock); up_read(&p_ci->m_lock);
ksmbd_inode_put(p_ci); ksmbd_inode_put(p_ci);
} }
...@@ -1200,7 +1201,9 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid, ...@@ -1200,7 +1201,9 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
/* Only v2 leases handle the directory */ /* Only v2 leases handle the directory */
if (S_ISDIR(file_inode(fp->filp)->i_mode)) { if (S_ISDIR(file_inode(fp->filp)->i_mode)) {
if (!lctx || lctx->version != 2) if (!lctx || lctx->version != 2 ||
(lctx->flags != SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE &&
!lctx->epoch))
return 0; return 0;
} }
...@@ -1465,8 +1468,9 @@ void create_lease_buf(u8 *rbuf, struct lease *lease) ...@@ -1465,8 +1468,9 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
buf->lcontext.LeaseFlags = lease->flags; buf->lcontext.LeaseFlags = lease->flags;
buf->lcontext.Epoch = cpu_to_le16(lease->epoch); buf->lcontext.Epoch = cpu_to_le16(lease->epoch);
buf->lcontext.LeaseState = lease->state; buf->lcontext.LeaseState = lease->state;
memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key, if (lease->flags == SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)
SMB2_LEASE_KEY_SIZE); memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key,
SMB2_LEASE_KEY_SIZE);
buf->ccontext.DataOffset = cpu_to_le16(offsetof buf->ccontext.DataOffset = cpu_to_le16(offsetof
(struct create_lease_v2, lcontext)); (struct create_lease_v2, lcontext));
buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context_v2)); buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context_v2));
...@@ -1525,8 +1529,9 @@ struct lease_ctx_info *parse_lease_state(void *open_req) ...@@ -1525,8 +1529,9 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
lreq->flags = lc->lcontext.LeaseFlags; lreq->flags = lc->lcontext.LeaseFlags;
lreq->epoch = lc->lcontext.Epoch; lreq->epoch = lc->lcontext.Epoch;
lreq->duration = lc->lcontext.LeaseDuration; lreq->duration = lc->lcontext.LeaseDuration;
memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey, if (lreq->flags == SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)
SMB2_LEASE_KEY_SIZE); memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
SMB2_LEASE_KEY_SIZE);
lreq->version = 2; lreq->version = 2;
} else { } else {
struct create_lease *lc = (struct create_lease *)cc; struct create_lease *lc = (struct create_lease *)cc;
......
...@@ -1926,7 +1926,7 @@ int smb2_tree_connect(struct ksmbd_work *work) ...@@ -1926,7 +1926,7 @@ int smb2_tree_connect(struct ksmbd_work *work)
struct ksmbd_session *sess = work->sess; struct ksmbd_session *sess = work->sess;
char *treename = NULL, *name = NULL; char *treename = NULL, *name = NULL;
struct ksmbd_tree_conn_status status; struct ksmbd_tree_conn_status status;
struct ksmbd_share_config *share; struct ksmbd_share_config *share = NULL;
int rc = -EINVAL; int rc = -EINVAL;
WORK_BUFFERS(work, req, rsp); WORK_BUFFERS(work, req, rsp);
...@@ -1988,7 +1988,7 @@ int smb2_tree_connect(struct ksmbd_work *work) ...@@ -1988,7 +1988,7 @@ int smb2_tree_connect(struct ksmbd_work *work)
write_unlock(&sess->tree_conns_lock); write_unlock(&sess->tree_conns_lock);
rsp->StructureSize = cpu_to_le16(16); rsp->StructureSize = cpu_to_le16(16);
out_err1: out_err1:
if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && share &&
test_share_config_flag(share, test_share_config_flag(share,
KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY)) KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY))
rsp->Capabilities = SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY; rsp->Capabilities = SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY;
...@@ -3376,9 +3376,9 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3376,9 +3376,9 @@ int smb2_open(struct ksmbd_work *work)
* after daccess, saccess, attrib_only, and stream are * after daccess, saccess, attrib_only, and stream are
* initialized. * initialized.
*/ */
write_lock(&fp->f_ci->m_lock); down_write(&fp->f_ci->m_lock);
list_add(&fp->node, &fp->f_ci->m_fp_list); list_add(&fp->node, &fp->f_ci->m_fp_list);
write_unlock(&fp->f_ci->m_lock); up_write(&fp->f_ci->m_lock);
/* Check delete pending among previous fp before oplock break */ /* Check delete pending among previous fp before oplock break */
if (ksmbd_inode_pending_delete(fp)) { if (ksmbd_inode_pending_delete(fp)) {
......
...@@ -646,7 +646,7 @@ int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp) ...@@ -646,7 +646,7 @@ int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp)
* Lookup fp in master fp list, and check desired access and * Lookup fp in master fp list, and check desired access and
* shared mode between previous open and current open. * shared mode between previous open and current open.
*/ */
read_lock(&curr_fp->f_ci->m_lock); down_read(&curr_fp->f_ci->m_lock);
list_for_each_entry(prev_fp, &curr_fp->f_ci->m_fp_list, node) { list_for_each_entry(prev_fp, &curr_fp->f_ci->m_fp_list, node) {
if (file_inode(filp) != file_inode(prev_fp->filp)) if (file_inode(filp) != file_inode(prev_fp->filp))
continue; continue;
...@@ -722,7 +722,7 @@ int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp) ...@@ -722,7 +722,7 @@ int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp)
break; break;
} }
} }
read_unlock(&curr_fp->f_ci->m_lock); up_read(&curr_fp->f_ci->m_lock);
return rc; return rc;
} }
......
...@@ -448,6 +448,10 @@ static int create_socket(struct interface *iface) ...@@ -448,6 +448,10 @@ static int create_socket(struct interface *iface)
sin6.sin6_family = PF_INET6; sin6.sin6_family = PF_INET6;
sin6.sin6_addr = in6addr_any; sin6.sin6_addr = in6addr_any;
sin6.sin6_port = htons(server_conf.tcp_port); sin6.sin6_port = htons(server_conf.tcp_port);
lock_sock(ksmbd_socket->sk);
ksmbd_socket->sk->sk_ipv6only = false;
release_sock(ksmbd_socket->sk);
} }
ksmbd_tcp_nodelay(ksmbd_socket); ksmbd_tcp_nodelay(ksmbd_socket);
......
...@@ -165,7 +165,7 @@ static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp) ...@@ -165,7 +165,7 @@ static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp)
ci->m_fattr = 0; ci->m_fattr = 0;
INIT_LIST_HEAD(&ci->m_fp_list); INIT_LIST_HEAD(&ci->m_fp_list);
INIT_LIST_HEAD(&ci->m_op_list); INIT_LIST_HEAD(&ci->m_op_list);
rwlock_init(&ci->m_lock); init_rwsem(&ci->m_lock);
ci->m_de = fp->filp->f_path.dentry; ci->m_de = fp->filp->f_path.dentry;
return 0; return 0;
} }
...@@ -261,14 +261,14 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp) ...@@ -261,14 +261,14 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp)
} }
if (atomic_dec_and_test(&ci->m_count)) { if (atomic_dec_and_test(&ci->m_count)) {
write_lock(&ci->m_lock); down_write(&ci->m_lock);
if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) { if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) {
ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING); ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING);
write_unlock(&ci->m_lock); up_write(&ci->m_lock);
ksmbd_vfs_unlink(filp); ksmbd_vfs_unlink(filp);
write_lock(&ci->m_lock); down_write(&ci->m_lock);
} }
write_unlock(&ci->m_lock); up_write(&ci->m_lock);
ksmbd_inode_free(ci); ksmbd_inode_free(ci);
} }
...@@ -289,9 +289,9 @@ static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp ...@@ -289,9 +289,9 @@ static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp
if (!has_file_id(fp->volatile_id)) if (!has_file_id(fp->volatile_id))
return; return;
write_lock(&fp->f_ci->m_lock); down_write(&fp->f_ci->m_lock);
list_del_init(&fp->node); list_del_init(&fp->node);
write_unlock(&fp->f_ci->m_lock); up_write(&fp->f_ci->m_lock);
write_lock(&ft->lock); write_lock(&ft->lock);
idr_remove(ft->idr, fp->volatile_id); idr_remove(ft->idr, fp->volatile_id);
...@@ -523,17 +523,17 @@ struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry) ...@@ -523,17 +523,17 @@ struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry)
if (!ci) if (!ci)
return NULL; return NULL;
read_lock(&ci->m_lock); down_read(&ci->m_lock);
list_for_each_entry(lfp, &ci->m_fp_list, node) { list_for_each_entry(lfp, &ci->m_fp_list, node) {
if (inode == file_inode(lfp->filp)) { if (inode == file_inode(lfp->filp)) {
atomic_dec(&ci->m_count); atomic_dec(&ci->m_count);
lfp = ksmbd_fp_get(lfp); lfp = ksmbd_fp_get(lfp);
read_unlock(&ci->m_lock); up_read(&ci->m_lock);
return lfp; return lfp;
} }
} }
atomic_dec(&ci->m_count); atomic_dec(&ci->m_count);
read_unlock(&ci->m_lock); up_read(&ci->m_lock);
return NULL; return NULL;
} }
...@@ -705,13 +705,13 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon, ...@@ -705,13 +705,13 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
conn = fp->conn; conn = fp->conn;
ci = fp->f_ci; ci = fp->f_ci;
write_lock(&ci->m_lock); down_write(&ci->m_lock);
list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) {
if (op->conn != conn) if (op->conn != conn)
continue; continue;
op->conn = NULL; op->conn = NULL;
} }
write_unlock(&ci->m_lock); up_write(&ci->m_lock);
fp->conn = NULL; fp->conn = NULL;
fp->tcon = NULL; fp->tcon = NULL;
...@@ -801,13 +801,13 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp) ...@@ -801,13 +801,13 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
fp->tcon = work->tcon; fp->tcon = work->tcon;
ci = fp->f_ci; ci = fp->f_ci;
write_lock(&ci->m_lock); down_write(&ci->m_lock);
list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) {
if (op->conn) if (op->conn)
continue; continue;
op->conn = fp->conn; op->conn = fp->conn;
} }
write_unlock(&ci->m_lock); up_write(&ci->m_lock);
__open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID); __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
if (!has_file_id(fp->volatile_id)) { if (!has_file_id(fp->volatile_id)) {
......
...@@ -47,7 +47,7 @@ struct stream { ...@@ -47,7 +47,7 @@ struct stream {
}; };
struct ksmbd_inode { struct ksmbd_inode {
rwlock_t m_lock; struct rw_semaphore m_lock;
atomic_t m_count; atomic_t m_count;
atomic_t op_count; atomic_t op_count;
/* opinfo count for streams */ /* opinfo count for streams */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment