summaryrefslogtreecommitdiff
path: root/fs
AgeCommit message (Collapse)AuthorFilesLines
2026-08-17ksmbd: retain connection for pending notify workNamjae Jeon3-1/+7
Deferred CHANGE_NOTIFY work keeps an async message ID after the original request work is released. A durable handle can outlive its connection, so the connection teardown can destroy its async IDA before the handle close releases the pending notify work. Give the synthetic deferred work a connection reference. Release it after the async ID in ksmbd_free_work_struct(). This keeps the async IDA alive until the deferred work is released, even when the original connection has already left the connection list. During server shutdown there is no client to receive a cleanup response. Skip the write and only release the pending work. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: preserve DOS attributes across truncating opensNamjae Jeon1-1/+8
An existing file can be opened with a truncating create request that supplies FileAttributes. Do not reset its cached DOS attributes while opening it. After a successful truncation, apply the requested attributes and store them in the DOS attribute xattr. This preserves READONLY when a truncating open requests that attribute. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: validate object id handles before response buffersNamjae Jeon1-5/+6
FSCTL_CREATE_OR_GET_OBJECT_ID requires a fixed-size output buffer, but an invalid file handle must take precedence over output buffer validation. Look up the handle before checking the available response buffer size. This returns STATUS_FILE_CLOSED for a closed handle while preserving the buffer size validation for valid handles. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: check base file delete pending for stream opensNamjae Jeon1-16/+6
A base file that has been marked for deletion remains present while stream handles are open. Name-based opens of either the base file or one of its streams must return STATUS_DELETE_PENDING during that interval. ksmbd_inode_pending_delete() returned only the per-handle stream state for stream handles. It therefore skipped the inode-wide S_DEL_PENDING state set by the base file delete-on-close path. As a result, a new stream open incorrectly succeeded. Check the inode-wide pending-delete state first for every handle. Only when the base file is not pending, check the per-handle stream state. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: synchronize lease breaks before renaming filesNamjae Jeon5-47/+78
Break read and handle caching leases before entering the VFS rename path. This keeps the destination name hidden until the lease holder acknowledges the break. Send the break synchronously before returning STATUS_PENDING for a rename. This avoids a race between the interim response and notification handling. Keep the existing asynchronous notification flow for all other lease break paths so chained breaks retain their ordering. Use the connection which owns the open for the notification. A lease table is shared by connections using the same client GUID. Its saved connection may belong to another active channel. Use it only when the owning channel is being released. Check directory sharing before issuing a break to avoid unnecessary lease breaks for a rename that must fail with a sharing violation. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: send lease breaks for handle-caching share conflictsNamjae Jeon1-2/+6
RH leases map to SMB2_OPLOCK_LEVEL_II because they do not include write caching. smb_grant_oplock() only sent break notifications for previous BATCH or EXCLUSIVE levels, so a conflicting open could skip the lease break when the existing lease was RH. That leaves the opener to fail or complete without the expected pending lease break sequence, instead of first asking the holder to drop handle caching. Treat share-mode conflicts against leases with HANDLE_CACHING as needing a break even when the mapped oplock level is LEVEL_II. This lets the server send the RH -> R lease break and wait for the normal break handling before continuing the conflicting open. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: validate file ids for query network interface infoNamjae Jeon1-0/+6
FSCTL_QUERY_NETWORK_INTERFACE_INFO is not tied to an open file handle. Clients send SMB2_NO_FID for both file id fields when issuing this request. Reject requests that provide any other file id before checking the output buffer size. This returns STATUS_INVALID_PARAMETER for invalid file ids instead of treating the request as valid or reporting STATUS_BUFFER_TOO_SMALL for a small output buffer. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: fall back to copy for duplicate extentsNamjae Jeon1-17/+31
FSCTL_DUPLICATE_EXTENTS_TO_FILE currently returns STATUS_NOT_SUPPORTED when vfs_clone_file_range() cannot clone the requested range. That can happen on filesystems without reflink support even though the server can still satisfy the request by copying the bytes. Validate the requested source range before attempting the operation. If the destination range extends past EOF, leave the destination size unchanged and complete the request without copying, matching observed client expectations for this ioctl. Reject sparse source to non-sparse destination requests as unsupported. Keep sparse destination and sparse-to-sparse cases on the normal clone or copy path. Reject overlapping same-file ranges as unsupported before attempting the clone or copy operation. Return the expected handle status for invalid handles. A closed target handle fails with STATUS_FILE_CLOSED, while a bad source handle embedded in the request buffer fails with STATUS_INVALID_HANDLE. Fall back to vfs_copy_file_range() whenever the clone operation does not copy the full requested length, and keep reporting an error only if the fallback also fails or copies a partial range. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: support file level trimNamjae Jeon4-1/+125
Advertise trim support through FS_SECTOR_SIZE_INFORMATION and handle FSCTL_FILE_LEVEL_TRIM requests. Process each trim range by punching a hole while keeping the file size unchanged, and report the number of ranges completed in the ioctl response. The trim operation uses the same byte-range lock handling as zero data for the affected part of the file. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: honor byte-range locks for zero dataNamjae Jeon2-1/+18
FSCTL_SET_ZERO_DATA changes file allocation state and must respect byte-range locks over the affected part of the file. Check the requested range, clipped to EOF, before issuing the fallocate operation. Return STATUS_FILE_LOCK_CONFLICT when the range conflicts with an existing lock. Ranges starting past EOF are left untouched by the lock check so they continue to succeed. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: fix permission checks for file allocation ioctlsNamjae Jeon1-1/+8
FSCTL_SET_SPARSE should not require FILE_WRITE_ATTRIBUTES only. A handle with FILE_WRITE_DATA or FILE_APPEND_DATA is also allowed to set the file allocation state, while FILE_WRITE_EA alone must still be rejected. FSCTL_QUERY_ALLOCATED_RANGES needs FILE_READ_DATA access. Reject handles that only have metadata access such as FILE_READ_ATTRIBUTES. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: handle allocated range queries on dense filesNamjae Jeon1-3/+26
FSCTL_QUERY_ALLOCATED_RANGES currently relies on SEEK_DATA and SEEK_HOLE for every file. That works for files with holes, but it is not a good match for dense files. A zeroed range in a dense file may be represented as an unwritten extent and skipped by SEEK_DATA. The server can then return no allocated ranges even though the file should still be treated as allocated from the protocol point of view. For dense files, report the requested range clipped to EOF as allocated instead of probing holes. Keep using SEEK_DATA and SEEK_HOLE for files marked with FILE_ATTRIBUTE_SPARSE_FILE, and wait for writeback before probing so punch-hole updates are visible to the filesystem seek implementation. This fixes the case where a query after zeroing data could return no ranges for a dense file. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: quiet mdssvc RPC log spam in create_smb2_pipeGael Blivet1-1/+10
silenced __rpc_method()'s own "Unsupported RPC: mdssvc" log line but missed that ksmbd_session_rpc_open() failing for that same, now-still-rejected pipe also trips a second, separate pr_err() here in its caller. macOS's routine mdssvc (Spotlight) probes still spam the kernel log via this second site on every single probe, defeating the original commit's stated purpose. Suppress this specific case the same way the other site does; behavior is unchanged for every other RPC failure. __rpc_method() (mgmt/user_session.c) returns -ENOENT for mdssvc, not -EINVAL. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: report actual xattr value length in stream enumerationGael Blivet1-2/+16
get_file_stream_info() (FileStreamInformation QUERY_INFO) reported each enumerated stream's StreamSize/StreamAllocationSize as stream_name_len -- the byte length of the stream's *name*, not its data. This is the same bug class already fixed for EndOfFile/ AllocationSize on an open stream handle (ksmbd_stream_eof()), just missed at this second site: a client enumerating streams sees a size derived from the name string length instead of the stream's actual content length, inconsistent with what querying the same stream by handle reports. Compute the real value length the same way ksmbd_stream_eof() does, via ksmbd_vfs_casexattr_len() on the already-known xattr key. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: add AAPL READDIR_ATTR V2 supportGael Blivet8-5/+97
Extends the existing V1 inline-FinderInfo mechanism (SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR) with the V2 variant: byte-identical layout otherwise, except the ShortNameLength+Reserved bytes (ignored outright by V1 clients) become a single flags field that V2 clients actually interpret. Negotiation: when a client's own client_caps requests V2 (SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR_V2), advertise V2 instead of V1 in the server's own server_caps reply -- they're mutually exclusive on the wire, not both set together. Wire format: the only currently-defined V2 flag, AAPL_READDIR_ATTR_V2_NO_XATTR, signals that an item has no xattrs/streams so the client can skip a separate query. Compute this per-entry in ksmbd_vfs_fill_dentry_attrs() by checking for any xattr under the XATTR_NAME_STREAM ("user.DosStream.") prefix -- a reliable, distinct marker for genuine ADS/stream xattrs, unlike DOSATTRIB or ACL xattrs which live under different prefixes, so this can't false-positive into telling Finder a file has no extra data when it actually does. Only computed when a V2 connection is active, to avoid the extra listxattr() call otherwise. V1's fixed ShortNameLength=24 convention (real macOS clients ignore the value outright per the same client source, so it's cosmetic parity with other real servers, not a functional requirement) is kept V1-only rather than reused as a V2 base value -- V2 clients do interpret this field, so it needs a clean 0-or-flag value, not a leftover V1 constant that happens not to collide with the one defined flag bit today. Confirmed via live diagnostics that macOS actually negotiates and uses V2 (client_caps bit 0x10 set) rather than falling back to V1 or ignoring the capability. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: implement full-file copy for AAPL ChunkCount=0 COPYCHUNKGael Blivet2-13/+93
fsctl_copychunk() treats FSCTL_SRV_COPYCHUNK with ChunkCount=0 as the standard SMB2 "query my copy limits, don't copy anything" request and returns success without ever looking up the file handles. That's correct for compliant SMB2 clients, but macOS Finder's Cmd+D duplicate sends ChunkCount=0 expecting the server to copy the whole file/stream -- so duplicated files are left at their just-created 0 bytes while the client reports success. Scope the full-copy fallback to AAPL-negotiated connections on a Time Machine share (conn->is_aapl && KSMBD_SHARE_FLAG_TIME_MACHINE) only, so standard non-AAPL SMB2 clients, and AAPL-negotiated clients on ordinary shares, keep the spec-correct query-limits behavior unchanged. both streams and regular files now share a single chunk_count == 0 fast path added right after src_file_size is computed, reusing the same buffered-copy helper and vfs_copy_file_range()/COPY_FILE_SPLICE fallback the existing per-chunk loop already uses, rather than the separate xattr-specific get/setxattr path this used before that rework. ChunksWritten/ChunkBytesWritten are 0 in the response: this is a synthesized whole-file copy, not a response to any chunk descriptor the client actually sent (it sent none), so there's no real chunk to report the count/size of. Only TotalBytesWritten is meaningful here. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: defer CHANGE_NOTIFY completion instead of STATUS_NOT_IMPLEMENTEDGael Blivet5-3/+280
smb2_notify() currently returns STATUS_NOT_IMPLEMENTED synchronously for every CHANGE_NOTIFY request. Genuine SMB2 servers never complete a CHANGE_NOTIFY spontaneously -- it's satisfied only by a real directory change or with STATUS_NOTIFY_CLEANUP when the watched handle is closed. macOS smbfs.kext depends on this deferred-completion contract: receiving STATUS_NOT_IMPLEMENTED instead makes it hard-freeze on unmount, since it never sees the cleanup it's waiting for. Add a notify_pendings list on struct ksmbd_file (protected by the existing f_lock) and a notify_entry list_head on struct ksmbd_work to link onto it. smb2_notify() now replies STATUS_PENDING immediately and queues a deferred STATUS_NOTIFY_CLEANUP response on the watched handle; __ksmbd_close_fd() drains and sends any pending notifications when the handle is actually closed. The drain splices the list out under fp->f_lock first, then processes the detached copy without the lock -- smb2_notify() on another connection can be adding to the same list at the same time a close happens on this one, and ksmbd_conn_write() can sleep (it takes the connection's write mutex), so it must not be called while the spinlock is held. Also handle the FileId=FFFF...FFFF share-root sentinel that macOS backupd sends to watch for changes without holding an open handle -- without an immediate STATUS_PENDING/STATUS_NOTIFY_CLEANUP reply here, backupd aborts Time Machine setup with STATUS_FILE_CLOSED. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: send inline FinderInfo in FIND responses when READDIR_ATTR negotiatedGael Blivet1-5/+53
Without READDIR_ATTR, macOS Finder resolves type/creator/icon for every file in a directory listing by opening its AFP_AfpInfo stream individually -- one extra CREATE+QUERY_INFO+CLOSE round trip per file, which is the dominant cost of browsing a large directory over SMB from a Mac. When the client negotiates READDIR_ATTR (conn->aapl_readdir_attr, set during CREATE's AAPL context exchange), inline the same information directly into each FILEID_BOTH_DIRECTORY_INFORMATION FIND entry: EaSize = max_access, expanded specific rights (GENERIC_ALL_FLAGS), not the raw FILE_GENERIC_ALL_LE "generic" meta-bit -- that bit has none of the specific FILE_* rights macOS's smbfs.kext checks bit-by-bit, so reporting it directly would fail every access check and show Finder's "no entry" badge on every file/folder. ShortNameLength = 24 (fixed; the spec says 0 when there's no short name; kept for wire parity with reference server, see below) ShortName[0..7] = resource fork size (0 -- no resource forks) ShortName[8..23] = compressed FinderInfo (all zero: type/creator unset, client falls back to extension-based icon/type detection, consistent with the AFP_AfpInfo synthesis this mirrors) Reserved2 = Unix mode bits Reparse-point status is still carried via ExtFileAttributes rather than EaSize once READDIR_ATTR is active, since EaSize is repurposed for max_access. Reverse-engineered from macOS smbfs.kext network behavior and cross-checked against reference implementation marshalling (reference implementation behavior). Also confirmed against AAPL's published public client behavior (public client behavior reference) -- every field here matches exactly, except ShortNameLength=24: real V1 clients read but never examine that field, so it's kept for wire parity with reference server, not because macOS requires it. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: synthesize empty AFP_AfpInfo xattr on first probeGael Blivet1-0/+24
Once a server advertises the AAPL COPYFILE capability, macOS requires an AFP_AfpInfo stream on every file it looks at for Finder type/ creator/icon resolution. smb2_set_stream_name_xattr() currently returns -EBADF (STATUS_OBJECT_NAME_NOT_FOUND) when a client opens AFP_AfpInfo with FILE_OPEN disposition and the xattr doesn't exist yet, which macOS treats as fatal for that file: Finder falls back to showing a generic icon, and file operations that depend on succeeding against this stream (e.g. Cmd+D duplication) fail. Synthesize a 60-byte zeroed AFP_AfpInfo xattr (magic 0x00051607, version 0x00020000, both big-endian per the AFP_AfpInfo wire format) on first FILE_OPEN probe instead. type=0/creator=0 tells macOS to fall back to extension-based type detection, which is correct for files with no explicit Finder metadata. The synthesized xattr persists on disk, so this only pays the extra write once per file; a later genuine write from macOS (e.g. after the user assigns a custom icon) overwrites it normally. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: add AAPL kAAPL_SERVER_QUERY create context supportGael Blivet10-2/+212
macOS clients (Finder, and specifically Time Machine's backupd) send an "AAPL" SMB2 create context on CREATE to negotiate AAPL-specific server capabilities (server_caps/vol_caps/model string). Without a response to this context, macOS Time Machine over SMB does not work at all. Add the AAPL create context structs (create_aapl_rsp, aapl_server_query_req) and create_aapl_rsp_buf(), which builds the kAAPL_SERVER_QUERY response mirroring the layout observed from macOS's own smbd, including the model string workaround: omitting the model string when the client requested it causes smbfs.kext to enter a broken disconnect path requiring a full macOS reboot to recover from. Command codes and bitmap values reuse the existing SMB2_CRTCTX_AAPL_* constants in fs/smb/common/smb2pdu.h. Wire format confirmed against AAPL's published public client kernel source (public client behavior reference) -- every field here and every SMB2_CRTCTX_AAPL_* constant matches exactly. Hook the request parsing and response into smb2_open()'s existing create-context handling, following the same DataOffset+DataLength bounds-checking convention already used by every other context parser in this file. The AAPL model string is configurable via the existing netlink startup path (server_conf.aapl_model, default "Xserve"). This is scoped to shares with the new KSMBD_SHARE_FLAG_TIME_MACHINE flag only, not enabled globally -- AAPL's AAPL extension is undocumented, so containing its blast radius to shares that explicitly opt in limits risk to ordinary SMB shares. conn->aapl_readdir_attr is set here when the client also advertises READDIR_ATTR support, but the actual inline-FinderInfo wire format (the feature that flag gates) is not implemented yet -- follow-up commit. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17smb: server: fix leak of ksmbd_ipc_login_request_ext() returned bufferEnzo Matsumiya2-0/+2
Free it unconditionally after ksmbd_alloc_user() calls. kmemleak splat: unreferenced object 0xffff888103b83540 (size 192): comm "pool-0", pid 16970, jiffies 4377290937 hex dump (first 32 bytes): 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace (crc 408ccc66): __kvmalloc_node_noprof+0x730/0x920 handle_generic_event+0xec/0x1a0 [ksmbd] genl_family_rcv_msg_doit+0xe0/0x130 genl_rcv_msg+0x181/0x290 netlink_rcv_skb+0x4f/0x100 genl_rcv+0x28/0x40 netlink_unicast+0x1e6/0x2c0 netlink_sendmsg+0x20a/0x450 ____sys_sendmsg+0x2e8/0x310 ___sys_sendmsg+0x78/0xc0 __sys_sendmsg+0x63/0xc0 do_syscall_64+0xa1/0x670 entry_SYSCALL_64_after_hwframe+0x76/0x7e Fixes: a77e0e02af1c ("ksmbd: add support for supplementary groups") Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: skip fallocate for SMB2_CREATE_ALLOCATION_SIZE on a stream handleGael Blivet1-7/+16
smb2_open() calls vfs_fallocate(fp->filp, ...) unconditionally when a client's CREATE request includes an AllocationSize create context. For a stream handle, fp->filp refers to the base file's data fork (streams are xattr-backed on the same underlying file, not separate files), so this pre-allocates storage on the base file's actual data instead of doing anything meaningful for the stream -- fallocate has no applicability to an xattr-backed stream at all. Skip the fallocate call for stream handles. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: don't check directory emptiness when deleting a streamGael Blivet1-1/+1
set_file_disposition_info() checks S_ISDIR(inode->i_mode) && ksmbd_vfs_empty_dir(fp) == -ENOTEMPTY to refuse deleting a non-empty directory. A stream handle's fp->filp refers to the same underlying inode as its base file or directory (streams are xattr-backed on that same inode), so this check also fires when the target is actually a stream attached to a directory, not the directory itself -- deleting the stream then incorrectly fails with -EBUSY whenever the directory happens to be non-empty, even though removing an xattr has nothing to do with the directory's contents. Skip the directory-emptiness check for stream handles, matching how ksmbd_stream_fd() is already used elsewhere in this function. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: zero-initialize xattr_dos_attrib in smb2_update_xattrs()Gael Blivet1-1/+1
ndr_decode_dos_attr() only populates da->itime for version-4 DOS attribute xattrs; for version 3 it's skipped entirely (only da->create_time is set). smb2_update_xattrs() declared da without initializing it, so fp->itime = da.itime unconditionally copies whatever was on the kernel stack for any file carrying a version-3 xattr (e.g. written by an older client or server) -- uninitialized stack memory that can later be exposed to a client via QUERY_INFO. Zero-initialize da at declaration, matching the pattern fsctl_set_sparse() already uses in this same file. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: validate out_buf_len before FSCTL_CREATE_OR_GET_OBJECT_ID and ↵Gael Blivet1-0/+10
FSCTL_GET_REPARSE_POINT writes Both cases write a fixed-size response structure into rsp->Buffer without first checking that out_buf_len (the space smb2_ioctl() actually has available, computed by smb2_calc_max_out_buf_len() from the client's OutputBufferLength minus space already consumed earlier in a compound request) is large enough. Every comparable case in this same switch (FSCTL_SRV_ENUMERATE_SNAPSHOTS, FSCTL_GET_COMPRESSION, FSCTL_VALIDATE_NEGOTIATE_INFO, FSCTL_SRV_REQUEST_RESUME_KEY, FSCTL_SRV_COPYCHUNK) validates this first; these two don't. A client can send a compound SMB2 request where an earlier command in the same compound chain consumes most of work->response_buf, leaving smb2_calc_max_out_buf_len() only a few bytes of out_buf_len for a trailing FSCTL_CREATE_OR_GET_OBJECT_ID or FSCTL_GET_REPARSE_POINT. Both then unconditionally write their full fixed-size structure (64 bytes and 8 bytes respectively) at rsp->Buffer[0] regardless, overflowing past the actual remaining space in the response buffer. Add the same out_buf_len check used by every other fixed-size-response case in this function, before the write. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: fix durable handle v2 default timeout units (60 -> 60000)Gael Blivet1-1/+8
When a client's Durable Handle Request V2 sets Timeout=0 ("let the server choose"), fp->durable_timeout was set to 60. Every other use of this field is in milliseconds: DURABLE_HANDLE_MAX_TIMEOUT (300000) in smb2pdu.h, the nonzero branch immediately above (min_t(unsigned int, dh_info.timeout, DURABLE_HANDLE_MAX_TIMEOUT), where dh_info.timeout is the wire value and already milliseconds per spec), and the scavenger in vfs_cache.c, which adds it directly to jiffies_to_msecs(jiffies). 60 is off by 1000x: the handle becomes scavenger-eligible 60 milliseconds after close instead of 60 seconds. A client requesting Timeout=0 is relying entirely on the server's default to cover the gap between a dropped connection and its reconnect -- 60ms is not enough time for even a fast network blip to be detected and reconnected, so any real disruption loses the race and a subsequent DH2C reconnect fails with a durable-handle lookup miss instead of succeeding. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: route stream FileDispositionInformation through stream delete flagGael Blivet2-10/+48
ksmbd_fd_set_delete_pending()/ksmbd_fd_clear_delete_pending() to keep a stream's FileDispositionInformation from marking the whole file for deletion, but used the inode-wide S_DEL_ON_CLS_STREAM flag to do it -- the exact same problem class the commit was fixing, one level up. S_DEL_ON_CLS_STREAM lives on the shared ksmbd_inode, not on any specific stream handle. If a file has multiple stream handles open and one gets marked delete-pending via FileDispositionInformation, the flag can't record *which* stream should be deleted: whichever stream handle happens to close first (not necessarily the one that was actually marked) sees S_DEL_ON_CLS_STREAM set and has its xattr removed. Two clients (or two handles from the same client) touching different streams on the same file can end up deleting the wrong one. ksmbd_inode_pending_delete() has the same issue: it only checks S_DEL_PENDING, which is never set for a stream handle, so a client querying FileStandardInformation.DeletePending on a stream marked via this path would incorrectly see 0. Track this per-handle instead (stream_del_pending on struct ksmbd_file), matching the file itself rather than the shared inode. ksmbd_fd_set_delete_on_close() (the CREATE-time FILE_DELETE_ON_CLOSE option, a separate call path from FileDispositionInformation) still uses the inode-wide flag; __ksmbd_inode_close() now checks both, since either one should trigger removing the stream's xattr on close. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: handle empty QUERY_ALLOCATED_RANGES outputNamjae Jeon1-4/+12
FSCTL_QUERY_ALLOCATED_RANGES can be issued with a valid input buffer but without room for an output range. Do not reject the request before looking at the file layout. If the query would produce a range, return STATUS_BUFFER_TOO_SMALL. If it produces no ranges, return success with an empty output. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: allow FSCTL_SET_SPARSE without input bufferNamjae Jeon1-2/+8
FSCTL_SET_SPARSE without an input buffer sets a file sparse. Treat a zero-length input buffer as SetSparse=true and keep rejecting truncated non-empty buffers. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: reject FSCTL_SET_SPARSE on directoriesNamjae Jeon1-0/+5
FSCTL_SET_SPARSE applies to files. Return STATUS_INVALID_PARAMETER when a client sends it for a directory handle instead of setting the sparse file attribute on the directory. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: persist FSCTL_SET_SPARSE stateNamjae Jeon1-22/+18
Advertise FILE_SUPPORTS_SPARSE_FILES so clients can use FSCTL_SET_SPARSE. Do not mark regular files sparse just because sparse support is advertised; FILE_ATTRIBUTE_SPARSE_FILE should reflect the state set by FSCTL_SET_SPARSE. Persist the sparse attribute in the DOS attribute xattr regardless of the store dos attributes setting. Restore the sparse and compressed bits from that xattr when only those emulated attributes need to be preserved. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: preserve compression state across opensNamjae Jeon2-16/+12
The compression state can be emulated with the DOS attribute xattr when the backing filesystem cannot store it directly. Do not limit that state to shares with store dos attributes enabled, otherwise a file reopened through another handle can lose FILE_ATTRIBUTE_COMPRESSED in file information responses. Load only the compressed bit from the DOS attribute xattr when store dos attributes is disabled. Keep the normal DOS attribute behavior unchanged when it is enabled. Also avoid clearing an already restored compressed bit just because the backing filesystem does not report FS_COMPR_FL. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: preserve compression state in set basic infoNamjae Jeon1-2/+5
FILE_ATTRIBUTE_COMPRESSED is controlled by FSCTL_SET_COMPRESSION and should not be set directly through FileBasicInformation. Keep the existing compression state when updating basic attributes and ignore the compressed bit supplied by the client in the basic information request. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: support file compression attributesNamjae Jeon3-15/+91
Advertise file compression support and keep the compression state in the per-file DOS attributes when the backing filesystem cannot apply the compression flag directly. FSCTL_SET_COMPRESSION should still update the state returned by FSCTL_GET_COMPRESSION and file compression information in that case. When a new object is created under a compressed directory, inherit the compression attribute from the parent. If FILE_NO_COMPRESSION is specified, clear the compression state after creation and let it override inheritance for both files and directories. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17smb/server: use MSG_EOR for async interim responseChenXiaoSong4-3/+14
Two kernel_sendmsg() calls can still use the same TCP skb if the first skb can take more data. This can happen when ksmbd sends two SMB2 responses very close to each other. Without MSG_EOR, TCP can append the next sendmsg data to the previous skb. Then STATUS_PENDING and the later response can be put into the same TCP skb. MSG_EOR marks the skb as end of record, so TCP will not collapse the next sendmsg data into it. Example: smbtorture //${server_ip}/export -U${username}%${password} smb2.compound_async.write_write Client request: Write Request Len:64 Off:0, File: compound_async_write_write; Write Request Len:64 Off:64 Before this patch, server responses: Write Response, File: compound_async_write_write Write Response SMB2, STATUS_PENDING, Write Response, MessageId 7 SMB2, Write Response, MessageId 7 After this patch: Write Response, File: compound_async_write_write Write Response, Error: STATUS_PENDING Write Response Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17smb/server: introduce struct ksmbd_transport_writeChenXiaoSong4-19/+38
Put the arguments of ksmbd_transport_ops ->writev() into a struct. This makes the function call shorter and easier to read. Add __ksmbd_conn_write() for the common write code. A later patch will use it for another write helper. No functional change. Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17smb/server: send compound prefix before async pending responseChenXiaoSong1-0/+45
When the last request in a compound request becomes async, ksmbd sends a STATUS_PENDING response for it. But the responses for previous requests in the same compound request are still kept in the same response buffer. Send these previous responses first. Clear NextCommand for the last response in this part, sign it again if needed, and reset the iov state. After that, the async request sends STATUS_PENDING first, and sends the real response later. Both are separate responses. Example: smbtorture //${server_ip}/export -U${username}%${password} smb2.compound_async.write_write Client request: Write Request Len:64 Off:0, File: compound_async_write_write; Write Request Len:64 Off:64 Before this patch, STATUS_PENDING Write Response is the first of several responses: Write Response, Error: STATUS_PENDING Write Response, File: compound_async_write_write; Write Response But STATUS_PENDING Write Response should be in the middle of several responses, after this patch: Write Response, File: compound_async_write_write Write Response SMB2, STATUS_PENDING, Write Response, MessageId 7 SMB2, Write Response, MessageId 7 Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: distinguish unknown RPC pipe namesNamjae Jeon2-10/+7
Unknown RPC pipe names and malformed CREATE parameters both use -EINVAL. Mapping that errno to STATUS_OBJECT_NAME_NOT_FOUND therefore also hides invalid request parameters as a missing pipe. Return -ENOENT when RPC method lookup cannot find a supported pipe and map only that error to STATUS_OBJECT_NAME_NOT_FOUND. Preserve STATUS_INVALID_PARAMETER for -EINVAL returned by request validation. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: clear stale sparse attribute on non-sparse sharesGael Blivet1-0/+10
smb2_update_xattrs() copies the DOS SPARSE attribute bit verbatim from the stored xattr into the in-memory file attributes, without checking whether the share is currently advertising FILE_SUPPORTS_SPARSE_FILES. A file whose xattr has a stale SPARSE bit (set by a previous client, or from before the share was reconfigured) would keep reporting as sparse even after sparse-file support is turned off for the share. This matters for Time Machine: sparsebundle band files rely on accurate sparse-file status being reported, since macOS decides whether to issue FSCTL_SET_SPARSE based on it. Mask the bit out when the share doesn't currently advertise sparse-file support. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: quiet mdssvc RPC log spamGael Blivet1-0/+3
macOS routinely probes the mdssvc RPC pipe to check for Spotlight search support. __rpc_method() already falls through to returning 0 (unsupported) for it via the default case, but that path also logs "Unsupported RPC: mdssvc" via pr_err on every single probe -- which happens often enough during normal macOS browsing/backup activity to spam the kernel log. Add an explicit case that returns the same value without the log line; behavior is unchanged, this only removes noise for an expected, routine client behavior. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: return STATUS_OBJECT_NAME_NOT_FOUND for unknown IPC pipe namesGael Blivet1-1/+7
create_smb2_pipe() maps ksmbd_session_rpc_open() failing with -EINVAL (pipe name not recognized/supported) to STATUS_INVALID_PARAMETER. macOS Time Machine's backupd treats STATUS_INVALID_PARAMETER on a pipe open as a fatal error and aborts the backup immediately, whereas STATUS_OBJECT_NAME_NOT_FOUND is handled gracefully -- the client just treats that particular pipe as unavailable and continues. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: report actual xattr value length for stream EndOfFile/AllocationSizeGael Blivet1-12/+43
fp->stream.size holds the byte length of the mangled xattr *name* string (it's used as the attr_name_len argument when looking up the xattr), not the size of the stream's actual data. CREATE and every QUERY_INFO handler that reports EndOfFile/AllocationSize for a stream handle used fp->stream.size directly, so clients received a bogus size derived from the internal xattr key name length instead of the stream's real content length. Add ksmbd_stream_eof() to query the xattr's actual value length via ksmbd_vfs_casexattr_len(), and use it at every site that reports a stream handle's size: the CREATE response, get_file_standard_info(), get_file_all_info(), get_file_network_open_info(), and find_file_posix_info(). Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: route stream FileDispositionInformation through stream delete flagGael Blivet3-2/+36
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. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: fix off-by-one rejecting minimal COPYCHUNK query-limits requestGael Blivet1-1/+1
The FSCTL_COPYCHUNK/FSCTL_COPYCHUNK_WRITE input length check uses in_buf_len <= sizeof(struct copychunk_ioctl_req), which rejects a buffer that is exactly sizeof(struct copychunk_ioctl_req) bytes -- the minimal, valid request containing only the fixed header with ChunkCount=0 and no chunk entries, used by clients to query the server's copy limits before issuing a real copychunk. Since copychunk_ioctl_req ends in a flexible array member, the correct minimum is that the buffer covers the fixed header, so use offsetof(..., Chunks) with '<' instead of '<=' against sizeof(): same value, but the boundary case is now correctly accepted. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Gael Blivet <gael.blivet@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: handle AAPL stream copy length mismatchNamjae Jeon1-7/+37
macOS can reuse the main file's chunk list when issuing a copychunk request for alternate data streams. The requested source range can therefore exceed the length of the xattr-backed stream and currently fails with STATUS_INVALID_VIEW_SIZE. For AAPL connections copying between two streams, limit the actual copy to the available source data while reporting the requested chunk length as written. Keep the source range validation unchanged for non-AAPL connections and requests involving a regular file. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: support copychunk for alternate data streamsNamjae Jeon1-30/+50
Copychunk rejects requests when either handle refers to an alternate data stream. These streams are stored in extended attributes and cannot be passed directly to vfs_copy_file_range(). Use the bounded buffered copy path when a source or destination is a stream. Obtain the source length from the stream extended attribute and perform I/O through the existing stream-aware read and write helpers. Keep vfs_copy_file_range() and its fallback for regular files only. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: preserve access denied status for copychunkNamjae Jeon1-1/+1
The copychunk error mapping handles -EACCES in an independent if statement. The following error chain therefore reaches its final else clause and overwrites STATUS_ACCESS_DENIED with STATUS_UNEXPECTED_IO_ERROR. Join the -EACCES check to the remaining error chain so an access failure is returned as STATUS_ACCESS_DENIED. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: preserve data during overlapping copy chunkNamjae Jeon1-10/+66
Copying an overlapping range within the same file through do_splice_direct() can overwrite source data that has not yet been read. This corrupts the destination when the target range starts inside and after the source range. Handle overlapping ranges with a bounded temporary buffer. Copy from the end when the destination follows the source and from the beginning otherwise, providing memmove semantics without allocating the entire copy length. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: return complete resume key responseNamjae Jeon1-1/+1
The FSCTL_SRV_REQUEST_RESUME_KEY response contains a mandatory four-byte context field after ContextLength. Defining the context as a flexible array excludes it from sizeof(struct resume_key_ioctl_rsp), so ksmbd sends only 28 bytes instead of the required 32 bytes. The truncated response cannot be decoded and results in an NDR buffer size error. Define the reserved context as a fixed four-byte field. This makes the response size match the wire format and ensures the field is zeroed and included in OutputCount. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
2026-08-17ksmbd: support empty snapshot enumerationNamjae Jeon3-0/+32
FSCTL_SRV_ENUM_SNAPS is currently unimplemented, causing clients to treat shadow-copy enumeration as unsupported even when the share simply has no snapshots. Handle the count-only SRV_SNAPSHOT_ARRAY request and return a valid empty snapshot list after validating the file handle and minimum output buffer size. Report a two-byte empty UTF-16 MULTI_SZ array and zero snapshot counts. This allows smb2.ioctl.shadow_copy to run without a snapshot backend. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>