mirror of
https://github.com/torvalds/linux.git
synced 2026-07-29 10:41:49 +02:00
ksmbd: close superseded durable handles through refcount handoff
ksmbd_close_disconnected_durable_delete_on_close() collects disconnected
durable handles for a name being superseded by a new delete-on-close
open, drops ci->m_lock, then closes each collected handle directly with
__ksmbd_close_fd().
That bypasses the FP_CLOSED and refcount handoff used by the other close
paths. If a durable reconnect or the durable scavenger already took a
reference to the same fp, the direct __ksmbd_close_fd() can free the
ksmbd_file while that other holder still owns a live reference.
Claim the disconnected durable handle before unlinking it from m_fp_list.
While holding ci->m_lock and global_ft.lock, only take ownership when the
durable lifetime reference is the only remaining reference. Then take a
transient reference, remove the fp from global_ft, mark it FP_CLOSED, and
move it to the local dispose list. If another holder already has a
reference, leave the fp linked and let that holder complete its path.
The dispose loop then drops both references owned by the claim. This keeps
the force-close path in the same refcount handoff model as the durable
scavenger and avoids leaving a live reconnected fp detached from
m_fp_list.
Fixes: 166e4c0702 ("ksmbd: supersede disconnected delete-on-close durable handle")
Signed-off-by: Gil Portnoy <dddhkts1@gmail.com>
Co-developed-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
3863716350
commit
c706195e5e
|
|
@ -581,7 +581,20 @@ bool ksmbd_close_disconnected_durable_delete_on_close(struct dentry *dentry)
|
|||
if (fp->conn || !fp->is_durable ||
|
||||
fp->f_state != FP_INITED)
|
||||
continue;
|
||||
list_move_tail(&fp->node, &dispose);
|
||||
|
||||
/*
|
||||
* Claim the close before unlinking fp from m_fp_list.
|
||||
* refcount == 1 means only the durable lifetime ref is
|
||||
* left. Add a transient ref so final close can drop both.
|
||||
*/
|
||||
write_lock(&global_ft.lock);
|
||||
if (atomic_read(&fp->refcount) == 1) {
|
||||
atomic_inc(&fp->refcount);
|
||||
__ksmbd_remove_durable_fd(fp);
|
||||
ksmbd_mark_fp_closed(fp);
|
||||
list_move_tail(&fp->node, &dispose);
|
||||
}
|
||||
write_unlock(&global_ft.lock);
|
||||
}
|
||||
}
|
||||
up_write(&ci->m_lock);
|
||||
|
|
@ -589,16 +602,18 @@ bool ksmbd_close_disconnected_durable_delete_on_close(struct dentry *dentry)
|
|||
/*
|
||||
* Drop our lookup reference before closing so the last __ksmbd_close_fd()
|
||||
* can drop m_count to zero and unlink the delete-on-close file. The
|
||||
* collected handles still hold references, so ci stays valid until they
|
||||
* are closed below.
|
||||
* collected handles still hold the transient reference taken above, so
|
||||
* ci stays valid until they are closed below.
|
||||
*/
|
||||
ksmbd_inode_put(ci);
|
||||
|
||||
while (!list_empty(&dispose)) {
|
||||
fp = list_first_entry(&dispose, struct ksmbd_file, node);
|
||||
list_del_init(&fp->node);
|
||||
__ksmbd_close_fd(NULL, fp);
|
||||
closed = true;
|
||||
if (atomic_sub_and_test(2, &fp->refcount)) {
|
||||
__ksmbd_close_fd(NULL, fp);
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return closed;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user