| From 0291d341c42d2be8e72ec6ac68730aa09e05ccbf Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sun, 31 Dec 2023 16:19:18 +0900 |
| Subject: ksmbd: lazy v2 lease break on smb2_write() |
| |
| From: Namjae Jeon <linkinjeon@kernel.org> |
| |
| [ Upstream commit c2a721eead71202a0d8ddd9b56ec8dce652c71d1 ] |
| |
| Don't immediately send directory lease break notification on smb2_write(). |
| Instead, It postpones it until smb2_close(). |
| |
| Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> |
| Signed-off-by: Steve French <stfrench@microsoft.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/smb/server/oplock.c | 45 +++++++++++++++++++++++++++++++++++++-- |
| fs/smb/server/oplock.h | 1 + |
| fs/smb/server/vfs.c | 3 +++ |
| fs/smb/server/vfs_cache.h | 1 + |
| 4 files changed, 48 insertions(+), 2 deletions(-) |
| |
| diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c |
| index 147d98427ce89..562b180459a1a 100644 |
| --- a/fs/smb/server/oplock.c |
| +++ b/fs/smb/server/oplock.c |
| @@ -396,8 +396,8 @@ void close_id_del_oplock(struct ksmbd_file *fp) |
| { |
| struct oplock_info *opinfo; |
| |
| - if (S_ISDIR(file_inode(fp->filp)->i_mode)) |
| - return; |
| + if (fp->reserve_lease_break) |
| + smb_lazy_parent_lease_break_close(fp); |
| |
| opinfo = opinfo_get(fp); |
| if (!opinfo) |
| @@ -1127,6 +1127,47 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, |
| ksmbd_inode_put(p_ci); |
| } |
| |
| +void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp) |
| +{ |
| + struct oplock_info *opinfo; |
| + struct ksmbd_inode *p_ci = NULL; |
| + |
| + rcu_read_lock(); |
| + opinfo = rcu_dereference(fp->f_opinfo); |
| + rcu_read_unlock(); |
| + |
| + if (!opinfo->is_lease || opinfo->o_lease->version != 2) |
| + return; |
| + |
| + p_ci = ksmbd_inode_lookup_lock(fp->filp->f_path.dentry->d_parent); |
| + if (!p_ci) |
| + return; |
| + |
| + read_lock(&p_ci->m_lock); |
| + list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) { |
| + if (!opinfo->is_lease) |
| + continue; |
| + |
| + if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE) { |
| + if (!atomic_inc_not_zero(&opinfo->refcount)) |
| + continue; |
| + |
| + atomic_inc(&opinfo->conn->r_count); |
| + if (ksmbd_conn_releasing(opinfo->conn)) { |
| + atomic_dec(&opinfo->conn->r_count); |
| + continue; |
| + } |
| + read_unlock(&p_ci->m_lock); |
| + oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE); |
| + opinfo_conn_put(opinfo); |
| + read_lock(&p_ci->m_lock); |
| + } |
| + } |
| + read_unlock(&p_ci->m_lock); |
| + |
| + ksmbd_inode_put(p_ci); |
| +} |
| + |
| /** |
| * smb_grant_oplock() - handle oplock/lease request on file open |
| * @work: smb work |
| diff --git a/fs/smb/server/oplock.h b/fs/smb/server/oplock.h |
| index b64d1536882a1..5b93ea9196c01 100644 |
| --- a/fs/smb/server/oplock.h |
| +++ b/fs/smb/server/oplock.h |
| @@ -129,4 +129,5 @@ int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci, |
| void destroy_lease_table(struct ksmbd_conn *conn); |
| void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, |
| struct lease_ctx_info *lctx); |
| +void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp); |
| #endif /* __KSMBD_OPLOCK_H */ |
| diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c |
| index 9091dcd7a3102..4277750a6da1b 100644 |
| --- a/fs/smb/server/vfs.c |
| +++ b/fs/smb/server/vfs.c |
| @@ -517,6 +517,9 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp, |
| } |
| } |
| |
| + /* Reserve lease break for parent dir at closing time */ |
| + fp->reserve_lease_break = true; |
| + |
| /* Do we need to break any of a levelII oplock? */ |
| smb_break_all_levII_oplock(work, fp, 1); |
| |
| diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h |
| index 4d4938d6029b6..a528f0cc775ae 100644 |
| --- a/fs/smb/server/vfs_cache.h |
| +++ b/fs/smb/server/vfs_cache.h |
| @@ -105,6 +105,7 @@ struct ksmbd_file { |
| struct ksmbd_readdir_data readdir_data; |
| int dot_dotdot[2]; |
| unsigned int f_state; |
| + bool reserve_lease_break; |
| }; |
| |
| static inline void set_ctx_actor(struct dir_context *ctx, |
| -- |
| 2.43.0 |
| |