[PATCH 2/7] ksmbd: route stream FileDispositionInformation through stream delete flag
"Gaël Blivet-Bailly" <[email protected]>
| Newsgroups | org.kernel.vger.linux-cifs |
|---|---|
| Message-ID | <[email protected]> |
From: Gael Blivet <[email protected]> set_file_disposition_info() calls ksmbd_set_inode_pending_delete() / ksmbd_clear_inode_pending_delete() unconditionally, which always sets S_DEL_PENDING on the whole inode (ci->m_flags), regardless of whether the handle being closed is a regular file or an alternate data stream. Requesting delete-pending on a single stream handle (e.g. deleting just an alternate data stream some clients keep alongside a file) would therefore incorrectly schedule deletion of the entire file's data, not just the stream. Add ksmbd_fd_set_delete_pending()/ksmbd_fd_clear_delete_pending(), following the same stream-vs-whole-file routing pattern already used by ksmbd_fd_set_delete_on_close() for the CREATE-time DeleteOnClose option, and switch set_file_disposition_info() to use them. Signed-off-by: Gael Blivet <[email protected]> --- fs/smb/server/smb2pdu.c | 4 ++-- fs/smb/server/vfs_cache.c | 32 ++++++++++++++++++++++++++++++++ fs/smb/server/vfs_cache.h | 2 ++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 39188bb84..e6d0f58d2 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -7117,9 +7117,9 @@ static int set_file_disposition_info(struct ksmbd_work *work, ksmbd_vfs_empty_dir(fp) == -ENOTEMPTY) return -EBUSY; smb_break_all_levII_oplock_for_delete(work, fp); - ksmbd_set_inode_pending_delete(fp); + ksmbd_fd_set_delete_pending(fp); } else { - ksmbd_clear_inode_pending_delete(fp); + ksmbd_fd_clear_delete_pending(fp); } return 0; } diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c index d95c405ea..2543dd7e8 100644 --- a/fs/smb/server/vfs_cache.c +++ b/fs/smb/server/vfs_cache.c @@ -294,6 +294,38 @@ void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp, up_write(&ci->m_lock); } +/* + * FileDispositionInformation (SET_INFO) on a stream handle must only + * mark the stream for deletion, not the whole file -- otherwise + * deleting a single alternate data stream (e.g. AFP_AfpInfo) deletes + * the entire file's data along with it. + */ +void ksmbd_fd_set_delete_pending(struct ksmbd_file *fp) +{ + struct ksmbd_inode *ci = fp->f_ci; + + if (ksmbd_stream_fd(fp)) { + down_write(&ci->m_lock); + ci->m_flags |= S_DEL_ON_CLS_STREAM; + up_write(&ci->m_lock); + } else { + ksmbd_set_inode_pending_delete(fp); + } +} + +void ksmbd_fd_clear_delete_pending(struct ksmbd_file *fp) +{ + struct ksmbd_inode *ci = fp->f_ci; + + if (ksmbd_stream_fd(fp)) { + down_write(&ci->m_lock); + ci->m_flags &= ~S_DEL_ON_CLS_STREAM; + up_write(&ci->m_lock); + } else { + ksmbd_clear_inode_pending_delete(fp); + } +} + static void ksmbd_inode_hash(struct ksmbd_inode *ci) { struct hlist_head *b = inode_hashtable + diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h index b9e27307a..111a4e315 100644 --- a/fs/smb/server/vfs_cache.h +++ b/fs/smb/server/vfs_cache.h @@ -214,6 +214,8 @@ void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp); void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp); void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp, int file_info); +void ksmbd_fd_set_delete_pending(struct ksmbd_file *fp); +void ksmbd_fd_clear_delete_pending(struct ksmbd_file *fp); int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp); int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share, struct ksmbd_file *fp, char *name); -- 2.43.0